mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 23:25:41 +00:00
dep: Add rapidyaml
This commit is contained in:
parent
f7bed69e7c
commit
5c08fa9d00
|
@ -29,6 +29,8 @@ add_subdirectory(reshadefx EXCLUDE_FROM_ALL)
|
||||||
disable_compiler_warnings_for_target(reshadefx)
|
disable_compiler_warnings_for_target(reshadefx)
|
||||||
add_subdirectory(rcheevos EXCLUDE_FROM_ALL)
|
add_subdirectory(rcheevos EXCLUDE_FROM_ALL)
|
||||||
disable_compiler_warnings_for_target(rcheevos)
|
disable_compiler_warnings_for_target(rcheevos)
|
||||||
|
add_subdirectory(rapidyaml EXCLUDE_FROM_ALL)
|
||||||
|
disable_compiler_warnings_for_target(rapidyaml)
|
||||||
|
|
||||||
# Build dependencies on Windows/Android.
|
# Build dependencies on Windows/Android.
|
||||||
if(WIN32 OR ANDROID)
|
if(WIN32 OR ANDROID)
|
||||||
|
|
75
dep/rapidyaml/CMakeLists.txt
Normal file
75
dep/rapidyaml/CMakeLists.txt
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
add_library(rapidyaml
|
||||||
|
include/c4/base64.hpp
|
||||||
|
include/c4/blob.hpp
|
||||||
|
include/c4/charconv.hpp
|
||||||
|
include/c4/compiler.hpp
|
||||||
|
include/c4/config.hpp
|
||||||
|
include/c4/cpu.hpp
|
||||||
|
include/c4/dump.hpp
|
||||||
|
include/c4/error.hpp
|
||||||
|
include/c4/export.hpp
|
||||||
|
include/c4/format.hpp
|
||||||
|
include/c4/language.hpp
|
||||||
|
include/c4/memory_util.hpp
|
||||||
|
include/c4/platform.hpp
|
||||||
|
include/c4/preprocessor.hpp
|
||||||
|
include/c4/std/std.hpp
|
||||||
|
include/c4/std/std_fwd.hpp
|
||||||
|
include/c4/std/string.hpp
|
||||||
|
include/c4/std/string_fwd.hpp
|
||||||
|
include/c4/std/string_view.hpp
|
||||||
|
include/c4/std/tuple.hpp
|
||||||
|
include/c4/std/vector.hpp
|
||||||
|
include/c4/std/vector_fwd.hpp
|
||||||
|
include/c4/substr.hpp
|
||||||
|
include/c4/substr_fwd.hpp
|
||||||
|
include/c4/szconv.hpp
|
||||||
|
include/c4/types.hpp
|
||||||
|
include/c4/utf.hpp
|
||||||
|
include/c4/windows.hpp
|
||||||
|
include/c4/windows_pop.hpp
|
||||||
|
include/c4/windows_push.hpp
|
||||||
|
include/c4/yml/common.hpp
|
||||||
|
include/c4/yml/detail/parser_dbg.hpp
|
||||||
|
include/c4/yml/detail/stack.hpp
|
||||||
|
include/c4/yml/emit.def.hpp
|
||||||
|
include/c4/yml/emit.hpp
|
||||||
|
include/c4/yml/export.hpp
|
||||||
|
include/c4/yml/node.hpp
|
||||||
|
include/c4/yml/parse.hpp
|
||||||
|
include/c4/yml/preprocess.hpp
|
||||||
|
include/c4/yml/std/map.hpp
|
||||||
|
include/c4/yml/std/std.hpp
|
||||||
|
include/c4/yml/std/string.hpp
|
||||||
|
include/c4/yml/std/vector.hpp
|
||||||
|
include/c4/yml/tree.hpp
|
||||||
|
include/c4/yml/writer.hpp
|
||||||
|
include/c4/yml/yml.hpp
|
||||||
|
include/ryml.hpp
|
||||||
|
include/ryml_std.hpp
|
||||||
|
src/c4/base64.cpp
|
||||||
|
src/c4/error.cpp
|
||||||
|
src/c4/format.cpp
|
||||||
|
src/c4/language.cpp
|
||||||
|
src/c4/memory_util.cpp
|
||||||
|
src/c4/utf.cpp
|
||||||
|
src/c4/yml/common.cpp
|
||||||
|
src/c4/yml/node.cpp
|
||||||
|
src/c4/yml/parse.cpp
|
||||||
|
src/c4/yml/preprocess.cpp
|
||||||
|
src/c4/yml/tree.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(rapidyaml PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/../fast_float/include"
|
||||||
|
)
|
||||||
|
target_include_directories(rapidyaml INTERFACE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(rapidyaml PUBLIC
|
||||||
|
"C4_NO_DEBUG_BREAK"
|
||||||
|
)
|
||||||
|
|
20
dep/rapidyaml/LICENSE.txt
Normal file
20
dep/rapidyaml/LICENSE.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (c) 2018, Joao Paulo Magalhaes <dev@jpmag.me>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
124
dep/rapidyaml/include/c4/base64.hpp
Normal file
124
dep/rapidyaml/include/c4/base64.hpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#ifndef _C4_BASE64_HPP_
|
||||||
|
#define _C4_BASE64_HPP_
|
||||||
|
|
||||||
|
/** @file base64.hpp encoding/decoding for base64.
|
||||||
|
* @see https://en.wikipedia.org/wiki/Base64
|
||||||
|
* @see https://www.base64encode.org/
|
||||||
|
* */
|
||||||
|
|
||||||
|
#include "c4/charconv.hpp"
|
||||||
|
#include "c4/blob.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
|
||||||
|
/** check that the given buffer is a valid base64 encoding
|
||||||
|
* @see https://en.wikipedia.org/wiki/Base64 */
|
||||||
|
C4CORE_EXPORT bool base64_valid(csubstr encoded);
|
||||||
|
|
||||||
|
|
||||||
|
/** base64-encode binary data.
|
||||||
|
* @param encoded [out] output buffer for encoded data
|
||||||
|
* @param data [in] the input buffer with the binary data
|
||||||
|
*
|
||||||
|
* @return the number of bytes needed to return the output (ie the
|
||||||
|
* required size for @p encoded). No writes occur beyond the end of
|
||||||
|
* the output buffer, so it is safe to do a speculative call where the
|
||||||
|
* encoded buffer is empty, or maybe too small. The caller should
|
||||||
|
* ensure that the returned size is smaller than the size of the
|
||||||
|
* encoded buffer.
|
||||||
|
*
|
||||||
|
* @note the result depends on endianness. If transfer between
|
||||||
|
* little/big endian systems is desired, the caller should normalize
|
||||||
|
* @p data before encoding.
|
||||||
|
*
|
||||||
|
* @see https://en.wikipedia.org/wiki/Base64 */
|
||||||
|
C4CORE_EXPORT size_t base64_encode(substr encoded, cblob data);
|
||||||
|
|
||||||
|
|
||||||
|
/** decode the base64 encoding in the given buffer
|
||||||
|
* @param encoded [in] the encoded base64
|
||||||
|
* @param data [out] the output buffer
|
||||||
|
*
|
||||||
|
* @return the number of bytes needed to return the output (ie the
|
||||||
|
* required size for @p data). No writes occur beyond the end of the
|
||||||
|
* output buffer, so it is safe to do a speculative call where the
|
||||||
|
* data buffer is empty, or maybe too small. The caller should ensure
|
||||||
|
* that the returned size is smaller than the size of the data buffer.
|
||||||
|
*
|
||||||
|
* @note the result depends on endianness. If transfer between
|
||||||
|
* little/big endian systems is desired, the caller should normalize
|
||||||
|
* @p data after decoding.
|
||||||
|
*
|
||||||
|
* @see https://en.wikipedia.org/wiki/Base64 */
|
||||||
|
C4CORE_EXPORT size_t base64_decode(csubstr encoded, blob data);
|
||||||
|
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
template<typename CharOrConstChar>
|
||||||
|
struct base64_wrapper_
|
||||||
|
{
|
||||||
|
blob_<CharOrConstChar> data;
|
||||||
|
base64_wrapper_() : data() {}
|
||||||
|
base64_wrapper_(blob_<CharOrConstChar> blob) : data(blob) {}
|
||||||
|
};
|
||||||
|
/** a tag type to mark a payload as base64-encoded */
|
||||||
|
using const_base64_wrapper = base64_wrapper_<cbyte>;
|
||||||
|
/** a tag type to mark a payload to be encoded as base64 */
|
||||||
|
using base64_wrapper = base64_wrapper_<byte>;
|
||||||
|
|
||||||
|
|
||||||
|
/** mark a variable to be written in base64 format */
|
||||||
|
template<class ...Args>
|
||||||
|
C4_ALWAYS_INLINE const_base64_wrapper cbase64(Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
return const_base64_wrapper(cblob(args...));
|
||||||
|
}
|
||||||
|
/** mark a csubstr to be written in base64 format */
|
||||||
|
C4_ALWAYS_INLINE const_base64_wrapper cbase64(csubstr s)
|
||||||
|
{
|
||||||
|
return const_base64_wrapper(cblob(s.str, s.len));
|
||||||
|
}
|
||||||
|
/** mark a variable to be written in base64 format */
|
||||||
|
template<class ...Args>
|
||||||
|
C4_ALWAYS_INLINE const_base64_wrapper base64(Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
return const_base64_wrapper(cblob(args...));
|
||||||
|
}
|
||||||
|
/** mark a csubstr to be written in base64 format */
|
||||||
|
C4_ALWAYS_INLINE const_base64_wrapper base64(csubstr s)
|
||||||
|
{
|
||||||
|
return const_base64_wrapper(cblob(s.str, s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** mark a variable to be read in base64 format */
|
||||||
|
template<class ...Args>
|
||||||
|
C4_ALWAYS_INLINE base64_wrapper base64(Args &... args)
|
||||||
|
{
|
||||||
|
return base64_wrapper(blob(args...));
|
||||||
|
}
|
||||||
|
/** mark a variable to be read in base64 format */
|
||||||
|
C4_ALWAYS_INLINE base64_wrapper base64(substr s)
|
||||||
|
{
|
||||||
|
return base64_wrapper(blob(s.str, s.len));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
|
||||||
|
/** write a variable in base64 format */
|
||||||
|
inline size_t to_chars(substr buf, fmt::const_base64_wrapper b)
|
||||||
|
{
|
||||||
|
return base64_encode(buf, b.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** read a variable in base64 format */
|
||||||
|
inline size_t from_chars(csubstr buf, fmt::base64_wrapper *b)
|
||||||
|
{
|
||||||
|
return base64_decode(buf, b->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_BASE64_HPP_ */
|
67
dep/rapidyaml/include/c4/blob.hpp
Normal file
67
dep/rapidyaml/include/c4/blob.hpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef _C4_BLOB_HPP_
|
||||||
|
#define _C4_BLOB_HPP_
|
||||||
|
|
||||||
|
#include "c4/types.hpp"
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
|
||||||
|
/** @file blob.hpp Mutable and immutable binary data blobs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct blob_;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<class T> struct is_blob_type : std::integral_constant<bool, false> {};
|
||||||
|
template<class T> struct is_blob_type<blob_<T>> : std::integral_constant<bool, true> {};
|
||||||
|
template<class T> struct is_blob_value_type : std::integral_constant<bool, (std::is_fundamental<T>::value || std::is_trivially_copyable<T>::value)> {};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct blob_
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<T, byte>::value || std::is_same<T, cbyte>::value, "must be either byte or cbyte");
|
||||||
|
static_assert(sizeof(T) == 1u, "must be either byte or cbyte");
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
T * buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE blob_() noexcept = default;
|
||||||
|
C4_ALWAYS_INLINE blob_(blob_ const& that) noexcept = default;
|
||||||
|
C4_ALWAYS_INLINE blob_(blob_ && that) noexcept = default;
|
||||||
|
C4_ALWAYS_INLINE blob_& operator=(blob_ && that) noexcept = default;
|
||||||
|
C4_ALWAYS_INLINE blob_& operator=(blob_ const& that) noexcept = default;
|
||||||
|
|
||||||
|
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> const& that) noexcept : buf(that.buf), len(that.len) {}
|
||||||
|
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_(blob_<U> && that) noexcept : buf(that.buf), len(that.len) {}
|
||||||
|
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> && that) noexcept { buf = that.buf; len = that.len; }
|
||||||
|
template<class U, class=typename std::enable_if<std::is_const<T>::value && std::is_same<typename std::add_const<U>::type, T>::value, U>::type> C4_ALWAYS_INLINE blob_& operator=(blob_<U> const& that) noexcept { buf = that.buf; len = that.len; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE blob_(void *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {}
|
||||||
|
C4_ALWAYS_INLINE blob_(void const *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(n) {}
|
||||||
|
|
||||||
|
#define _C4_REQUIRE_BLOBTYPE(ty) class=typename std::enable_if<((!detail::is_blob_type<ty>::value) && (detail::is_blob_value_type<ty>::value)), T>::type
|
||||||
|
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U &var) noexcept : buf(reinterpret_cast<T*>(&var)), len(sizeof(U)) {}
|
||||||
|
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U *ptr, size_t n) noexcept : buf(reinterpret_cast<T*>(ptr)), len(sizeof(U) * n) { C4_ASSERT(is_aligned(ptr)); }
|
||||||
|
template<class U, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U &var) noexcept { buf = reinterpret_cast<T*>(&var); len = sizeof(U); return *this; }
|
||||||
|
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_(U (&arr)[N]) noexcept : buf(reinterpret_cast<T*>(arr)), len(sizeof(U) * N) {}
|
||||||
|
template<class U, size_t N, _C4_REQUIRE_BLOBTYPE(U)> C4_ALWAYS_INLINE blob_& operator= (U (&arr)[N]) noexcept { buf = reinterpret_cast<T*>(arr); len = sizeof(U) * N; return *this; }
|
||||||
|
#undef _C4_REQUIRE_BLOBTYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
/** an immutable binary blob */
|
||||||
|
using cblob = blob_<cbyte>;
|
||||||
|
/** a mutable binary blob */
|
||||||
|
using blob = blob_< byte>;
|
||||||
|
|
||||||
|
C4_MUST_BE_TRIVIAL_COPY(blob);
|
||||||
|
C4_MUST_BE_TRIVIAL_COPY(cblob);
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_BLOB_HPP_
|
168
dep/rapidyaml/include/c4/c4core.natvis
Normal file
168
dep/rapidyaml/include/c4/c4core.natvis
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Very good intro:
|
||||||
|
@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
|
||||||
|
See also:
|
||||||
|
@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
|
||||||
|
@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
|
||||||
|
@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
|
||||||
|
-->
|
||||||
|
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
|
<Type Name="c4::basic_substring<*>">
|
||||||
|
<DisplayString>{str,[len]} (sz={len})</DisplayString>
|
||||||
|
<StringView>str,[len]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">len</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>len</Size>
|
||||||
|
<ValuePointer>str</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::span<*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::spanrs<*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<Item Name="[capacity]">m_capacity</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<!-- display span<char>/span<const char> as a string too -->
|
||||||
|
<Type Name="c4::span<char,*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
|
||||||
|
<StringView>m_ptr,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::span<const char,*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size})</DisplayString>
|
||||||
|
<StringView>m_ptr,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<!-- display spanrs<char>/spanrs<const char> as a string too -->
|
||||||
|
<Type Name="c4::spanrs<char,*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
|
||||||
|
<StringView>m_ptr,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<Item Name="[capacity]">m_capacity</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::spanrs<const char,*>">
|
||||||
|
<DisplayString>{m_ptr,[m_size]} (sz={m_size}, cap={m_capacity})</DisplayString>
|
||||||
|
<StringView>m_ptr,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<Item Name="[capacity]">m_capacity</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_ptr</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<!-- =========================================================================================== -->
|
||||||
|
<Type Name="c4::string_impl<*,*,*,*>">
|
||||||
|
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]} (sz={(($T3*)this)->m_size})</DisplayString>
|
||||||
|
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="m_str">
|
||||||
|
<DisplayString>{(($T3*)this)->m_str,[(($T3*)this)->m_size]}</DisplayString>
|
||||||
|
<StringView>(($T3*)this)->m_str,[(($T3*)this)->m_size]</StringView>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="m_size">
|
||||||
|
<DisplayString>{(($T3*)this)->m_size}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::basic_substring<*,*>">
|
||||||
|
<DisplayString>{m_str,[m_size]} (sz={m_size})</DisplayString>
|
||||||
|
<StringView>m_str,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[size]">
|
||||||
|
<DisplayString>{m_size}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::basic_substringrs<*,*>">
|
||||||
|
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
|
||||||
|
<StringView>m_str,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[size]">
|
||||||
|
<DisplayString>{m_size}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[capacity]">
|
||||||
|
<DisplayString>{m_capacity}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[full]">
|
||||||
|
<DisplayString>{m_str,[m_capacity]}</DisplayString>
|
||||||
|
<StringView>m_str,[m_capacity]</StringView>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::basic_string<*,*,*>">
|
||||||
|
<DisplayString>{m_str,[m_size]} (sz={m_size},cap={m_capacity})</DisplayString>
|
||||||
|
<StringView>m_str,[m_size]</StringView>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[size]">
|
||||||
|
<DisplayString>{m_size}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[full]">
|
||||||
|
<DisplayString>{m_str,[m_capacity]}</DisplayString>
|
||||||
|
<StringView>m_str,[m_capacity]</StringView>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<!-- enum symbols -->
|
||||||
|
<Type Name="c4::EnumSymbols<*>::Sym">
|
||||||
|
<DisplayString>{value} - {name}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[value]">value</Item>
|
||||||
|
<Item Name="[name]">name</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="c4::EnumSymbols<*>">
|
||||||
|
<DisplayString>{m_symbols,[m_num]} (sz={m_num})</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_num</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_num</Size>
|
||||||
|
<ValuePointer>m_symbols</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
</AutoVisualizer>
|
2428
dep/rapidyaml/include/c4/charconv.hpp
Normal file
2428
dep/rapidyaml/include/c4/charconv.hpp
Normal file
File diff suppressed because it is too large
Load diff
117
dep/rapidyaml/include/c4/compiler.hpp
Normal file
117
dep/rapidyaml/include/c4/compiler.hpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#ifndef _C4_COMPILER_HPP_
|
||||||
|
#define _C4_COMPILER_HPP_
|
||||||
|
|
||||||
|
/** @file compiler.hpp Provides compiler information macros
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
#include "c4/platform.hpp"
|
||||||
|
|
||||||
|
// Compilers:
|
||||||
|
// C4_MSVC
|
||||||
|
// Visual Studio 2022: MSVC++ 17, 1930
|
||||||
|
// Visual Studio 2019: MSVC++ 16, 1920
|
||||||
|
// Visual Studio 2017: MSVC++ 15
|
||||||
|
// Visual Studio 2015: MSVC++ 14
|
||||||
|
// Visual Studio 2013: MSVC++ 13
|
||||||
|
// Visual Studio 2013: MSVC++ 12
|
||||||
|
// Visual Studio 2012: MSVC++ 11
|
||||||
|
// Visual Studio 2010: MSVC++ 10
|
||||||
|
// Visual Studio 2008: MSVC++ 09
|
||||||
|
// Visual Studio 2005: MSVC++ 08
|
||||||
|
// C4_CLANG
|
||||||
|
// C4_GCC
|
||||||
|
// C4_ICC (intel compiler)
|
||||||
|
/** @see http://sourceforge.net/p/predef/wiki/Compilers/ for a list of compiler identifier macros */
|
||||||
|
/** @see https://msdn.microsoft.com/en-us/library/b0084kay.aspx for VS2013 predefined macros */
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# define C4_MSVC
|
||||||
|
# define C4_MSVC_VERSION_2022 17
|
||||||
|
# define C4_MSVC_VERSION_2019 16
|
||||||
|
# define C4_MSVC_VERSION_2017 15
|
||||||
|
# define C4_MSVC_VERSION_2015 14
|
||||||
|
# define C4_MSVC_VERSION_2013 12
|
||||||
|
# define C4_MSVC_VERSION_2012 11
|
||||||
|
# if _MSC_VER >= 1930
|
||||||
|
# define C4_MSVC_VERSION C4_MSVC_VERSION_2022 // visual studio 2022
|
||||||
|
# define C4_MSVC_2022
|
||||||
|
# elif _MSC_VER >= 1920
|
||||||
|
# define C4_MSVC_VERSION C_4MSVC_VERSION_2019 // visual studio 2019
|
||||||
|
# define C4_MSVC_2019
|
||||||
|
# elif _MSC_VER >= 1910
|
||||||
|
# define C4_MSVC_VERSION C4_MSVC_VERSION_2017 // visual studio 2017
|
||||||
|
# define C4_MSVC_2017
|
||||||
|
# elif _MSC_VER == 1900
|
||||||
|
# define C4_MSVC_VERSION C4_MSVC_VERSION_2015 // visual studio 2015
|
||||||
|
# define C4_MSVC_2015
|
||||||
|
# elif _MSC_VER == 1800
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# define C4_MSVC_VERSION C4_MSVC_VERSION_2013 // visual studio 2013
|
||||||
|
# define C4_MSVC_2013
|
||||||
|
# elif _MSC_VER == 1700
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# define C4_MSVC_VERSION C4_MSVC_VERSION_2012 // visual studio 2012
|
||||||
|
# define C4_MSVC_2012
|
||||||
|
# elif _MSC_VER == 1600
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# define C4_MSVC_VERSION 10 // visual studio 2010
|
||||||
|
# define C4_MSVC_2010
|
||||||
|
# elif _MSC_VER == 1500
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# define C4_MSVC_VERSION 09 // visual studio 2008
|
||||||
|
# define C4_MSVC_2008
|
||||||
|
# elif _MSC_VER == 1400
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# define C4_MSVC_VERSION 08 // visual studio 2005
|
||||||
|
# define C4_MSVC_2005
|
||||||
|
# else
|
||||||
|
# error "MSVC version not supported"
|
||||||
|
# endif // _MSC_VER
|
||||||
|
#else
|
||||||
|
# define C4_MSVC_VERSION 0 // visual studio not present
|
||||||
|
# define C4_GCC_LIKE
|
||||||
|
# ifdef __INTEL_COMPILER // check ICC before checking GCC, as ICC defines __GNUC__ too
|
||||||
|
# define C4_ICC
|
||||||
|
# define C4_ICC_VERSION __INTEL_COMPILER
|
||||||
|
# elif defined(__APPLE_CC__)
|
||||||
|
# define C4_XCODE
|
||||||
|
# if defined(__clang__)
|
||||||
|
# define C4_CLANG
|
||||||
|
# ifndef __apple_build_version__
|
||||||
|
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||||
|
# else
|
||||||
|
# define C4_CLANG_VERSION __apple_build_version__
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define C4_XCODE_VERSION __APPLE_CC__
|
||||||
|
# endif
|
||||||
|
# elif defined(__clang__)
|
||||||
|
# define C4_CLANG
|
||||||
|
# ifndef __apple_build_version__
|
||||||
|
# define C4_CLANG_VERSION C4_VERSION_ENCODED(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||||
|
# else
|
||||||
|
# define C4_CLANG_VERSION __apple_build_version__
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# define C4_GCC
|
||||||
|
# if defined(__GNUC_PATCHLEVEL__)
|
||||||
|
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||||
|
# else
|
||||||
|
# define C4_GCC_VERSION C4_VERSION_ENCODED(__GNUC__, __GNUC_MINOR__, 0)
|
||||||
|
# endif
|
||||||
|
# if __GNUC__ < 5
|
||||||
|
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 8
|
||||||
|
// provided by cmake sub-project
|
||||||
|
# include "c4/gcc-4.8.hpp"
|
||||||
|
# else
|
||||||
|
// we do not support GCC < 4.8:
|
||||||
|
// * misses std::is_trivially_copyable
|
||||||
|
// * misses std::align
|
||||||
|
// * -Wshadow has false positives when a local function parameter has the same name as a method
|
||||||
|
# error "GCC < 4.8 is not supported"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif // defined(C4_WIN) && defined(_MSC_VER)
|
||||||
|
|
||||||
|
#endif /* _C4_COMPILER_HPP_ */
|
39
dep/rapidyaml/include/c4/config.hpp
Normal file
39
dep/rapidyaml/include/c4/config.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef _C4_CONFIG_HPP_
|
||||||
|
#define _C4_CONFIG_HPP_
|
||||||
|
|
||||||
|
/** @defgroup basic_headers Basic headers
|
||||||
|
* @brief Headers providing basic macros, platform+cpu+compiler information,
|
||||||
|
* C++ facilities and basic typedefs. */
|
||||||
|
|
||||||
|
/** @file config.hpp Contains configuration defines and includes the basic_headers.
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
//#define C4_DEBUG
|
||||||
|
|
||||||
|
#define C4_ERROR_SHOWS_FILELINE
|
||||||
|
//#define C4_ERROR_SHOWS_FUNC
|
||||||
|
//#define C4_ERROR_THROWS_EXCEPTION
|
||||||
|
//#define C4_NO_ALLOC_DEFAULTS
|
||||||
|
//#define C4_REDEFINE_CPPNEW
|
||||||
|
|
||||||
|
#ifndef C4_SIZE_TYPE
|
||||||
|
# define C4_SIZE_TYPE size_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef C4_STR_SIZE_TYPE
|
||||||
|
# define C4_STR_SIZE_TYPE C4_SIZE_TYPE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef C4_TIME_TYPE
|
||||||
|
# define C4_TIME_TYPE double
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "c4/export.hpp"
|
||||||
|
#include "c4/preprocessor.hpp"
|
||||||
|
#include "c4/platform.hpp"
|
||||||
|
#include "c4/cpu.hpp"
|
||||||
|
#include "c4/compiler.hpp"
|
||||||
|
#include "c4/language.hpp"
|
||||||
|
#include "c4/types.hpp"
|
||||||
|
|
||||||
|
#endif // _C4_CONFIG_HPP_
|
149
dep/rapidyaml/include/c4/cpu.hpp
Normal file
149
dep/rapidyaml/include/c4/cpu.hpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#ifndef _C4_CPU_HPP_
|
||||||
|
#define _C4_CPU_HPP_
|
||||||
|
|
||||||
|
/** @file cpu.hpp Provides processor information macros
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
// see also https://sourceforge.net/p/predef/wiki/Architectures/
|
||||||
|
// see also https://sourceforge.net/p/predef/wiki/Endianness/
|
||||||
|
// see also https://github.com/googlesamples/android-ndk/blob/android-mk/hello-jni/jni/hello-jni.c
|
||||||
|
// see http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
|
||||||
|
|
||||||
|
#ifdef __ORDER_LITTLE_ENDIAN__
|
||||||
|
# define _C4EL __ORDER_LITTLE_ENDIAN__
|
||||||
|
#else
|
||||||
|
# define _C4EL 1234
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ORDER_BIG_ENDIAN__
|
||||||
|
# define _C4EB __ORDER_BIG_ENDIAN__
|
||||||
|
#else
|
||||||
|
# define _C4EB 4321
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// mixed byte order (eg, PowerPC or ia64)
|
||||||
|
#define _C4EM 1111
|
||||||
|
|
||||||
|
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||||
|
# define C4_CPU_X86_64
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
|
||||||
|
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||||
|
# define C4_CPU_X86
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
|
||||||
|
#elif defined(__arm__) || defined(_M_ARM) \
|
||||||
|
|| defined(__TARGET_ARCH_ARM) || defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
# if defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
# define C4_CPU_ARM64
|
||||||
|
# define C4_CPU_ARMV8
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# else
|
||||||
|
# define C4_CPU_ARM
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
# if defined(__ARM_ARCH_8__) || defined(__ARM_ARCH_8A__) \
|
||||||
|
|| (defined(__ARCH_ARM) && __ARCH_ARM >= 8) \
|
||||||
|
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 8)
|
||||||
|
# define C4_CPU_ARMV8
|
||||||
|
# elif defined(__ARM_ARCH_7__) || defined(_ARM_ARCH_7) \
|
||||||
|
|| defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) \
|
||||||
|
|| defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) \
|
||||||
|
|| defined(__ARM_ARCH_7EM__) \
|
||||||
|
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 7) \
|
||||||
|
|| (defined(_M_ARM) && _M_ARM >= 7)
|
||||||
|
# define C4_CPU_ARMV7
|
||||||
|
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||||
|
|| defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) \
|
||||||
|
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) \
|
||||||
|
|| defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_6KZ__) \
|
||||||
|
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 6)
|
||||||
|
# define C4_CPU_ARMV6
|
||||||
|
# elif defined(__ARM_ARCH_5TEJ__) \
|
||||||
|
|| defined(__ARM_ARCH_5TE__) \
|
||||||
|
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 5)
|
||||||
|
# define C4_CPU_ARMV5
|
||||||
|
# elif defined(__ARM_ARCH_4T__) \
|
||||||
|
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM >= 4)
|
||||||
|
# define C4_CPU_ARMV4
|
||||||
|
# else
|
||||||
|
# error "unknown CPU architecture: ARM"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if defined(__ARMEL__) || defined(__LITTLE_ENDIAN__) || defined(__AARCH64EL__) \
|
||||||
|
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
|
||||||
|
|| defined(_MSC_VER) // winarm64 does not provide any of the above macros,
|
||||||
|
// but advises little-endianess:
|
||||||
|
// https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170
|
||||||
|
// So if it is visual studio compiling, we'll assume little endian.
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
# elif defined(__ARMEB__) || defined(__BIG_ENDIAN__) || defined(__AARCH64EB__) \
|
||||||
|
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||||
|
# define C4_BYTE_ORDER _C4EB
|
||||||
|
# elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_PDP_ENDIAN__)
|
||||||
|
# define C4_BYTE_ORDER _C4EM
|
||||||
|
# else
|
||||||
|
# error "unknown endianness"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||||
|
# define C4_CPU_IA64
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# define C4_BYTE_ORDER _C4EM
|
||||||
|
// itanium is bi-endian - check byte order below
|
||||||
|
|
||||||
|
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \
|
||||||
|
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \
|
||||||
|
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||||
|
# if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||||
|
# define C4_CPU_PPC64
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# else
|
||||||
|
# define C4_CPU_PPC
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
# endif
|
||||||
|
# define C4_BYTE_ORDER _C4EM
|
||||||
|
// ppc is bi-endian - check byte order below
|
||||||
|
|
||||||
|
#elif defined(__s390x__) || defined(__zarch__) || defined(__SYSC_ZARCH_)
|
||||||
|
# define C4_CPU_S390_X
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# define C4_BYTE_ORDER _C4EB
|
||||||
|
|
||||||
|
#elif defined(__xtensa__) || defined(__XTENSA__)
|
||||||
|
# define C4_CPU_XTENSA
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
// not sure about this...
|
||||||
|
# if defined(__XTENSA_EL__) || defined(__xtensa_el__)
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
# else
|
||||||
|
# define C4_BYTE_ORDER _C4EB
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__riscv)
|
||||||
|
# if __riscv_xlen == 64
|
||||||
|
# define C4_CPU_RISCV64
|
||||||
|
# define C4_WORDSIZE 8
|
||||||
|
# else
|
||||||
|
# define C4_CPU_RISCV32
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
# endif
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
# define C4_BYTE_ORDER _C4EL
|
||||||
|
# define C4_WORDSIZE 4
|
||||||
|
|
||||||
|
#elif defined(SWIG)
|
||||||
|
# error "please define CPU architecture macros when compiling with swig"
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "unknown CPU architecture"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define C4_LITTLE_ENDIAN (C4_BYTE_ORDER == _C4EL)
|
||||||
|
#define C4_BIG_ENDIAN (C4_BYTE_ORDER == _C4EB)
|
||||||
|
#define C4_MIXED_ENDIAN (C4_BYTE_ORDER == _C4EM)
|
||||||
|
|
||||||
|
#endif /* _C4_CPU_HPP_ */
|
582
dep/rapidyaml/include/c4/dump.hpp
Normal file
582
dep/rapidyaml/include/c4/dump.hpp
Normal file
|
@ -0,0 +1,582 @@
|
||||||
|
#ifndef C4_DUMP_HPP_
|
||||||
|
#define C4_DUMP_HPP_
|
||||||
|
|
||||||
|
#include <c4/substr.hpp>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** type of the function to dump characters */
|
||||||
|
using DumperPfn = void (*)(csubstr buf);
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Arg>
|
||||||
|
inline size_t dump(substr buf, Arg const& a)
|
||||||
|
{
|
||||||
|
size_t sz = to_chars(buf, a); // need to serialize to the buffer
|
||||||
|
if(C4_LIKELY(sz <= buf.len))
|
||||||
|
dumpfn(buf.first(sz));
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg>
|
||||||
|
inline size_t dump(DumperFn &&dumpfn, substr buf, Arg const& a)
|
||||||
|
{
|
||||||
|
size_t sz = to_chars(buf, a); // need to serialize to the buffer
|
||||||
|
if(C4_LIKELY(sz <= buf.len))
|
||||||
|
dumpfn(buf.first(sz));
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn>
|
||||||
|
inline size_t dump(substr buf, csubstr a)
|
||||||
|
{
|
||||||
|
if(buf.len)
|
||||||
|
dumpfn(a); // dump directly, no need to serialize to the buffer
|
||||||
|
return 0; // no space was used in the buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn>
|
||||||
|
inline size_t dump(DumperFn &&dumpfn, substr buf, csubstr a)
|
||||||
|
{
|
||||||
|
if(buf.len)
|
||||||
|
dumpfn(a); // dump directly, no need to serialize to the buffer
|
||||||
|
return 0; // no space was used in the buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, size_t N>
|
||||||
|
inline size_t dump(substr buf, const char (&a)[N])
|
||||||
|
{
|
||||||
|
if(buf.len)
|
||||||
|
dumpfn(csubstr(a)); // dump directly, no need to serialize to the buffer
|
||||||
|
return 0; // no space was used in the buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, size_t N>
|
||||||
|
inline size_t dump(DumperFn &&dumpfn, substr buf, const char (&a)[N])
|
||||||
|
{
|
||||||
|
if(buf.len)
|
||||||
|
dumpfn(csubstr(a)); // dump directly, no need to serialize to the buffer
|
||||||
|
return 0; // no space was used in the buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** */
|
||||||
|
struct DumpResults
|
||||||
|
{
|
||||||
|
enum : size_t { noarg = (size_t)-1 };
|
||||||
|
size_t bufsize = 0;
|
||||||
|
size_t lastok = noarg;
|
||||||
|
bool success_until(size_t expected) const { return lastok == noarg ? false : lastok >= expected; }
|
||||||
|
bool write_arg(size_t arg) const { return lastok == noarg || arg > lastok; }
|
||||||
|
size_t argfail() const { return lastok + 1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminates the variadic recursion
|
||||||
|
template<class DumperFn>
|
||||||
|
size_t cat_dump(DumperFn &&, substr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminates the variadic recursion
|
||||||
|
template<DumperPfn dumpfn>
|
||||||
|
size_t cat_dump(substr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
/** take the function pointer as a function argument */
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
size_t cat_dump(DumperFn &&dumpfn, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t size_for_a = dump(dumpfn, buf, a);
|
||||||
|
if(C4_UNLIKELY(size_for_a > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
size_t size_for_more = cat_dump(dumpfn, buf, more...);
|
||||||
|
return size_for_more > size_for_a ? size_for_more : size_for_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** take the function pointer as a template argument */
|
||||||
|
template<DumperPfn dumpfn,class Arg, class... Args>
|
||||||
|
size_t cat_dump(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t size_for_a = dump<dumpfn>(buf, a);
|
||||||
|
if(C4_LIKELY(size_for_a > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
size_t size_for_more = cat_dump<dumpfn>(buf, more...);
|
||||||
|
return size_for_more > size_for_a ? size_for_more : size_for_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// terminates the variadic recursion
|
||||||
|
template<DumperPfn dumpfn, class Arg>
|
||||||
|
DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg)))
|
||||||
|
{
|
||||||
|
size_t sz = dump<dumpfn>(buf, a); // yield to the specialized function
|
||||||
|
if(currarg == results.lastok + 1 && sz <= buf.len)
|
||||||
|
results.lastok = currarg;
|
||||||
|
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminates the variadic recursion
|
||||||
|
template<class DumperFn, class Arg>
|
||||||
|
DumpResults cat_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg)))
|
||||||
|
{
|
||||||
|
size_t sz = dump(dumpfn, buf, a); // yield to the specialized function
|
||||||
|
if(currarg == results.lastok + 1 && sz <= buf.len)
|
||||||
|
results.lastok = currarg;
|
||||||
|
results.bufsize = sz > results.bufsize ? sz : results.bufsize;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Arg, class... Args>
|
||||||
|
DumpResults cat_dump_resume(size_t currarg, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
results = detail::cat_dump_resume<dumpfn>(currarg, results, buf, a);
|
||||||
|
return detail::cat_dump_resume<dumpfn>(currarg + 1u, results, buf, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
DumpResults cat_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
results = detail::cat_dump_resume(currarg, dumpfn, results, buf, a);
|
||||||
|
return detail::cat_dump_resume(currarg + 1u, dumpfn, results, buf, more...);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
if(results.bufsize > buf.len)
|
||||||
|
return results;
|
||||||
|
return detail::cat_dump_resume<dumpfn>(0u, results, buf, a, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
if(results.bufsize > buf.len)
|
||||||
|
return results;
|
||||||
|
return detail::cat_dump_resume(0u, dumpfn, results, buf, a, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults cat_dump_resume(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::cat_dump_resume<dumpfn>(0u, DumpResults{}, buf, a, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults cat_dump_resume(DumperFn &&dumpfn, substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::cat_dump_resume(0u, dumpfn, DumpResults{}, buf, a, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminate the recursion
|
||||||
|
template<class DumperFn, class Sep>
|
||||||
|
size_t catsep_dump(DumperFn &&, substr, Sep const& C4_RESTRICT)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate the recursion
|
||||||
|
template<DumperPfn dumpfn, class Sep>
|
||||||
|
size_t catsep_dump(substr, Sep const& C4_RESTRICT)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
/** take the function pointer as a function argument */
|
||||||
|
template<class DumperFn, class Sep, class Arg, class... Args>
|
||||||
|
size_t catsep_dump(DumperFn &&dumpfn, substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t sz = dump(dumpfn, buf, a);
|
||||||
|
if(C4_UNLIKELY(sz > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
|
||||||
|
{
|
||||||
|
size_t szsep = dump(dumpfn, buf, sep);
|
||||||
|
if(C4_UNLIKELY(szsep > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
sz = sz > szsep ? sz : szsep;
|
||||||
|
}
|
||||||
|
size_t size_for_more = catsep_dump(dumpfn, buf, sep, more...);
|
||||||
|
return size_for_more > sz ? size_for_more : sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** take the function pointer as a template argument */
|
||||||
|
template<DumperPfn dumpfn, class Sep, class Arg, class... Args>
|
||||||
|
size_t catsep_dump(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t sz = dump<dumpfn>(buf, a);
|
||||||
|
if(C4_UNLIKELY(sz > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
if C4_IF_CONSTEXPR (sizeof...(more) > 0)
|
||||||
|
{
|
||||||
|
size_t szsep = dump<dumpfn>(buf, sep);
|
||||||
|
if(C4_UNLIKELY(szsep > buf.len))
|
||||||
|
buf = buf.first(0); // ensure no more calls
|
||||||
|
sz = sz > szsep ? sz : szsep;
|
||||||
|
}
|
||||||
|
size_t size_for_more = catsep_dump<dumpfn>(buf, sep, more...);
|
||||||
|
return size_for_more > sz ? size_for_more : sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
namespace detail {
|
||||||
|
template<DumperPfn dumpfn, class Arg>
|
||||||
|
void catsep_dump_resume_(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(results->write_arg(currarg)))
|
||||||
|
{
|
||||||
|
size_t sz = dump<dumpfn>(*buf, a);
|
||||||
|
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
|
||||||
|
if(C4_LIKELY(sz <= buf->len))
|
||||||
|
results->lastok = currarg;
|
||||||
|
else
|
||||||
|
buf->len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg>
|
||||||
|
void catsep_dump_resume_(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(results->write_arg(currarg)))
|
||||||
|
{
|
||||||
|
size_t sz = dump(dumpfn, *buf, a);
|
||||||
|
results->bufsize = sz > results->bufsize ? sz : results->bufsize;
|
||||||
|
if(C4_LIKELY(sz <= buf->len))
|
||||||
|
results->lastok = currarg;
|
||||||
|
else
|
||||||
|
buf->len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Sep, class Arg>
|
||||||
|
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume_<dumpfn>(currarg, results, buf, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Sep, class Arg>
|
||||||
|
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT, Arg const& C4_RESTRICT a)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume_(currarg, dumpfn, results, buf, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Sep, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume_<dumpfn>(currarg , results, buf, a);
|
||||||
|
detail::catsep_dump_resume_<dumpfn>(currarg + 1u, results, buf, sep);
|
||||||
|
detail::catsep_dump_resume <dumpfn>(currarg + 2u, results, buf, sep, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Sep, class Arg, class... Args>
|
||||||
|
C4_ALWAYS_INLINE void catsep_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults *C4_RESTRICT results, substr *C4_RESTRICT buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume_(currarg , dumpfn, results, buf, a);
|
||||||
|
detail::catsep_dump_resume_(currarg + 1u, dumpfn, results, buf, sep);
|
||||||
|
detail::catsep_dump_resume (currarg + 2u, dumpfn, results, buf, sep, more...);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Sep, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumpResults results, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume<dumpfn>(0u, &results, &buf, sep, more...);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Sep, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
detail::catsep_dump_resume(0u, dumpfn, &results, &buf, sep, more...);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Sep, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
DumpResults results;
|
||||||
|
detail::catsep_dump_resume<dumpfn>(0u, &results, &buf, sep, more...);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class Sep, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults catsep_dump_resume(DumperFn &&dumpfn, substr buf, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
DumpResults results;
|
||||||
|
detail::catsep_dump_resume(0u, dumpfn, &results, &buf, sep, more...);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** take the function pointer as a function argument */
|
||||||
|
template<class DumperFn>
|
||||||
|
C4_ALWAYS_INLINE size_t format_dump(DumperFn &&dumpfn, substr buf, csubstr fmt)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(buf.len > 0 && fmt.len))
|
||||||
|
dumpfn(fmt);
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** take the function pointer as a function argument */
|
||||||
|
template<DumperPfn dumpfn>
|
||||||
|
C4_ALWAYS_INLINE size_t format_dump(substr buf, csubstr fmt)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
|
||||||
|
dumpfn(fmt);
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** take the function pointer as a function argument */
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
size_t format_dump(DumperFn &&dumpfn, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
|
||||||
|
dumpfn(fmt);
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
if(C4_LIKELY(buf.len > 0 && pos > 0))
|
||||||
|
dumpfn(fmt.first(pos)); // we can dump without using buf
|
||||||
|
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
|
||||||
|
pos = dump(dumpfn, buf, a);
|
||||||
|
if(C4_UNLIKELY(pos > buf.len))
|
||||||
|
buf.len = 0; // ensure no more calls to dump
|
||||||
|
size_t size_for_more = format_dump(dumpfn, buf, fmt, more...);
|
||||||
|
return size_for_more > pos ? size_for_more : pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** take the function pointer as a template argument */
|
||||||
|
template<DumperPfn dumpfn, class Arg, class... Args>
|
||||||
|
size_t format_dump(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(buf.len > 0 && fmt.len > 0))
|
||||||
|
dumpfn(fmt);
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
if(C4_LIKELY(buf.len > 0 && pos > 0))
|
||||||
|
dumpfn(fmt.first(pos)); // we can dump without using buf
|
||||||
|
fmt = fmt.sub(pos + 2); // skip {} do this before assigning to pos again
|
||||||
|
pos = dump<dumpfn>(buf, a);
|
||||||
|
if(C4_UNLIKELY(pos > buf.len))
|
||||||
|
buf.len = 0; // ensure no more calls to dump
|
||||||
|
size_t size_for_more = format_dump<dumpfn>(buf, fmt, more...);
|
||||||
|
return size_for_more > pos ? size_for_more : pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn>
|
||||||
|
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
dumpfn(fmt);
|
||||||
|
results.lastok = currarg;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn>
|
||||||
|
DumpResults format_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt)
|
||||||
|
{
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
dumpfn(fmt);
|
||||||
|
results.lastok = currarg;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class Arg, class... Args>
|
||||||
|
DumpResults format_dump_resume(size_t currarg, DumpResults results, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
// we need to process the format even if we're not
|
||||||
|
// going to print the first arguments because we're resuming
|
||||||
|
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg)))
|
||||||
|
{
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
results.lastok = currarg;
|
||||||
|
dumpfn(fmt);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
results.lastok = currarg;
|
||||||
|
dumpfn(fmt.first(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt = fmt.sub(pos + 2);
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg + 1)))
|
||||||
|
{
|
||||||
|
pos = dump<dumpfn>(buf, a);
|
||||||
|
results.bufsize = pos > results.bufsize ? pos : results.bufsize;
|
||||||
|
if(C4_LIKELY(pos <= buf.len))
|
||||||
|
results.lastok = currarg + 1;
|
||||||
|
else
|
||||||
|
buf.len = 0;
|
||||||
|
}
|
||||||
|
return detail::format_dump_resume<dumpfn>(currarg + 2u, results, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
template<class DumperFn, class Arg, class... Args>
|
||||||
|
DumpResults format_dump_resume(size_t currarg, DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
// we need to process the format even if we're not
|
||||||
|
// going to print the first arguments because we're resuming
|
||||||
|
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
|
||||||
|
// we can dump without using buf
|
||||||
|
// but we'll only dump if the buffer is ok
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg)))
|
||||||
|
{
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
results.lastok = currarg;
|
||||||
|
dumpfn(fmt);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
if(C4_LIKELY(buf.len > 0))
|
||||||
|
{
|
||||||
|
results.lastok = currarg;
|
||||||
|
dumpfn(fmt.first(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt = fmt.sub(pos + 2);
|
||||||
|
if(C4_LIKELY(results.write_arg(currarg + 1)))
|
||||||
|
{
|
||||||
|
pos = dump(dumpfn, buf, a);
|
||||||
|
results.bufsize = pos > results.bufsize ? pos : results.bufsize;
|
||||||
|
if(C4_LIKELY(pos <= buf.len))
|
||||||
|
results.lastok = currarg + 1;
|
||||||
|
else
|
||||||
|
buf.len = 0;
|
||||||
|
}
|
||||||
|
return detail::format_dump_resume(currarg + 2u, dumpfn, results, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults format_dump_resume(DumpResults results, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::format_dump_resume<dumpfn>(0u, results, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, DumpResults results, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::format_dump_resume(0u, dumpfn, results, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<DumperPfn dumpfn, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults format_dump_resume(substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::format_dump_resume<dumpfn>(0u, DumpResults{}, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DumperFn, class... Args>
|
||||||
|
C4_ALWAYS_INLINE DumpResults format_dump_resume(DumperFn &&dumpfn, substr buf, csubstr fmt, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
return detail::format_dump_resume(0u, dumpfn, DumpResults{}, buf, fmt, more...);
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* C4_DUMP_HPP_ */
|
435
dep/rapidyaml/include/c4/error.hpp
Normal file
435
dep/rapidyaml/include/c4/error.hpp
Normal file
|
@ -0,0 +1,435 @@
|
||||||
|
#ifndef _C4_ERROR_HPP_
|
||||||
|
#define _C4_ERROR_HPP_
|
||||||
|
|
||||||
|
/** @file error.hpp Facilities for error reporting and runtime assertions. */
|
||||||
|
|
||||||
|
/** @defgroup error_checking Error checking */
|
||||||
|
|
||||||
|
#include "c4/config.hpp"
|
||||||
|
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
|
||||||
|
* will throw an exception
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_EXCEPTIONS_ENABLED
|
||||||
|
/** if this is defined and exceptions are enabled, then calls to C4_ERROR()
|
||||||
|
* will throw an exception
|
||||||
|
* @see C4_EXCEPTIONS_ENABLED
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_ERROR_THROWS_EXCEPTION
|
||||||
|
/** evaluates to noexcept when C4_ERROR might be called and
|
||||||
|
* exceptions are disabled. Otherwise, defaults to nothing.
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_NOEXCEPT
|
||||||
|
#endif // _DOXYGEN_
|
||||||
|
|
||||||
|
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
|
||||||
|
# define C4_NOEXCEPT
|
||||||
|
#else
|
||||||
|
# define C4_NOEXCEPT noexcept
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace detail {
|
||||||
|
struct fail_type__ {};
|
||||||
|
} // detail
|
||||||
|
} // c4
|
||||||
|
#define C4_STATIC_ERROR(dummy_type, errmsg) \
|
||||||
|
static_assert(std::is_same<dummy_type, c4::detail::fail_type__>::value, errmsg)
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define C4_ASSERT_SAME_TYPE(ty1, ty2) \
|
||||||
|
C4_STATIC_ASSERT(std::is_same<ty1 C4_COMMA_X ty2>::value)
|
||||||
|
|
||||||
|
#define C4_ASSERT_DIFF_TYPE(ty1, ty2) \
|
||||||
|
C4_STATIC_ASSERT( ! std::is_same<ty1 C4_COMMA_X ty2>::value)
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
/** utility macro that triggers a breakpoint when
|
||||||
|
* the debugger is attached and NDEBUG is not defined.
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_DEBUG_BREAK()
|
||||||
|
#endif // _DOXYGEN_
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
|
||||||
|
# define C4_DEBUG_BREAK()
|
||||||
|
#else
|
||||||
|
# ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# if !defined(__APPLE_CC__)
|
||||||
|
# if __clang_major__ >= 10
|
||||||
|
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if __clang_major__ >= 13
|
||||||
|
# pragma clang diagnostic ignored "-Wgnu-inline-cpp-without-extern" // debugbreak/debugbreak.h:50:16: error: 'gnu_inline' attribute without 'extern' in C++ treated as externally available, this changed in Clang 10 [-Werror,-Wgnu-inline-cpp-without-extern]
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# endif
|
||||||
|
# include <c4/ext/debugbreak/debugbreak.h>
|
||||||
|
# define C4_DEBUG_BREAK() if(c4::is_debugger_attached()) { ::debug_break(); }
|
||||||
|
# ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
C4CORE_EXPORT bool is_debugger_attached();
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
|
||||||
|
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
|
||||||
|
* clang requires switching off compiler warnings for pedantic mode.
|
||||||
|
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
/* GCC also issues a warning for zero-args calls to variadic macros.
|
||||||
|
* This warning is switched on with -pedantic and apparently there is no
|
||||||
|
* easy way to turn it off as with clang. But marking this as a system
|
||||||
|
* header works.
|
||||||
|
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
|
||||||
|
* @see http://stackoverflow.com/questions/35587137/ */
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
typedef enum : uint32_t {
|
||||||
|
/** when an error happens and the debugger is attached, call C4_DEBUG_BREAK().
|
||||||
|
* Without effect otherwise. */
|
||||||
|
ON_ERROR_DEBUGBREAK = 0x01 << 0,
|
||||||
|
/** when an error happens log a message. */
|
||||||
|
ON_ERROR_LOG = 0x01 << 1,
|
||||||
|
/** when an error happens invoke a callback if it was set with
|
||||||
|
* set_error_callback(). */
|
||||||
|
ON_ERROR_CALLBACK = 0x01 << 2,
|
||||||
|
/** when an error happens call std::terminate(). */
|
||||||
|
ON_ERROR_ABORT = 0x01 << 3,
|
||||||
|
/** when an error happens and exceptions are enabled throw an exception.
|
||||||
|
* Without effect otherwise. */
|
||||||
|
ON_ERROR_THROW = 0x01 << 4,
|
||||||
|
/** the default flags. */
|
||||||
|
ON_ERROR_DEFAULTS = ON_ERROR_DEBUGBREAK|ON_ERROR_LOG|ON_ERROR_CALLBACK|ON_ERROR_ABORT
|
||||||
|
} ErrorFlags_e;
|
||||||
|
using error_flags = uint32_t;
|
||||||
|
C4CORE_EXPORT void set_error_flags(error_flags f);
|
||||||
|
C4CORE_EXPORT error_flags get_error_flags();
|
||||||
|
|
||||||
|
|
||||||
|
using error_callback_type = void (*)(const char* msg, size_t msg_size);
|
||||||
|
C4CORE_EXPORT void set_error_callback(error_callback_type cb);
|
||||||
|
C4CORE_EXPORT error_callback_type get_error_callback();
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** RAII class controling the error settings inside a scope. */
|
||||||
|
struct ScopedErrorSettings
|
||||||
|
{
|
||||||
|
error_flags m_flags;
|
||||||
|
error_callback_type m_callback;
|
||||||
|
|
||||||
|
explicit ScopedErrorSettings(error_callback_type cb)
|
||||||
|
: m_flags(get_error_flags()),
|
||||||
|
m_callback(get_error_callback())
|
||||||
|
{
|
||||||
|
set_error_callback(cb);
|
||||||
|
}
|
||||||
|
explicit ScopedErrorSettings(error_flags flags)
|
||||||
|
: m_flags(get_error_flags()),
|
||||||
|
m_callback(get_error_callback())
|
||||||
|
{
|
||||||
|
set_error_flags(flags);
|
||||||
|
}
|
||||||
|
explicit ScopedErrorSettings(error_flags flags, error_callback_type cb)
|
||||||
|
: m_flags(get_error_flags()),
|
||||||
|
m_callback(get_error_callback())
|
||||||
|
{
|
||||||
|
set_error_flags(flags);
|
||||||
|
set_error_callback(cb);
|
||||||
|
}
|
||||||
|
~ScopedErrorSettings()
|
||||||
|
{
|
||||||
|
set_error_flags(m_flags);
|
||||||
|
set_error_callback(m_callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** source location */
|
||||||
|
struct srcloc;
|
||||||
|
|
||||||
|
C4CORE_EXPORT void handle_error(srcloc s, const char *fmt, ...);
|
||||||
|
C4CORE_EXPORT void handle_warning(srcloc s, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
|
# define C4_ERROR(msg, ...) \
|
||||||
|
do { \
|
||||||
|
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
|
||||||
|
{ \
|
||||||
|
C4_DEBUG_BREAK() \
|
||||||
|
} \
|
||||||
|
c4::handle_error(C4_SRCLOC(), msg, ## __VA_ARGS__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
# define C4_WARNING(msg, ...) \
|
||||||
|
c4::handle_warning(C4_SRCLOC(), msg, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
|
||||||
|
struct srcloc
|
||||||
|
{
|
||||||
|
const char *file = "";
|
||||||
|
const char *func = "";
|
||||||
|
int line = 0;
|
||||||
|
};
|
||||||
|
#define C4_SRCLOC() c4::srcloc{__FILE__, C4_PRETTY_FUNC, __LINE__}
|
||||||
|
|
||||||
|
#elif defined(C4_ERROR_SHOWS_FILELINE)
|
||||||
|
|
||||||
|
struct srcloc
|
||||||
|
{
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
#define C4_SRCLOC() c4::srcloc{__FILE__, __LINE__}
|
||||||
|
|
||||||
|
#elif ! defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
|
||||||
|
struct srcloc
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#define C4_SRCLOC() c4::srcloc()
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error not implemented
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// assertions
|
||||||
|
|
||||||
|
// Doxygen needs this so that only one definition counts
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
/** Explicitly enables assertions, independently of NDEBUG status.
|
||||||
|
* This is meant to allow enabling assertions even when NDEBUG is defined.
|
||||||
|
* Defaults to undefined.
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_USE_ASSERT
|
||||||
|
/** assert that a condition is true; this is turned off when NDEBUG
|
||||||
|
* is defined and C4_USE_ASSERT is not true.
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_ASSERT
|
||||||
|
/** same as C4_ASSERT(), additionally prints a printf-formatted message
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_ASSERT_MSG
|
||||||
|
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults
|
||||||
|
* to noexcept
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_NOEXCEPT_A
|
||||||
|
#endif // _DOXYGEN_
|
||||||
|
|
||||||
|
#ifndef C4_USE_ASSERT
|
||||||
|
# ifdef NDEBUG
|
||||||
|
# define C4_USE_ASSERT 0
|
||||||
|
# else
|
||||||
|
# define C4_USE_ASSERT 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if C4_USE_ASSERT
|
||||||
|
# define C4_ASSERT(cond) C4_CHECK(cond)
|
||||||
|
# define C4_ASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
|
||||||
|
# define C4_ASSERT_IF(predicate, cond) if(predicate) { C4_ASSERT(cond); }
|
||||||
|
# define C4_NOEXCEPT_A C4_NOEXCEPT
|
||||||
|
#else
|
||||||
|
# define C4_ASSERT(cond)
|
||||||
|
# define C4_ASSERT_MSG(cond, /*fmt, */...)
|
||||||
|
# define C4_ASSERT_IF(predicate, cond)
|
||||||
|
# define C4_NOEXCEPT_A noexcept
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// extreme assertions
|
||||||
|
|
||||||
|
// Doxygen needs this so that only one definition counts
|
||||||
|
#ifdef _DOXYGEN_
|
||||||
|
/** Explicitly enables extreme assertions; this is meant to allow enabling
|
||||||
|
* assertions even when NDEBUG is defined. Defaults to undefined.
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_USE_XASSERT
|
||||||
|
/** extreme assertion: can be switched off independently of
|
||||||
|
* the regular assertion; use for example for bounds checking in hot code.
|
||||||
|
* Turned on only when C4_USE_XASSERT is defined
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_XASSERT
|
||||||
|
/** same as C4_XASSERT(), and additionally prints a printf-formatted message
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_XASSERT_MSG
|
||||||
|
/** evaluates to C4_NOEXCEPT when C4_XASSERT is disabled; otherwise, defaults to noexcept
|
||||||
|
* @ingroup error_checking */
|
||||||
|
# define C4_NOEXCEPT_X
|
||||||
|
#endif // _DOXYGEN_
|
||||||
|
|
||||||
|
#ifndef C4_USE_XASSERT
|
||||||
|
# define C4_USE_XASSERT C4_USE_ASSERT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if C4_USE_XASSERT
|
||||||
|
# define C4_XASSERT(cond) C4_CHECK(cond)
|
||||||
|
# define C4_XASSERT_MSG(cond, /*fmt, */...) C4_CHECK_MSG(cond, ## __VA_ARGS__)
|
||||||
|
# define C4_XASSERT_IF(predicate, cond) if(predicate) { C4_XASSERT(cond); }
|
||||||
|
# define C4_NOEXCEPT_X C4_NOEXCEPT
|
||||||
|
#else
|
||||||
|
# define C4_XASSERT(cond)
|
||||||
|
# define C4_XASSERT_MSG(cond, /*fmt, */...)
|
||||||
|
# define C4_XASSERT_IF(predicate, cond)
|
||||||
|
# define C4_NOEXCEPT_X noexcept
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// checks: never switched-off
|
||||||
|
|
||||||
|
/** Check that a condition is true, or raise an error when not
|
||||||
|
* true. Unlike C4_ASSERT(), this check is not disabled in non-debug
|
||||||
|
* builds.
|
||||||
|
* @see C4_ASSERT
|
||||||
|
* @ingroup error_checking
|
||||||
|
*
|
||||||
|
* @todo add constexpr-compatible compile-time assert:
|
||||||
|
* https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
|
||||||
|
*/
|
||||||
|
#define C4_CHECK(cond) \
|
||||||
|
do { \
|
||||||
|
if(C4_UNLIKELY(!(cond))) \
|
||||||
|
{ \
|
||||||
|
C4_ERROR("check failed: %s", #cond); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
/** like C4_CHECK(), and additionally log a printf-style message.
|
||||||
|
* @see C4_CHECK
|
||||||
|
* @ingroup error_checking */
|
||||||
|
#define C4_CHECK_MSG(cond, fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if(C4_UNLIKELY(!(cond))) \
|
||||||
|
{ \
|
||||||
|
C4_ERROR("check failed: " #cond "\n" fmt, ## __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Common error conditions
|
||||||
|
|
||||||
|
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
|
||||||
|
#define C4_NOT_IMPLEMENTED_MSG(/*msg, */...) C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__)
|
||||||
|
#define C4_NOT_IMPLEMENTED_IF(condition) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); } } while(0)
|
||||||
|
#define C4_NOT_IMPLEMENTED_IF_MSG(condition, /*msg, */...) do { if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " __VA_ARGS__); } } while(0)
|
||||||
|
|
||||||
|
#define C4_NEVER_REACH() do { C4_ERROR("never reach this point"); C4_UNREACHABLE(); } while(0)
|
||||||
|
#define C4_NEVER_REACH_MSG(/*msg, */...) do { C4_ERROR("never reach this point: " __VA_ARGS__); C4_UNREACHABLE(); } while(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// helpers for warning suppression
|
||||||
|
// idea adapted from https://github.com/onqtam/doctest/
|
||||||
|
|
||||||
|
// TODO: add C4_MESSAGE() https://stackoverflow.com/questions/18252351/custom-preprocessor-macro-for-a-conditional-pragma-message-xxx?rq=1
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC_PUSH __pragma(warning(push))
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC(w) __pragma(warning(disable : w))
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC_POP __pragma(warning(pop))
|
||||||
|
#else // C4_MSVC
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC_PUSH
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC(w)
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC_POP
|
||||||
|
#endif // C4_MSVC
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef C4_CLANG
|
||||||
|
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG_PUSH _Pragma("clang diagnostic push")
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG(w) C4_PRAGMA_TO_STR(clang diagnostic ignored w)
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG_POP _Pragma("clang diagnostic pop")
|
||||||
|
#else // C4_CLANG
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG_PUSH
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG(w)
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG_POP
|
||||||
|
#endif // C4_CLANG
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef C4_GCC
|
||||||
|
#define C4_PRAGMA_TO_STR(x) _Pragma(#x)
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_PUSH _Pragma("GCC diagnostic push")
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC(w) C4_PRAGMA_TO_STR(GCC diagnostic ignored w)
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_POP _Pragma("GCC diagnostic pop")
|
||||||
|
#else // C4_GCC
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_PUSH
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC(w)
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_POP
|
||||||
|
#endif // C4_GCC
|
||||||
|
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(w) \
|
||||||
|
C4_SUPPRESS_WARNING_MSVC_PUSH \
|
||||||
|
C4_SUPPRESS_WARNING_MSVC(w)
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w) \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG_PUSH \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG(w)
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
|
||||||
|
C4_SUPPRESS_WARNING_GCC_PUSH \
|
||||||
|
C4_SUPPRESS_WARNING_GCC(w)
|
||||||
|
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_CLANG_PUSH \
|
||||||
|
C4_SUPPRESS_WARNING_GCC_PUSH \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG_PUSH
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_CLANG(w) \
|
||||||
|
C4_SUPPRESS_WARNING_GCC(w) \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG(w)
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH(w) \
|
||||||
|
C4_SUPPRESS_WARNING_GCC_WITH_PUSH(w) \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG_WITH_PUSH(w)
|
||||||
|
|
||||||
|
#define C4_SUPPRESS_WARNING_GCC_CLANG_POP \
|
||||||
|
C4_SUPPRESS_WARNING_GCC_POP \
|
||||||
|
C4_SUPPRESS_WARNING_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_ERROR_HPP_ */
|
18
dep/rapidyaml/include/c4/export.hpp
Normal file
18
dep/rapidyaml/include/c4/export.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef C4_EXPORT_HPP_
|
||||||
|
#define C4_EXPORT_HPP_
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef C4CORE_SHARED
|
||||||
|
#ifdef C4CORE_EXPORTS
|
||||||
|
#define C4CORE_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define C4CORE_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define C4CORE_EXPORT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define C4CORE_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* C4CORE_EXPORT_HPP_ */
|
879
dep/rapidyaml/include/c4/format.hpp
Normal file
879
dep/rapidyaml/include/c4/format.hpp
Normal file
|
@ -0,0 +1,879 @@
|
||||||
|
#ifndef _C4_FORMAT_HPP_
|
||||||
|
#define _C4_FORMAT_HPP_
|
||||||
|
|
||||||
|
/** @file format.hpp provides type-safe facilities for formatting arguments
|
||||||
|
* to string buffers */
|
||||||
|
|
||||||
|
#include "c4/charconv.hpp"
|
||||||
|
#include "c4/blob.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017
|
||||||
|
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)
|
||||||
|
# endif
|
||||||
|
# pragma warning(disable: 4996) // snprintf/scanf: this function or variable may be unsafe
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wuseless-cast"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// formatting truthy types as booleans
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
/** write a variable as an alphabetic boolean, ie as either true or false
|
||||||
|
* @param strict_read */
|
||||||
|
template<class T>
|
||||||
|
struct boolalpha_
|
||||||
|
{
|
||||||
|
boolalpha_(T val_, bool strict_read_=false) : val(val_ ? true : false), strict_read(strict_read_) {}
|
||||||
|
bool val;
|
||||||
|
bool strict_read;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
boolalpha_<T> boolalpha(T const& val, bool strict_read=false)
|
||||||
|
{
|
||||||
|
return boolalpha_<T>(val, strict_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
/** write a variable as an alphabetic boolean, ie as either true or false */
|
||||||
|
template<class T>
|
||||||
|
inline size_t to_chars(substr buf, fmt::boolalpha_<T> fmt)
|
||||||
|
{
|
||||||
|
return to_chars(buf, fmt.val ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// formatting integral types
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
/** format an integral type with a custom radix */
|
||||||
|
template<typename T>
|
||||||
|
struct integral_
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
T radix;
|
||||||
|
C4_ALWAYS_INLINE integral_(T val_, T radix_) : val(val_), radix(radix_) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** format an integral type with a custom radix, and pad with zeroes on the left */
|
||||||
|
template<typename T>
|
||||||
|
struct integral_padded_
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
T radix;
|
||||||
|
size_t num_digits;
|
||||||
|
C4_ALWAYS_INLINE integral_padded_(T val_, T radix_, size_t nd) : val(val_), radix(radix_), num_digits(nd) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** format an integral type with a custom radix */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_<T> integral(T val, T radix=10)
|
||||||
|
{
|
||||||
|
return integral_<T>(val, radix);
|
||||||
|
}
|
||||||
|
/** format an integral type with a custom radix */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_<intptr_t> integral(T const* val, T radix=10)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(val), static_cast<intptr_t>(radix));
|
||||||
|
}
|
||||||
|
/** format an integral type with a custom radix */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_<intptr_t> integral(std::nullptr_t, T radix=10)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(intptr_t(0), static_cast<intptr_t>(radix));
|
||||||
|
}
|
||||||
|
/** pad the argument with zeroes on the left, with decimal radix */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_padded_<T> zpad(T val, size_t num_digits)
|
||||||
|
{
|
||||||
|
return integral_padded_<T>(val, T(10), num_digits);
|
||||||
|
}
|
||||||
|
/** pad the argument with zeroes on the left */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_padded_<T> zpad(integral_<T> val, size_t num_digits)
|
||||||
|
{
|
||||||
|
return integral_padded_<T>(val.val, val.radix, num_digits);
|
||||||
|
}
|
||||||
|
/** pad the argument with zeroes on the left */
|
||||||
|
C4_ALWAYS_INLINE integral_padded_<intptr_t> zpad(std::nullptr_t, size_t num_digits)
|
||||||
|
{
|
||||||
|
return integral_padded_<intptr_t>(0, 16, num_digits);
|
||||||
|
}
|
||||||
|
/** pad the argument with zeroes on the left */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_padded_<intptr_t> zpad(T const* val, size_t num_digits)
|
||||||
|
{
|
||||||
|
return integral_padded_<intptr_t>(reinterpret_cast<intptr_t>(val), 16, num_digits);
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE integral_padded_<intptr_t> zpad(T * val, size_t num_digits)
|
||||||
|
{
|
||||||
|
return integral_padded_<intptr_t>(reinterpret_cast<intptr_t>(val), 16, num_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** format the pointer as an hexadecimal value */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> hex(T * v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(16));
|
||||||
|
}
|
||||||
|
/** format the pointer as an hexadecimal value */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> hex(T const* v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(16));
|
||||||
|
}
|
||||||
|
/** format null as an hexadecimal value
|
||||||
|
* @overload hex */
|
||||||
|
inline integral_<intptr_t> hex(std::nullptr_t)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(0, intptr_t(16));
|
||||||
|
}
|
||||||
|
/** format the integral_ argument as an hexadecimal value
|
||||||
|
* @overload hex */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<T> hex(T v)
|
||||||
|
{
|
||||||
|
return integral_<T>(v, T(16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** format the pointer as an octal value */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> oct(T const* v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(8));
|
||||||
|
}
|
||||||
|
/** format the pointer as an octal value */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> oct(T * v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(8));
|
||||||
|
}
|
||||||
|
/** format null as an octal value */
|
||||||
|
inline integral_<intptr_t> oct(std::nullptr_t)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(intptr_t(0), intptr_t(8));
|
||||||
|
}
|
||||||
|
/** format the integral_ argument as an octal value */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<T> oct(T v)
|
||||||
|
{
|
||||||
|
return integral_<T>(v, T(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** format the pointer as a binary 0-1 value
|
||||||
|
* @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> bin(T const* v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(2));
|
||||||
|
}
|
||||||
|
/** format the pointer as a binary 0-1 value
|
||||||
|
* @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<intptr_t> bin(T * v)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(reinterpret_cast<intptr_t>(v), intptr_t(2));
|
||||||
|
}
|
||||||
|
/** format null as a binary 0-1 value
|
||||||
|
* @see c4::raw() if you want to use a binary memcpy instead of 0-1 formatting */
|
||||||
|
inline integral_<intptr_t> bin(std::nullptr_t)
|
||||||
|
{
|
||||||
|
return integral_<intptr_t>(intptr_t(0), intptr_t(2));
|
||||||
|
}
|
||||||
|
/** format the integral_ argument as a binary 0-1 value
|
||||||
|
* @see c4::raw() if you want to use a raw memcpy-based binary dump instead of 0-1 formatting */
|
||||||
|
template<class T>
|
||||||
|
inline integral_<T> bin(T v)
|
||||||
|
{
|
||||||
|
return integral_<T>(v, T(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct overflow_checked_
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<T>::value, "range checking only for integral types");
|
||||||
|
C4_ALWAYS_INLINE overflow_checked_(T &val_) : val(&val_) {}
|
||||||
|
T *val;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE overflow_checked_<T> overflow_checked(T &val)
|
||||||
|
{
|
||||||
|
return overflow_checked_<T>(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
/** format an integral_ signed type */
|
||||||
|
template<typename T>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if<std::is_signed<T>::value, size_t>::type
|
||||||
|
to_chars(substr buf, fmt::integral_<T> fmt)
|
||||||
|
{
|
||||||
|
return itoa(buf, fmt.val, fmt.radix);
|
||||||
|
}
|
||||||
|
/** format an integral_ signed type, pad with zeroes */
|
||||||
|
template<typename T>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if<std::is_signed<T>::value, size_t>::type
|
||||||
|
to_chars(substr buf, fmt::integral_padded_<T> fmt)
|
||||||
|
{
|
||||||
|
return itoa(buf, fmt.val, fmt.radix, fmt.num_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** format an integral_ unsigned type */
|
||||||
|
template<typename T>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if<std::is_unsigned<T>::value, size_t>::type
|
||||||
|
to_chars(substr buf, fmt::integral_<T> fmt)
|
||||||
|
{
|
||||||
|
return utoa(buf, fmt.val, fmt.radix);
|
||||||
|
}
|
||||||
|
/** format an integral_ unsigned type, pad with zeroes */
|
||||||
|
template<typename T>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if<std::is_unsigned<T>::value, size_t>::type
|
||||||
|
to_chars(substr buf, fmt::integral_padded_<T> fmt)
|
||||||
|
{
|
||||||
|
return utoa(buf, fmt.val, fmt.radix, fmt.num_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE bool from_chars(csubstr s, fmt::overflow_checked_<T> wrapper)
|
||||||
|
{
|
||||||
|
if(C4_LIKELY(!overflows<T>(s)))
|
||||||
|
return atox(s, wrapper.val);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// formatting real types
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct real_
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
int precision;
|
||||||
|
RealFormat_e fmt;
|
||||||
|
real_(T v, int prec=-1, RealFormat_e f=FTOA_FLOAT) : val(v), precision(prec), fmt(f) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
real_<T> real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT)
|
||||||
|
{
|
||||||
|
return real_<T>(val, precision, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
inline size_t to_chars(substr buf, fmt::real_< float> fmt) { return ftoa(buf, fmt.val, fmt.precision, fmt.fmt); }
|
||||||
|
inline size_t to_chars(substr buf, fmt::real_<double> fmt) { return dtoa(buf, fmt.val, fmt.precision, fmt.fmt); }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// writing raw binary data
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
/** @see blob_ */
|
||||||
|
template<class T>
|
||||||
|
struct raw_wrapper_ : public blob_<T>
|
||||||
|
{
|
||||||
|
size_t alignment;
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE raw_wrapper_(blob_<T> data, size_t alignment_) noexcept
|
||||||
|
:
|
||||||
|
blob_<T>(data),
|
||||||
|
alignment(alignment_)
|
||||||
|
{
|
||||||
|
C4_ASSERT_MSG(alignment > 0 && (alignment & (alignment - 1)) == 0, "alignment must be a power of two");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using const_raw_wrapper = raw_wrapper_<cbyte>;
|
||||||
|
using raw_wrapper = raw_wrapper_<byte>;
|
||||||
|
|
||||||
|
/** mark a variable to be written in raw binary format, using memcpy
|
||||||
|
* @see blob_ */
|
||||||
|
inline const_raw_wrapper craw(cblob data, size_t alignment=alignof(max_align_t))
|
||||||
|
{
|
||||||
|
return const_raw_wrapper(data, alignment);
|
||||||
|
}
|
||||||
|
/** mark a variable to be written in raw binary format, using memcpy
|
||||||
|
* @see blob_ */
|
||||||
|
inline const_raw_wrapper raw(cblob data, size_t alignment=alignof(max_align_t))
|
||||||
|
{
|
||||||
|
return const_raw_wrapper(data, alignment);
|
||||||
|
}
|
||||||
|
/** mark a variable to be written in raw binary format, using memcpy
|
||||||
|
* @see blob_ */
|
||||||
|
template<class T>
|
||||||
|
inline const_raw_wrapper craw(T const& C4_RESTRICT data, size_t alignment=alignof(T))
|
||||||
|
{
|
||||||
|
return const_raw_wrapper(cblob(data), alignment);
|
||||||
|
}
|
||||||
|
/** mark a variable to be written in raw binary format, using memcpy
|
||||||
|
* @see blob_ */
|
||||||
|
template<class T>
|
||||||
|
inline const_raw_wrapper raw(T const& C4_RESTRICT data, size_t alignment=alignof(T))
|
||||||
|
{
|
||||||
|
return const_raw_wrapper(cblob(data), alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** mark a variable to be read in raw binary format, using memcpy */
|
||||||
|
inline raw_wrapper raw(blob data, size_t alignment=alignof(max_align_t))
|
||||||
|
{
|
||||||
|
return raw_wrapper(data, alignment);
|
||||||
|
}
|
||||||
|
/** mark a variable to be read in raw binary format, using memcpy */
|
||||||
|
template<class T>
|
||||||
|
inline raw_wrapper raw(T & C4_RESTRICT data, size_t alignment=alignof(T))
|
||||||
|
{
|
||||||
|
return raw_wrapper(blob(data), alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
|
||||||
|
/** write a variable in raw binary format, using memcpy */
|
||||||
|
C4CORE_EXPORT size_t to_chars(substr buf, fmt::const_raw_wrapper r);
|
||||||
|
|
||||||
|
/** read a variable in raw binary format, using memcpy */
|
||||||
|
C4CORE_EXPORT bool from_chars(csubstr buf, fmt::raw_wrapper *r);
|
||||||
|
/** read a variable in raw binary format, using memcpy */
|
||||||
|
inline bool from_chars(csubstr buf, fmt::raw_wrapper r)
|
||||||
|
{
|
||||||
|
return from_chars(buf, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** read a variable in raw binary format, using memcpy */
|
||||||
|
inline size_t from_chars_first(csubstr buf, fmt::raw_wrapper *r)
|
||||||
|
{
|
||||||
|
return from_chars(buf, r);
|
||||||
|
}
|
||||||
|
/** read a variable in raw binary format, using memcpy */
|
||||||
|
inline size_t from_chars_first(csubstr buf, fmt::raw_wrapper r)
|
||||||
|
{
|
||||||
|
return from_chars(buf, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// formatting aligned to left/right
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct left_
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
size_t width;
|
||||||
|
char pad;
|
||||||
|
left_(T v, size_t w, char p) : val(v), width(w), pad(p) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct right_
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
size_t width;
|
||||||
|
char pad;
|
||||||
|
right_(T v, size_t w, char p) : val(v), width(w), pad(p) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** mark an argument to be aligned left */
|
||||||
|
template<class T>
|
||||||
|
left_<T> left(T val, size_t width, char padchar=' ')
|
||||||
|
{
|
||||||
|
return left_<T>(val, width, padchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** mark an argument to be aligned right */
|
||||||
|
template<class T>
|
||||||
|
right_<T> right(T val, size_t width, char padchar=' ')
|
||||||
|
{
|
||||||
|
return right_<T>(val, width, padchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
size_t to_chars(substr buf, fmt::left_<T> const& C4_RESTRICT align)
|
||||||
|
{
|
||||||
|
size_t ret = to_chars(buf, align.val);
|
||||||
|
if(ret >= buf.len || ret >= align.width)
|
||||||
|
return ret > align.width ? ret : align.width;
|
||||||
|
buf.first(align.width).sub(ret).fill(align.pad);
|
||||||
|
to_chars(buf, align.val);
|
||||||
|
return align.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
size_t to_chars(substr buf, fmt::right_<T> const& C4_RESTRICT align)
|
||||||
|
{
|
||||||
|
size_t ret = to_chars(buf, align.val);
|
||||||
|
if(ret >= buf.len || ret >= align.width)
|
||||||
|
return ret > align.width ? ret : align.width;
|
||||||
|
size_t rem = static_cast<size_t>(align.width - ret);
|
||||||
|
buf.first(rem).fill(align.pad);
|
||||||
|
to_chars(buf.sub(rem), align.val);
|
||||||
|
return align.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminates the variadic recursion
|
||||||
|
inline size_t cat(substr /*buf*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
/** serialize the arguments, concatenating them to the given fixed-size buffer.
|
||||||
|
* The buffer size is strictly respected: no writes will occur beyond its end.
|
||||||
|
* @return the number of characters needed to write all the arguments into the buffer.
|
||||||
|
* @see c4::catrs() if instead of a fixed-size buffer, a resizeable container is desired
|
||||||
|
* @see c4::uncat() for the inverse function
|
||||||
|
* @see c4::catsep() if a separator between each argument is to be used
|
||||||
|
* @see c4::format() if a format string is desired */
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
size_t cat(substr buf, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t num = to_chars(buf, a);
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num += cat(buf, more...);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::cat() but return a substr instead of a size */
|
||||||
|
template<class... Args>
|
||||||
|
substr cat_sub(substr buf, Args && ...args)
|
||||||
|
{
|
||||||
|
size_t sz = cat(buf, std::forward<Args>(args)...);
|
||||||
|
C4_CHECK(sz <= buf.len);
|
||||||
|
return {buf.str, sz <= buf.len ? sz : buf.len};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminates the variadic recursion
|
||||||
|
inline size_t uncat(csubstr /*buf*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
/** deserialize the arguments from the given buffer.
|
||||||
|
*
|
||||||
|
* @return the number of characters read from the buffer, or csubstr::npos
|
||||||
|
* if a conversion was not successful.
|
||||||
|
* @see c4::cat(). c4::uncat() is the inverse of c4::cat(). */
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
size_t uncat(csubstr buf, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t out = from_chars_first(buf, &a);
|
||||||
|
if(C4_UNLIKELY(out == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
buf = buf.len >= out ? buf.sub(out) : substr{};
|
||||||
|
size_t num = uncat(buf, more...);
|
||||||
|
if(C4_UNLIKELY(num == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
return out + num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Sep>
|
||||||
|
C4_ALWAYS_INLINE size_t catsep_more(substr /*buf*/, Sep const& C4_RESTRICT /*sep*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Sep, class Arg, class... Args>
|
||||||
|
size_t catsep_more(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t ret = to_chars(buf, sep);
|
||||||
|
size_t num = ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = to_chars(buf, a);
|
||||||
|
num += ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = catsep_more(buf, sep, more...);
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Sep>
|
||||||
|
inline size_t uncatsep_more(csubstr /*buf*/, Sep & /*sep*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Sep, class Arg, class... Args>
|
||||||
|
size_t uncatsep_more(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t ret = from_chars_first(buf, &sep);
|
||||||
|
size_t num = ret;
|
||||||
|
if(C4_UNLIKELY(ret == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = from_chars_first(buf, &a);
|
||||||
|
if(C4_UNLIKELY(ret == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = uncatsep_more(buf, sep, more...);
|
||||||
|
if(C4_UNLIKELY(ret == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
template<class Sep>
|
||||||
|
size_t catsep(substr /*buf*/, Sep const& C4_RESTRICT /*sep*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
/** serialize the arguments, concatenating them to the given fixed-size
|
||||||
|
* buffer, using a separator between each argument.
|
||||||
|
* The buffer size is strictly respected: no writes will occur beyond its end.
|
||||||
|
* @return the number of characters needed to write all the arguments into the buffer.
|
||||||
|
* @see c4::catseprs() if instead of a fixed-size buffer, a resizeable container is desired
|
||||||
|
* @see c4::uncatsep() for the inverse function (ie, reading instead of writing)
|
||||||
|
* @see c4::cat() if no separator is needed
|
||||||
|
* @see c4::format() if a format string is desired */
|
||||||
|
template<class Sep, class Arg, class... Args>
|
||||||
|
size_t catsep(substr buf, Sep const& C4_RESTRICT sep, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t num = to_chars(buf, a);
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num += detail::catsep_more(buf, sep, more...);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::catsep() but return a substr instead of a size
|
||||||
|
* @see c4::catsep(). c4::uncatsep() is the inverse of c4::catsep(). */
|
||||||
|
template<class... Args>
|
||||||
|
substr catsep_sub(substr buf, Args && ...args)
|
||||||
|
{
|
||||||
|
size_t sz = catsep(buf, std::forward<Args>(args)...);
|
||||||
|
C4_CHECK(sz <= buf.len);
|
||||||
|
return {buf.str, sz <= buf.len ? sz : buf.len};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** deserialize the arguments from the given buffer, using a separator.
|
||||||
|
*
|
||||||
|
* @return the number of characters read from the buffer, or csubstr::npos
|
||||||
|
* if a conversion was not successful
|
||||||
|
* @see c4::catsep(). c4::uncatsep() is the inverse of c4::catsep(). */
|
||||||
|
template<class Sep, class Arg, class... Args>
|
||||||
|
size_t uncatsep(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t ret = from_chars_first(buf, &a), num = ret;
|
||||||
|
if(C4_UNLIKELY(ret == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = detail::uncatsep_more(buf, sep, more...);
|
||||||
|
if(C4_UNLIKELY(ret == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminates the variadic recursion
|
||||||
|
inline size_t format(substr buf, csubstr fmt)
|
||||||
|
{
|
||||||
|
return to_chars(buf, fmt);
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
/** using a format string, serialize the arguments into the given
|
||||||
|
* fixed-size buffer.
|
||||||
|
* The buffer size is strictly respected: no writes will occur beyond its end.
|
||||||
|
* In the format string, each argument is marked with a compact
|
||||||
|
* curly-bracket pair: {}. Arguments beyond the last curly bracket pair
|
||||||
|
* are silently ignored. For example:
|
||||||
|
* @code{.cpp}
|
||||||
|
* c4::format(buf, "the {} drank {} {}", "partier", 5, "beers"); // the partier drank 5 beers
|
||||||
|
* c4::format(buf, "the {} drank {} {}", "programmer", 6, "coffees"); // the programmer drank 6 coffees
|
||||||
|
* @endcode
|
||||||
|
* @return the number of characters needed to write into the buffer.
|
||||||
|
* @see c4::formatrs() if instead of a fixed-size buffer, a resizeable container is desired
|
||||||
|
* @see c4::unformat() for the inverse function
|
||||||
|
* @see c4::cat() if no format or separator is needed
|
||||||
|
* @see c4::catsep() if no format is needed, but a separator must be used */
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
size_t format(substr buf, csubstr fmt, Arg const& C4_RESTRICT a, Args const& C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
size_t pos = fmt.find("{}"); // @todo use _find_fmt()
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
return to_chars(buf, fmt);
|
||||||
|
size_t num = to_chars(buf, fmt.sub(0, pos));
|
||||||
|
size_t out = num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = to_chars(buf, a);
|
||||||
|
out += num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = format(buf, fmt.sub(pos + 2), more...);
|
||||||
|
out += num;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::format() but return a substr instead of a size
|
||||||
|
* @see c4::format()
|
||||||
|
* @see c4::catsep(). uncatsep() is the inverse of catsep(). */
|
||||||
|
template<class... Args>
|
||||||
|
substr format_sub(substr buf, csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
size_t sz = c4::format(buf, fmt, args...);
|
||||||
|
C4_CHECK(sz <= buf.len);
|
||||||
|
return {buf.str, sz <= buf.len ? sz : buf.len};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
// terminates the variadic recursion
|
||||||
|
inline size_t unformat(csubstr /*buf*/, csubstr fmt)
|
||||||
|
{
|
||||||
|
return fmt.len;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
|
||||||
|
/** using a format string, deserialize the arguments from the given
|
||||||
|
* buffer.
|
||||||
|
* @return the number of characters read from the buffer, or npos if a conversion failed.
|
||||||
|
* @see c4::format(). c4::unformat() is the inverse function to format(). */
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
size_t unformat(csubstr buf, csubstr fmt, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
|
||||||
|
{
|
||||||
|
const size_t pos = fmt.find("{}");
|
||||||
|
if(C4_UNLIKELY(pos == csubstr::npos))
|
||||||
|
return unformat(buf, fmt);
|
||||||
|
size_t num = pos;
|
||||||
|
size_t out = num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = from_chars_first(buf, &a);
|
||||||
|
if(C4_UNLIKELY(num == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
out += num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = unformat(buf, fmt.sub(pos + 2), more...);
|
||||||
|
if(C4_UNLIKELY(num == csubstr::npos))
|
||||||
|
return csubstr::npos;
|
||||||
|
out += num;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** like c4::cat(), but receives a container, and resizes it as needed to contain
|
||||||
|
* the result. The container is overwritten. To append to it, use the append
|
||||||
|
* overload.
|
||||||
|
* @see c4::cat() */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline void catrs(CharOwningContainer * C4_RESTRICT cont, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont);
|
||||||
|
size_t ret = cat(buf, args...);
|
||||||
|
cont->resize(ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::cat(), but creates and returns a new container sized as needed to contain
|
||||||
|
* the result.
|
||||||
|
* @see c4::cat() */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline CharOwningContainer catrs(Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
CharOwningContainer cont;
|
||||||
|
catrs(&cont, args...);
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::cat(), but receives a container, and appends to it instead of
|
||||||
|
* overwriting it. The container is resized as needed to contain the result.
|
||||||
|
* @return the region newly appended to the original container
|
||||||
|
* @see c4::cat()
|
||||||
|
* @see c4::catrs() */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline csubstr catrs_append(CharOwningContainer * C4_RESTRICT cont, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
const size_t pos = cont->size();
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont).sub(pos);
|
||||||
|
size_t ret = cat(buf, args...);
|
||||||
|
cont->resize(pos + ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
return to_csubstr(*cont).range(pos, cont->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** like c4::catsep(), but receives a container, and resizes it as needed to contain the result.
|
||||||
|
* The container is overwritten. To append to the container use the append overload.
|
||||||
|
* @see c4::catsep() */
|
||||||
|
template<class CharOwningContainer, class Sep, class... Args>
|
||||||
|
inline void catseprs(CharOwningContainer * C4_RESTRICT cont, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont);
|
||||||
|
size_t ret = catsep(buf, sep, args...);
|
||||||
|
cont->resize(ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::catsep(), but create a new container with the result.
|
||||||
|
* @return the requested container */
|
||||||
|
template<class CharOwningContainer, class Sep, class... Args>
|
||||||
|
inline CharOwningContainer catseprs(Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
CharOwningContainer cont;
|
||||||
|
catseprs(&cont, sep, args...);
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** like catsep(), but receives a container, and appends the arguments, resizing the
|
||||||
|
* container as needed to contain the result. The buffer is appended to.
|
||||||
|
* @return a csubstr of the appended part
|
||||||
|
* @ingroup formatting_functions */
|
||||||
|
template<class CharOwningContainer, class Sep, class... Args>
|
||||||
|
inline csubstr catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep const& C4_RESTRICT sep, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
const size_t pos = cont->size();
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont).sub(pos);
|
||||||
|
size_t ret = catsep(buf, sep, args...);
|
||||||
|
cont->resize(pos + ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
return to_csubstr(*cont).range(pos, cont->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** like c4::format(), but receives a container, and resizes it as needed
|
||||||
|
* to contain the result. The container is overwritten. To append to
|
||||||
|
* the container use the append overload.
|
||||||
|
* @see c4::format() */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline void formatrs(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont);
|
||||||
|
size_t ret = format(buf, fmt, args...);
|
||||||
|
cont->resize(ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like c4::format(), but create a new container with the result.
|
||||||
|
* @return the requested container */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline CharOwningContainer formatrs(csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
CharOwningContainer cont;
|
||||||
|
formatrs(&cont, fmt, args...);
|
||||||
|
return cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** like format(), but receives a container, and appends the
|
||||||
|
* arguments, resizing the container as needed to contain the
|
||||||
|
* result. The buffer is appended to.
|
||||||
|
* @return the region newly appended to the original container
|
||||||
|
* @ingroup formatting_functions */
|
||||||
|
template<class CharOwningContainer, class... Args>
|
||||||
|
inline csubstr formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args const& C4_RESTRICT ...args)
|
||||||
|
{
|
||||||
|
const size_t pos = cont->size();
|
||||||
|
retry:
|
||||||
|
substr buf = to_substr(*cont).sub(pos);
|
||||||
|
size_t ret = format(buf, fmt, args...);
|
||||||
|
cont->resize(pos + ret);
|
||||||
|
if(ret > buf.len)
|
||||||
|
goto retry;
|
||||||
|
return to_csubstr(*cont).range(pos, cont->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_FORMAT_HPP_ */
|
306
dep/rapidyaml/include/c4/language.hpp
Normal file
306
dep/rapidyaml/include/c4/language.hpp
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
#ifndef _C4_LANGUAGE_HPP_
|
||||||
|
#define _C4_LANGUAGE_HPP_
|
||||||
|
|
||||||
|
/** @file language.hpp Provides language standard information macros and
|
||||||
|
* compiler agnostic utility macros: namespace facilities, function attributes,
|
||||||
|
* variable attributes, etc.
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
#include "c4/preprocessor.hpp"
|
||||||
|
#include "c4/compiler.hpp"
|
||||||
|
|
||||||
|
/* Detect C++ standard.
|
||||||
|
* @see http://stackoverflow.com/a/7132549/5875572 */
|
||||||
|
#ifndef C4_CPP
|
||||||
|
# if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# if _MSC_VER >= 1910 // >VS2015: VS2017, VS2019
|
||||||
|
# if (!defined(_MSVC_LANG))
|
||||||
|
# error _MSVC not defined
|
||||||
|
# endif
|
||||||
|
# if _MSVC_LANG >= 201705L
|
||||||
|
# define C4_CPP 20
|
||||||
|
# define C4_CPP20
|
||||||
|
# elif _MSVC_LANG == 201703L
|
||||||
|
# define C4_CPP 17
|
||||||
|
# define C4_CPP17
|
||||||
|
# elif _MSVC_LANG >= 201402L
|
||||||
|
# define C4_CPP 14
|
||||||
|
# define C4_CPP14
|
||||||
|
# elif _MSVC_LANG >= 201103L
|
||||||
|
# define C4_CPP 11
|
||||||
|
# define C4_CPP11
|
||||||
|
# else
|
||||||
|
# error C++ lesser than C++11 not supported
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if _MSC_VER == 1900
|
||||||
|
# define C4_CPP 14 // VS2015 is c++14 https://devblogs.microsoft.com/cppblog/c111417-features-in-vs-2015-rtm/
|
||||||
|
# define C4_CPP14
|
||||||
|
# elif _MSC_VER == 1800 // VS2013
|
||||||
|
# define C4_CPP 11
|
||||||
|
# define C4_CPP11
|
||||||
|
# else
|
||||||
|
# error C++ lesser than C++11 not supported
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# elif defined(__INTEL_COMPILER) // https://software.intel.com/en-us/node/524490
|
||||||
|
# ifdef __INTEL_CXX20_MODE__ // not sure about this
|
||||||
|
# define C4_CPP 20
|
||||||
|
# define C4_CPP20
|
||||||
|
# elif defined __INTEL_CXX17_MODE__ // not sure about this
|
||||||
|
# define C4_CPP 17
|
||||||
|
# define C4_CPP17
|
||||||
|
# elif defined __INTEL_CXX14_MODE__ // not sure about this
|
||||||
|
# define C4_CPP 14
|
||||||
|
# define C4_CPP14
|
||||||
|
# elif defined __INTEL_CXX11_MODE__
|
||||||
|
# define C4_CPP 11
|
||||||
|
# define C4_CPP11
|
||||||
|
# else
|
||||||
|
# error C++ lesser than C++11 not supported
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# ifndef __cplusplus
|
||||||
|
# error __cplusplus is not defined?
|
||||||
|
# endif
|
||||||
|
# if __cplusplus == 1
|
||||||
|
# error cannot handle __cplusplus==1
|
||||||
|
# elif __cplusplus >= 201709L
|
||||||
|
# define C4_CPP 20
|
||||||
|
# define C4_CPP20
|
||||||
|
# elif __cplusplus >= 201703L
|
||||||
|
# define C4_CPP 17
|
||||||
|
# define C4_CPP17
|
||||||
|
# elif __cplusplus >= 201402L
|
||||||
|
# define C4_CPP 14
|
||||||
|
# define C4_CPP14
|
||||||
|
# elif __cplusplus >= 201103L
|
||||||
|
# define C4_CPP 11
|
||||||
|
# define C4_CPP11
|
||||||
|
# elif __cplusplus >= 199711L
|
||||||
|
# error C++ lesser than C++11 not supported
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef C4_CPP == 20
|
||||||
|
# define C4_CPP20
|
||||||
|
# elif C4_CPP == 17
|
||||||
|
# define C4_CPP17
|
||||||
|
# elif C4_CPP == 14
|
||||||
|
# define C4_CPP14
|
||||||
|
# elif C4_CPP == 11
|
||||||
|
# define C4_CPP11
|
||||||
|
# elif C4_CPP == 98
|
||||||
|
# define C4_CPP98
|
||||||
|
# error C++ lesser than C++11 not supported
|
||||||
|
# else
|
||||||
|
# error C4_CPP must be one of 20, 17, 14, 11, 98
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef C4_CPP20
|
||||||
|
# define C4_CPP17
|
||||||
|
# define C4_CPP14
|
||||||
|
# define C4_CPP11
|
||||||
|
#elif defined(C4_CPP17)
|
||||||
|
# define C4_CPP14
|
||||||
|
# define C4_CPP11
|
||||||
|
#elif defined(C4_CPP14)
|
||||||
|
# define C4_CPP11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** lifted from this answer: http://stackoverflow.com/a/20170989/5875572 */
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# if _MSC_VER < 1900
|
||||||
|
# define C4_CONSTEXPR11
|
||||||
|
# define C4_CONSTEXPR14
|
||||||
|
# elif _MSC_VER < 2000
|
||||||
|
# define C4_CONSTEXPR11 constexpr
|
||||||
|
# define C4_CONSTEXPR14
|
||||||
|
# else
|
||||||
|
# define C4_CONSTEXPR11 constexpr
|
||||||
|
# define C4_CONSTEXPR14 constexpr
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if __cplusplus < 201103
|
||||||
|
# define C4_CONSTEXPR11
|
||||||
|
# define C4_CONSTEXPR14
|
||||||
|
# elif __cplusplus == 201103
|
||||||
|
# define C4_CONSTEXPR11 constexpr
|
||||||
|
# define C4_CONSTEXPR14
|
||||||
|
# else
|
||||||
|
# define C4_CONSTEXPR11 constexpr
|
||||||
|
# define C4_CONSTEXPR14 constexpr
|
||||||
|
# endif
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
#if C4_CPP < 17
|
||||||
|
#define C4_IF_CONSTEXPR
|
||||||
|
#define C4_INLINE_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
#define C4_IF_CONSTEXPR constexpr
|
||||||
|
#define C4_INLINE_CONSTEXPR inline constexpr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# if (defined(_CPPUNWIND) && (_CPPUNWIND == 1))
|
||||||
|
# define C4_EXCEPTIONS
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
|
||||||
|
# define C4_EXCEPTIONS
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef C4_EXCEPTIONS
|
||||||
|
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) exc_code
|
||||||
|
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { exc_code } while(0)
|
||||||
|
#else
|
||||||
|
# define C4_IF_EXCEPTIONS_(exc_code, setjmp_code) setjmp_code
|
||||||
|
# define C4_IF_EXCEPTIONS(exc_code, setjmp_code) do { setjmp_code } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# if defined(_CPPRTTI)
|
||||||
|
# define C4_RTTI
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if defined(__GXX_RTTI)
|
||||||
|
# define C4_RTTI
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef C4_RTTI
|
||||||
|
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_rtti
|
||||||
|
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_rtti } while(0)
|
||||||
|
#else
|
||||||
|
# define C4_IF_RTTI_(code_rtti, code_no_rtti) code_no_rtti
|
||||||
|
# define C4_IF_RTTI(code_rtti, code_no_rtti) do { code_no_rtti } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
#define _C4_BEGIN_NAMESPACE(ns) namespace ns {
|
||||||
|
#define _C4_END_NAMESPACE(ns) }
|
||||||
|
|
||||||
|
// MSVC cant handle the C4_FOR_EACH macro... need to fix this
|
||||||
|
//#define C4_BEGIN_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_BEGIN_NAMESPACE, , __VA_ARGS__)
|
||||||
|
//#define C4_END_NAMESPACE(...) C4_FOR_EACH_SEP(_C4_END_NAMESPACE, , __VA_ARGS__)
|
||||||
|
#define C4_BEGIN_NAMESPACE(ns) namespace ns {
|
||||||
|
#define C4_END_NAMESPACE(ns) }
|
||||||
|
|
||||||
|
#define C4_BEGIN_HIDDEN_NAMESPACE namespace /*hidden*/ {
|
||||||
|
#define C4_END_HIDDEN_NAMESPACE } /* namespace hidden */
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef C4_API
|
||||||
|
# if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# if defined(C4_EXPORT)
|
||||||
|
# define C4_API __declspec(dllexport)
|
||||||
|
# elif defined(C4_IMPORT)
|
||||||
|
# define C4_API __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define C4_API
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define C4_API
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# define C4_RESTRICT __restrict
|
||||||
|
# define C4_RESTRICT_FN __declspec(restrict)
|
||||||
|
# define C4_NO_INLINE __declspec(noinline)
|
||||||
|
# define C4_ALWAYS_INLINE inline __forceinline
|
||||||
|
/** these are not available in VS AFAIK */
|
||||||
|
# define C4_CONST
|
||||||
|
# define C4_PURE
|
||||||
|
# define C4_FLATTEN
|
||||||
|
# define C4_HOT /** @todo */
|
||||||
|
# define C4_COLD /** @todo */
|
||||||
|
# define C4_EXPECT(x, y) x /** @todo */
|
||||||
|
# define C4_LIKELY(x) x /** @todo */
|
||||||
|
# define C4_UNLIKELY(x) x /** @todo */
|
||||||
|
# define C4_UNREACHABLE() /** @todo */
|
||||||
|
# define C4_ATTR_FORMAT(...) /** */
|
||||||
|
# define C4_NORETURN /** @todo */
|
||||||
|
#else
|
||||||
|
///< @todo assuming gcc-like compiler. check it is actually so.
|
||||||
|
/** for function attributes in GCC,
|
||||||
|
* @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes */
|
||||||
|
/** for __builtin functions in GCC,
|
||||||
|
* @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */
|
||||||
|
# define C4_RESTRICT __restrict__
|
||||||
|
# define C4_RESTRICT_FN __attribute__((restrict))
|
||||||
|
# define C4_NO_INLINE __attribute__((noinline))
|
||||||
|
# define C4_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||||
|
# define C4_CONST __attribute__((const))
|
||||||
|
# define C4_PURE __attribute__((pure))
|
||||||
|
/** force inlining of every callee function */
|
||||||
|
# define C4_FLATTEN __atribute__((flatten))
|
||||||
|
/** mark a function as hot, ie as having a visible impact in CPU time
|
||||||
|
* thus making it more likely to inline, etc
|
||||||
|
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
|
||||||
|
# define C4_HOT __attribute__((hot))
|
||||||
|
/** mark a function as cold, ie as NOT having a visible impact in CPU time
|
||||||
|
* @see http://stackoverflow.com/questions/15028990/semantics-of-gcc-hot-attribute */
|
||||||
|
# define C4_COLD __attribute__((cold))
|
||||||
|
# define C4_EXPECT(x, y) __builtin_expect(x, y) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
|
||||||
|
# define C4_LIKELY(x) __builtin_expect(x, 1)
|
||||||
|
# define C4_UNLIKELY(x) __builtin_expect(x, 0)
|
||||||
|
# define C4_UNREACHABLE() __builtin_unreachable()
|
||||||
|
# define C4_ATTR_FORMAT(...) //__attribute__((format (__VA_ARGS__))) ///< @see https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
|
||||||
|
# define C4_NORETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define C4_FUNC __FUNCTION__
|
||||||
|
# define C4_PRETTY_FUNC __FUNCSIG__
|
||||||
|
#else /// @todo assuming gcc-like compiler. check it is actually so.
|
||||||
|
# define C4_FUNC __FUNCTION__
|
||||||
|
# define C4_PRETTY_FUNC __PRETTY_FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** prevent compiler warnings about a specific var being unused */
|
||||||
|
#define C4_UNUSED(var) (void)var
|
||||||
|
|
||||||
|
#if C4_CPP >= 17
|
||||||
|
#define C4_STATIC_ASSERT(cond) static_assert(cond)
|
||||||
|
#else
|
||||||
|
#define C4_STATIC_ASSERT(cond) static_assert((cond), #cond)
|
||||||
|
#endif
|
||||||
|
#define C4_STATIC_ASSERT_MSG(cond, msg) static_assert((cond), #cond ": " msg)
|
||||||
|
|
||||||
|
/** @def C4_DONT_OPTIMIZE idea lifted from GoogleBenchmark.
|
||||||
|
* @see https://github.com/google/benchmark/blob/master/include/benchmark/benchmark_api.h */
|
||||||
|
namespace c4 {
|
||||||
|
namespace detail {
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define C4_DONT_OPTIMIZE(var) c4::detail::dont_optimize(var)
|
||||||
|
template< class T >
|
||||||
|
C4_ALWAYS_INLINE void dont_optimize(T const& value) { asm volatile("" : : "g"(value) : "memory"); }
|
||||||
|
#else
|
||||||
|
# define C4_DONT_OPTIMIZE(var) c4::detail::use_char_pointer(reinterpret_cast< const char* >(&var))
|
||||||
|
void use_char_pointer(char const volatile*);
|
||||||
|
#endif
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
/** @def C4_KEEP_EMPTY_LOOP prevent an empty loop from being optimized out.
|
||||||
|
* @see http://stackoverflow.com/a/7084193/5875572 */
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# define C4_KEEP_EMPTY_LOOP { char c; C4_DONT_OPTIMIZE(c); }
|
||||||
|
#else
|
||||||
|
# define C4_KEEP_EMPTY_LOOP { asm(""); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @def C4_VA_LIST_REUSE_MUST_COPY
|
||||||
|
* @todo <jpmag> I strongly suspect that this is actually only in UNIX platforms. revisit this. */
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# define C4_VA_LIST_REUSE_MUST_COPY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_LANGUAGE_HPP_ */
|
778
dep/rapidyaml/include/c4/memory_util.hpp
Normal file
778
dep/rapidyaml/include/c4/memory_util.hpp
Normal file
|
@ -0,0 +1,778 @@
|
||||||
|
#ifndef _C4_MEMORY_UTIL_HPP_
|
||||||
|
#define _C4_MEMORY_UTIL_HPP_
|
||||||
|
|
||||||
|
#include "c4/config.hpp"
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
#include "c4/compiler.hpp"
|
||||||
|
#include "c4/cpu.hpp"
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && __GNUC__ >= 10) || defined(__has_builtin)
|
||||||
|
#define _C4_USE_LSB_INTRINSIC(which) __has_builtin(which)
|
||||||
|
#define _C4_USE_MSB_INTRINSIC(which) __has_builtin(which)
|
||||||
|
#elif defined(C4_MSVC)
|
||||||
|
#define _C4_USE_LSB_INTRINSIC(which) true
|
||||||
|
#define _C4_USE_MSB_INTRINSIC(which) true
|
||||||
|
#else
|
||||||
|
// let's try our luck
|
||||||
|
#define _C4_USE_LSB_INTRINSIC(which) true
|
||||||
|
#define _C4_USE_MSB_INTRINSIC(which) true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** @file memory_util.hpp Some memory utilities. */
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
/** set the given memory to zero */
|
||||||
|
C4_ALWAYS_INLINE void mem_zero(void* mem, size_t num_bytes)
|
||||||
|
{
|
||||||
|
memset(mem, 0, num_bytes);
|
||||||
|
}
|
||||||
|
/** set the given memory to zero */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE void mem_zero(T* mem, size_t num_elms)
|
||||||
|
{
|
||||||
|
memset(mem, 0, sizeof(T) * num_elms);
|
||||||
|
}
|
||||||
|
/** set the given memory to zero */
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE void mem_zero(T* mem)
|
||||||
|
{
|
||||||
|
memset(mem, 0, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONST bool mem_overlaps(void const* a, void const* b, size_t sza, size_t szb)
|
||||||
|
{
|
||||||
|
// thanks @timwynants
|
||||||
|
return (((const char*)b + szb) > a && b < ((const char*)a+sza));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times);
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
C4_ALWAYS_INLINE C4_CONST bool is_aligned(T *ptr, uintptr_t alignment=alignof(T))
|
||||||
|
{
|
||||||
|
return (uintptr_t(ptr) & (alignment - uintptr_t(1))) == uintptr_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// least significant bit
|
||||||
|
|
||||||
|
/** @name msb Compute the least significant bit
|
||||||
|
* @note the input value must be nonzero
|
||||||
|
* @note the input type must be unsigned
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
// https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
|
||||||
|
#define _c4_lsb_fallback \
|
||||||
|
unsigned c = 0; \
|
||||||
|
v = (v ^ (v - 1)) >> 1; /* Set v's trailing 0s to 1s and zero rest */ \
|
||||||
|
for(; v; ++c) \
|
||||||
|
v >>= 1; \
|
||||||
|
return (unsigned) c
|
||||||
|
|
||||||
|
// u8
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto lsb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
|
||||||
|
// upcast to use the intrinsic, it's cheaper.
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanForward(&bit, (unsigned long)v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return (unsigned)__builtin_ctz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u16
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto lsb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
|
||||||
|
// upcast to use the intrinsic, it's cheaper.
|
||||||
|
// Then remember that the upcast makes it to 31bits
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanForward(&bit, (unsigned long)v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return (unsigned)__builtin_ctz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u32
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto lsb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanForward(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return (unsigned)__builtin_ctz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u64 in 64bits
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto lsb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzl)
|
||||||
|
#if defined(C4_MSVC)
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanForward64(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return (unsigned)__builtin_ctzl((unsigned long)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u64 in 32bits
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto lsb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzll)
|
||||||
|
#if defined(C4_MSVC)
|
||||||
|
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanForward64(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return (unsigned)__builtin_ctzll((unsigned long long)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_lsb_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _c4_lsb_fallback
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<class I, I val, unsigned num_bits, bool finished> struct _lsb11;
|
||||||
|
template<class I, I val, unsigned num_bits>
|
||||||
|
struct _lsb11<I, val, num_bits, false>
|
||||||
|
{
|
||||||
|
enum : unsigned { num = _lsb11<I, (val>>1), num_bits+I(1), (((val>>1)&I(1))!=I(0))>::num };
|
||||||
|
};
|
||||||
|
template<class I, I val, unsigned num_bits>
|
||||||
|
struct _lsb11<I, val, num_bits, true>
|
||||||
|
{
|
||||||
|
enum : unsigned { num = num_bits };
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
/** TMP version of lsb(); this needs to be implemented with template
|
||||||
|
* meta-programming because C++11 cannot use a constexpr function with
|
||||||
|
* local variables
|
||||||
|
* @see lsb */
|
||||||
|
template<class I, I number>
|
||||||
|
struct lsb11
|
||||||
|
{
|
||||||
|
static_assert(number != 0, "lsb: number must be nonzero");
|
||||||
|
enum : unsigned { value = detail::_lsb11<I, number, 0, ((number&I(1))!=I(0))>::num};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// most significant bit
|
||||||
|
|
||||||
|
|
||||||
|
/** @name msb Compute the most significant bit
|
||||||
|
* @note the input value must be nonzero
|
||||||
|
* @note the input type must be unsigned
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
|
||||||
|
#define _c4_msb8_fallback \
|
||||||
|
unsigned n = 0; \
|
||||||
|
if(v & I(0xf0)) v >>= 4, n |= I(4); \
|
||||||
|
if(v & I(0x0c)) v >>= 2, n |= I(2); \
|
||||||
|
if(v & I(0x02)) v >>= 1, n |= I(1); \
|
||||||
|
return n
|
||||||
|
|
||||||
|
#define _c4_msb16_fallback \
|
||||||
|
unsigned n = 0; \
|
||||||
|
if(v & I(0xff00)) v >>= 8, n |= I(8); \
|
||||||
|
if(v & I(0x00f0)) v >>= 4, n |= I(4); \
|
||||||
|
if(v & I(0x000c)) v >>= 2, n |= I(2); \
|
||||||
|
if(v & I(0x0002)) v >>= 1, n |= I(1); \
|
||||||
|
return n
|
||||||
|
|
||||||
|
#define _c4_msb32_fallback \
|
||||||
|
unsigned n = 0; \
|
||||||
|
if(v & I(0xffff0000)) v >>= 16, n |= 16; \
|
||||||
|
if(v & I(0x0000ff00)) v >>= 8, n |= 8; \
|
||||||
|
if(v & I(0x000000f0)) v >>= 4, n |= 4; \
|
||||||
|
if(v & I(0x0000000c)) v >>= 2, n |= 2; \
|
||||||
|
if(v & I(0x00000002)) v >>= 1, n |= 1; \
|
||||||
|
return n
|
||||||
|
|
||||||
|
#define _c4_msb64_fallback \
|
||||||
|
unsigned n = 0; \
|
||||||
|
if(v & I(0xffffffff00000000)) v >>= 32, n |= I(32); \
|
||||||
|
if(v & I(0x00000000ffff0000)) v >>= 16, n |= I(16); \
|
||||||
|
if(v & I(0x000000000000ff00)) v >>= 8, n |= I(8); \
|
||||||
|
if(v & I(0x00000000000000f0)) v >>= 4, n |= I(4); \
|
||||||
|
if(v & I(0x000000000000000c)) v >>= 2, n |= I(2); \
|
||||||
|
if(v & I(0x0000000000000002)) v >>= 1, n |= I(1); \
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
// u8
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto msb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
|
||||||
|
// upcast to use the intrinsic, it's cheaper.
|
||||||
|
// Then remember that the upcast makes it to 31bits
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanReverse(&bit, (unsigned long)v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_msb8_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 31u - (unsigned)__builtin_clz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_msb8_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u16
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto msb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
|
||||||
|
// upcast to use the intrinsic, it's cheaper.
|
||||||
|
// Then remember that the upcast makes it to 31bits
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanReverse(&bit, (unsigned long)v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_msb16_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 31u - (unsigned)__builtin_clz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_msb16_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u32
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto msb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanReverse(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_msb32_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 31u - (unsigned)__builtin_clz((unsigned)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_msb32_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u64 in 64bits
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto msb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_MSB_INTRINSIC(__builtin_clzl)
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanReverse64(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_msb64_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 63u - (unsigned)__builtin_clzl((unsigned long)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_msb64_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// u64 in 32bits
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14
|
||||||
|
auto msb(I v) noexcept
|
||||||
|
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
|
||||||
|
C4_ASSERT(v != 0);
|
||||||
|
#if _C4_USE_MSB_INTRINSIC(__builtin_clzll)
|
||||||
|
#ifdef C4_MSVC
|
||||||
|
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
|
||||||
|
unsigned long bit;
|
||||||
|
_BitScanReverse64(&bit, v);
|
||||||
|
return bit;
|
||||||
|
#else
|
||||||
|
_c4_msb64_fallback;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 63u - (unsigned)__builtin_clzll((unsigned long long)v);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_c4_msb64_fallback;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _c4_msb8_fallback
|
||||||
|
#undef _c4_msb16_fallback
|
||||||
|
#undef _c4_msb32_fallback
|
||||||
|
#undef _c4_msb64_fallback
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<class I, I val, I num_bits, bool finished> struct _msb11;
|
||||||
|
template<class I, I val, I num_bits>
|
||||||
|
struct _msb11< I, val, num_bits, false>
|
||||||
|
{
|
||||||
|
enum : unsigned { num = _msb11<I, (val>>1), num_bits+I(1), ((val>>1)==I(0))>::num };
|
||||||
|
};
|
||||||
|
template<class I, I val, I num_bits>
|
||||||
|
struct _msb11<I, val, num_bits, true>
|
||||||
|
{
|
||||||
|
static_assert(val == 0, "bad implementation");
|
||||||
|
enum : unsigned { num = (unsigned)(num_bits-1) };
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
/** TMP version of msb(); this needs to be implemented with template
|
||||||
|
* meta-programming because C++11 cannot use a constexpr function with
|
||||||
|
* local variables
|
||||||
|
* @see msb */
|
||||||
|
template<class I, I number>
|
||||||
|
struct msb11
|
||||||
|
{
|
||||||
|
enum : unsigned { value = detail::_msb11<I, number, 0, (number==I(0))>::num };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#undef _C4_USE_LSB_INTRINSIC
|
||||||
|
#undef _C4_USE_MSB_INTRINSIC
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// there is an implicit conversion below; it happens when E or B are
|
||||||
|
// narrower than int, and thus any operation will upcast the result to
|
||||||
|
// int, and then downcast to assign
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wconversion")
|
||||||
|
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
if(exponent >= 0)
|
||||||
|
{
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= base;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exponent *= E(-1);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r /= base;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, B base, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
if(exponent >= 0)
|
||||||
|
{
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= base;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exponent *= E(-1);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r /= base;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, class Base, Base base, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
B bbase = B(base);
|
||||||
|
if(exponent >= 0)
|
||||||
|
{
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= bbase;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exponent *= E(-1);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r /= bbase;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= base;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, B base, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= base;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/** integer power; this function is constexpr-14 because of the local
|
||||||
|
* variables */
|
||||||
|
template<class B, class Base, Base base, class E>
|
||||||
|
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
|
||||||
|
{
|
||||||
|
C4_STATIC_ASSERT(std::is_integral<E>::value);
|
||||||
|
B r = B(1);
|
||||||
|
B bbase = B(base);
|
||||||
|
for(E e = 0; e < exponent; ++e)
|
||||||
|
r *= bbase;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** return a mask with all bits set [first_bit,last_bit[; this function
|
||||||
|
* is constexpr-14 because of the local variables */
|
||||||
|
template<class I>
|
||||||
|
C4_CONSTEXPR14 I contiguous_mask(I first_bit, I last_bit)
|
||||||
|
{
|
||||||
|
I r = 0;
|
||||||
|
for(I i = first_bit; i < last_bit; ++i)
|
||||||
|
{
|
||||||
|
r |= (I(1) << i);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class I, I val, I first, I last, bool finished>
|
||||||
|
struct _ctgmsk11;
|
||||||
|
|
||||||
|
template<class I, I val, I first, I last>
|
||||||
|
struct _ctgmsk11< I, val, first, last, true>
|
||||||
|
{
|
||||||
|
enum : I { value = _ctgmsk11<I, val|(I(1)<<first), first+I(1), last, (first+1!=last)>::value };
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class I, I val, I first, I last>
|
||||||
|
struct _ctgmsk11< I, val, first, last, false>
|
||||||
|
{
|
||||||
|
enum : I { value = val };
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
/** TMP version of contiguous_mask(); this needs to be implemented with template
|
||||||
|
* meta-programming because C++11 cannot use a constexpr function with
|
||||||
|
* local variables
|
||||||
|
* @see contiguous_mask */
|
||||||
|
template<class I, I first_bit, I last_bit>
|
||||||
|
struct contiguous_mask11
|
||||||
|
{
|
||||||
|
enum : I { value = detail::_ctgmsk11<I, I(0), first_bit, last_bit, (first_bit!=last_bit)>::value };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** use Empty Base Class Optimization to reduce the size of a pair of
|
||||||
|
* potentially empty types*/
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
typedef enum {
|
||||||
|
tpc_same,
|
||||||
|
tpc_same_empty,
|
||||||
|
tpc_both_empty,
|
||||||
|
tpc_first_empty,
|
||||||
|
tpc_second_empty,
|
||||||
|
tpc_general
|
||||||
|
} TightPairCase_e;
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
constexpr TightPairCase_e tpc_which_case()
|
||||||
|
{
|
||||||
|
return std::is_same<First, Second>::value ?
|
||||||
|
std::is_empty<First>::value ?
|
||||||
|
tpc_same_empty
|
||||||
|
:
|
||||||
|
tpc_same
|
||||||
|
:
|
||||||
|
std::is_empty<First>::value && std::is_empty<Second>::value ?
|
||||||
|
tpc_both_empty
|
||||||
|
:
|
||||||
|
std::is_empty<First>::value ?
|
||||||
|
tpc_first_empty
|
||||||
|
:
|
||||||
|
std::is_empty<Second>::value ?
|
||||||
|
tpc_second_empty
|
||||||
|
:
|
||||||
|
tpc_general
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class First, class Second, TightPairCase_e Case>
|
||||||
|
struct tight_pair
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
First m_first;
|
||||||
|
Second m_second;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : m_first(), m_second() {}
|
||||||
|
tight_pair(First const& f, Second const& s) : m_first(f), m_second(s) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
struct tight_pair<First, Second, tpc_same_empty> : public First
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<First, Second>::value, "bad implementation");
|
||||||
|
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : First() {}
|
||||||
|
tight_pair(First const& f, Second const& /*s*/) : First(f) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
struct tight_pair<First, Second, tpc_both_empty> : public First, public Second
|
||||||
|
{
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : First(), Second() {}
|
||||||
|
tight_pair(First const& f, Second const& s) : First(f), Second(s) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
struct tight_pair<First, Second, tpc_same> : public First
|
||||||
|
{
|
||||||
|
Second m_second;
|
||||||
|
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : First() {}
|
||||||
|
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
struct tight_pair<First, Second, tpc_first_empty> : public First
|
||||||
|
{
|
||||||
|
Second m_second;
|
||||||
|
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : First(), m_second() {}
|
||||||
|
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
struct tight_pair<First, Second, tpc_second_empty> : public Second
|
||||||
|
{
|
||||||
|
First m_first;
|
||||||
|
|
||||||
|
using first_type = First;
|
||||||
|
using second_type = Second;
|
||||||
|
|
||||||
|
tight_pair() : Second(), m_first() {}
|
||||||
|
tight_pair(First const& f, Second const& s) : Second(s), m_first(f) {}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
|
||||||
|
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<class First, class Second>
|
||||||
|
using tight_pair = detail::tight_pair<First, Second, detail::tpc_which_case<First,Second>()>;
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_MEMORY_UTIL_HPP_ */
|
46
dep/rapidyaml/include/c4/platform.hpp
Normal file
46
dep/rapidyaml/include/c4/platform.hpp
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef _C4_PLATFORM_HPP_
|
||||||
|
#define _C4_PLATFORM_HPP_
|
||||||
|
|
||||||
|
/** @file platform.hpp Provides platform information macros
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
// see also https://sourceforge.net/p/predef/wiki/OperatingSystems/
|
||||||
|
|
||||||
|
#if defined(_WIN64)
|
||||||
|
# define C4_WIN
|
||||||
|
# define C4_WIN64
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define C4_WIN
|
||||||
|
# define C4_WIN32
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# define C4_ANDROID
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# include "TargetConditionals.h"
|
||||||
|
# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||||
|
# define C4_IOS
|
||||||
|
# elif TARGET_OS_MAC || TARGET_OS_OSX
|
||||||
|
# define C4_MACOS
|
||||||
|
# else
|
||||||
|
# error "Unknown Apple platform"
|
||||||
|
# endif
|
||||||
|
#elif defined(__linux__) || defined(__linux)
|
||||||
|
# define C4_UNIX
|
||||||
|
# define C4_LINUX
|
||||||
|
#elif defined(__unix__) || defined(__unix)
|
||||||
|
# define C4_UNIX
|
||||||
|
#elif defined(__arm__) || defined(__aarch64__)
|
||||||
|
# define C4_ARM
|
||||||
|
#elif defined(__xtensa__) || defined(__XTENSA__)
|
||||||
|
# define C4_XTENSA
|
||||||
|
#elif defined(SWIG)
|
||||||
|
# define C4_SWIG
|
||||||
|
#else
|
||||||
|
# error "unknown platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__posix) || defined(C4_UNIX) || defined(C4_LINUX)
|
||||||
|
# define C4_POSIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _C4_PLATFORM_HPP_ */
|
123
dep/rapidyaml/include/c4/preprocessor.hpp
Normal file
123
dep/rapidyaml/include/c4/preprocessor.hpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#ifndef _C4_PREPROCESSOR_HPP_
|
||||||
|
#define _C4_PREPROCESSOR_HPP_
|
||||||
|
|
||||||
|
/** @file preprocessor.hpp Contains basic macros and preprocessor utilities.
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
/* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
|
||||||
|
* variadic macros is not portable, but works in clang, gcc, msvc, icc.
|
||||||
|
* clang requires switching off compiler warnings for pedantic mode.
|
||||||
|
* @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
/* GCC also issues a warning for zero-args calls to variadic macros.
|
||||||
|
* This warning is switched on with -pedantic and apparently there is no
|
||||||
|
* easy way to turn it off as with clang. But marking this as a system
|
||||||
|
* header works.
|
||||||
|
* @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
|
||||||
|
* @see http://stackoverflow.com/questions/35587137/ */
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define C4_WIDEN(str) L"" str
|
||||||
|
|
||||||
|
#define C4_COUNTOF(arr) (sizeof(arr)/sizeof((arr)[0]))
|
||||||
|
|
||||||
|
#define C4_EXPAND(arg) arg
|
||||||
|
|
||||||
|
/** useful in some macro calls with template arguments */
|
||||||
|
#define C4_COMMA ,
|
||||||
|
/** useful in some macro calls with template arguments
|
||||||
|
* @see C4_COMMA */
|
||||||
|
#define C4_COMMA_X C4_COMMA
|
||||||
|
|
||||||
|
/** expand and quote */
|
||||||
|
#define C4_XQUOTE(arg) _C4_XQUOTE(arg)
|
||||||
|
#define _C4_XQUOTE(arg) C4_QUOTE(arg)
|
||||||
|
#define C4_QUOTE(arg) #arg
|
||||||
|
|
||||||
|
/** expand and concatenate */
|
||||||
|
#define C4_XCAT(arg1, arg2) _C4_XCAT(arg1, arg2)
|
||||||
|
#define _C4_XCAT(arg1, arg2) C4_CAT(arg1, arg2)
|
||||||
|
#define C4_CAT(arg1, arg2) arg1##arg2
|
||||||
|
|
||||||
|
#define C4_VERSION_CAT(major, minor, patch) ((major)*10000 + (minor)*100 + (patch))
|
||||||
|
|
||||||
|
/** A preprocessor foreach. Spectacular trick taken from:
|
||||||
|
* http://stackoverflow.com/a/1872506/5875572
|
||||||
|
* The first argument is for a macro receiving a single argument,
|
||||||
|
* which will be called with every subsequent argument. There is
|
||||||
|
* currently a limit of 32 arguments, and at least 1 must be provided.
|
||||||
|
*
|
||||||
|
Example:
|
||||||
|
@code{.cpp}
|
||||||
|
struct Example {
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
int c;
|
||||||
|
};
|
||||||
|
// define a one-arg macro to be called
|
||||||
|
#define PRN_STRUCT_OFFSETS(field) PRN_STRUCT_OFFSETS_(Example, field)
|
||||||
|
#define PRN_STRUCT_OFFSETS_(structure, field) printf(C4_XQUOTE(structure) ":" C4_XQUOTE(field)" - offset=%zu\n", offsetof(structure, field));
|
||||||
|
|
||||||
|
// now call the macro for a, b and c
|
||||||
|
C4_FOR_EACH(PRN_STRUCT_OFFSETS, a, b, c);
|
||||||
|
@endcode */
|
||||||
|
#define C4_FOR_EACH(what, ...) C4_FOR_EACH_SEP(what, ;, __VA_ARGS__)
|
||||||
|
|
||||||
|
/** same as C4_FOR_EACH(), but use a custom separator between statements.
|
||||||
|
* If a comma is needed as the separator, use the C4_COMMA macro.
|
||||||
|
* @see C4_FOR_EACH
|
||||||
|
* @see C4_COMMA
|
||||||
|
*/
|
||||||
|
#define C4_FOR_EACH_SEP(what, sep, ...) _C4_FOR_EACH_(_C4_FOR_EACH_NARG(__VA_ARGS__), what, sep, __VA_ARGS__)
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
|
||||||
|
#define _C4_FOR_EACH_01(what, sep, x) what(x) sep
|
||||||
|
#define _C4_FOR_EACH_02(what, sep, x, ...) what(x) sep _C4_FOR_EACH_01(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_03(what, sep, x, ...) what(x) sep _C4_FOR_EACH_02(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_04(what, sep, x, ...) what(x) sep _C4_FOR_EACH_03(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_05(what, sep, x, ...) what(x) sep _C4_FOR_EACH_04(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_06(what, sep, x, ...) what(x) sep _C4_FOR_EACH_05(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_07(what, sep, x, ...) what(x) sep _C4_FOR_EACH_06(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_08(what, sep, x, ...) what(x) sep _C4_FOR_EACH_07(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_09(what, sep, x, ...) what(x) sep _C4_FOR_EACH_08(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_10(what, sep, x, ...) what(x) sep _C4_FOR_EACH_09(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_11(what, sep, x, ...) what(x) sep _C4_FOR_EACH_10(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_12(what, sep, x, ...) what(x) sep _C4_FOR_EACH_11(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_13(what, sep, x, ...) what(x) sep _C4_FOR_EACH_12(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_14(what, sep, x, ...) what(x) sep _C4_FOR_EACH_13(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_15(what, sep, x, ...) what(x) sep _C4_FOR_EACH_14(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_16(what, sep, x, ...) what(x) sep _C4_FOR_EACH_15(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_17(what, sep, x, ...) what(x) sep _C4_FOR_EACH_16(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_18(what, sep, x, ...) what(x) sep _C4_FOR_EACH_17(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_19(what, sep, x, ...) what(x) sep _C4_FOR_EACH_18(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_20(what, sep, x, ...) what(x) sep _C4_FOR_EACH_19(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_21(what, sep, x, ...) what(x) sep _C4_FOR_EACH_20(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_22(what, sep, x, ...) what(x) sep _C4_FOR_EACH_21(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_23(what, sep, x, ...) what(x) sep _C4_FOR_EACH_22(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_24(what, sep, x, ...) what(x) sep _C4_FOR_EACH_23(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_25(what, sep, x, ...) what(x) sep _C4_FOR_EACH_24(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_26(what, sep, x, ...) what(x) sep _C4_FOR_EACH_25(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_27(what, sep, x, ...) what(x) sep _C4_FOR_EACH_26(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_28(what, sep, x, ...) what(x) sep _C4_FOR_EACH_27(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_29(what, sep, x, ...) what(x) sep _C4_FOR_EACH_28(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_30(what, sep, x, ...) what(x) sep _C4_FOR_EACH_29(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_31(what, sep, x, ...) what(x) sep _C4_FOR_EACH_30(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_32(what, sep, x, ...) what(x) sep _C4_FOR_EACH_31(what, sep, __VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_NARG(...) _C4_FOR_EACH_NARG_(__VA_ARGS__, _C4_FOR_EACH_RSEQ_N())
|
||||||
|
#define _C4_FOR_EACH_NARG_(...) _C4_FOR_EACH_ARG_N(__VA_ARGS__)
|
||||||
|
#define _C4_FOR_EACH_ARG_N(_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...) N
|
||||||
|
#define _C4_FOR_EACH_RSEQ_N() 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01
|
||||||
|
#define _C4_FOR_EACH_(N, what, sep, ...) C4_XCAT(_C4_FOR_EACH_, N)(what, sep, __VA_ARGS__)
|
||||||
|
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_PREPROCESSOR_HPP_ */
|
11
dep/rapidyaml/include/c4/std/std.hpp
Normal file
11
dep/rapidyaml/include/c4/std/std.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _C4_STD_STD_HPP_
|
||||||
|
#define _C4_STD_STD_HPP_
|
||||||
|
|
||||||
|
/** @file std.hpp includes all c4-std interop files */
|
||||||
|
|
||||||
|
#include "c4/std/vector.hpp"
|
||||||
|
#include "c4/std/string.hpp"
|
||||||
|
#include "c4/std/string_view.hpp"
|
||||||
|
#include "c4/std/tuple.hpp"
|
||||||
|
|
||||||
|
#endif // _C4_STD_STD_HPP_
|
10
dep/rapidyaml/include/c4/std/std_fwd.hpp
Normal file
10
dep/rapidyaml/include/c4/std/std_fwd.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _C4_STD_STD_FWD_HPP_
|
||||||
|
#define _C4_STD_STD_FWD_HPP_
|
||||||
|
|
||||||
|
/** @file std_fwd.hpp includes all c4-std interop fwd files */
|
||||||
|
|
||||||
|
#include "c4/std/vector_fwd.hpp"
|
||||||
|
#include "c4/std/string_fwd.hpp"
|
||||||
|
//#include "c4/std/tuple_fwd.hpp"
|
||||||
|
|
||||||
|
#endif // _C4_STD_STD_FWD_HPP_
|
97
dep/rapidyaml/include/c4/std/string.hpp
Normal file
97
dep/rapidyaml/include/c4/std/string.hpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#ifndef _C4_STD_STRING_HPP_
|
||||||
|
#define _C4_STD_STRING_HPP_
|
||||||
|
|
||||||
|
/** @file string.hpp */
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/substr.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** get a writeable view to an existing std::string.
|
||||||
|
* When the string is empty, the returned view will be pointing
|
||||||
|
* at the character with value '\0', but the size will be zero.
|
||||||
|
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
|
||||||
|
*/
|
||||||
|
C4_ALWAYS_INLINE c4::substr to_substr(std::string &s) noexcept
|
||||||
|
{
|
||||||
|
#if C4_CPP < 11
|
||||||
|
#error this function will have undefined behavior
|
||||||
|
#endif
|
||||||
|
// since c++11 it is legal to call s[s.size()].
|
||||||
|
return c4::substr(&s[0], s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get a readonly view to an existing std::string.
|
||||||
|
* When the string is empty, the returned view will be pointing
|
||||||
|
* at the character with value '\0', but the size will be zero.
|
||||||
|
* @see https://en.cppreference.com/w/cpp/string/basic_string/operator_at
|
||||||
|
*/
|
||||||
|
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string const& s) noexcept
|
||||||
|
{
|
||||||
|
#if C4_CPP < 11
|
||||||
|
#error this function will have undefined behavior
|
||||||
|
#endif
|
||||||
|
// since c++11 it is legal to call s[s.size()].
|
||||||
|
return c4::csubstr(&s[0], s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) == 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) != 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) >= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) > 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) <= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string const& s) { return ss.compare(to_csubstr(s)) < 0; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE bool operator== (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) == 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator!= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) != 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator>= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) <= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator> (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) < 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator<= (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) >= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator< (std::string const& s, c4::csubstr ss) { return ss.compare(to_csubstr(s)) > 0; }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** copy an std::string to a writeable string view */
|
||||||
|
inline size_t to_chars(c4::substr buf, std::string const& s)
|
||||||
|
{
|
||||||
|
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
|
||||||
|
size_t len = buf.len < s.size() ? buf.len : s.size();
|
||||||
|
// calling memcpy with null strings is undefined behavior
|
||||||
|
// and will wreak havoc in calling code's branches.
|
||||||
|
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
|
||||||
|
if(len)
|
||||||
|
{
|
||||||
|
C4_ASSERT(s.data() != nullptr);
|
||||||
|
C4_ASSERT(buf.str != nullptr);
|
||||||
|
memcpy(buf.str, s.data(), len);
|
||||||
|
}
|
||||||
|
return s.size(); // return the number of needed chars
|
||||||
|
}
|
||||||
|
|
||||||
|
/** copy a string view to an existing std::string */
|
||||||
|
inline bool from_chars(c4::csubstr buf, std::string * s)
|
||||||
|
{
|
||||||
|
s->resize(buf.len);
|
||||||
|
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
|
||||||
|
// calling memcpy with null strings is undefined behavior
|
||||||
|
// and will wreak havoc in calling code's branches.
|
||||||
|
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
|
||||||
|
if(buf.len)
|
||||||
|
{
|
||||||
|
C4_ASSERT(buf.str != nullptr);
|
||||||
|
memcpy(&(*s)[0], buf.str, buf.len);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_STD_STRING_HPP_
|
59
dep/rapidyaml/include/c4/std/string_fwd.hpp
Normal file
59
dep/rapidyaml/include/c4/std/string_fwd.hpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef _C4_STD_STRING_FWD_HPP_
|
||||||
|
#define _C4_STD_STRING_FWD_HPP_
|
||||||
|
|
||||||
|
/** @file string_fwd.hpp */
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/substr_fwd.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
// forward declarations for std::string
|
||||||
|
#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
|
||||||
|
#include <bits/stringfwd.h> // use the fwd header in glibcxx
|
||||||
|
#elif defined(_LIBCPP_VERSION) || defined(__APPLE_CC__)
|
||||||
|
#include <iosfwd> // use the fwd header in stdlibc++
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
//! @todo is there a fwd header in msvc?
|
||||||
|
namespace std {
|
||||||
|
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4643) // Forward declaring 'char_traits' in namespace std is not permitted by the C++ Standard.
|
||||||
|
template<typename> struct char_traits;
|
||||||
|
template<typename> class allocator;
|
||||||
|
template<typename _CharT, typename _Traits, typename _Alloc> class basic_string;
|
||||||
|
using string = basic_string<char, char_traits<char>, allocator<char>>;
|
||||||
|
C4_SUPPRESS_WARNING_MSVC_POP
|
||||||
|
} /* namespace std */
|
||||||
|
#else
|
||||||
|
#error "unknown standard library"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE c4::substr to_substr(std::string &s) noexcept;
|
||||||
|
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string const& s) noexcept;
|
||||||
|
|
||||||
|
bool operator== (c4::csubstr ss, std::string const& s);
|
||||||
|
bool operator!= (c4::csubstr ss, std::string const& s);
|
||||||
|
bool operator>= (c4::csubstr ss, std::string const& s);
|
||||||
|
bool operator> (c4::csubstr ss, std::string const& s);
|
||||||
|
bool operator<= (c4::csubstr ss, std::string const& s);
|
||||||
|
bool operator< (c4::csubstr ss, std::string const& s);
|
||||||
|
|
||||||
|
bool operator== (std::string const& s, c4::csubstr ss);
|
||||||
|
bool operator!= (std::string const& s, c4::csubstr ss);
|
||||||
|
bool operator>= (std::string const& s, c4::csubstr ss);
|
||||||
|
bool operator> (std::string const& s, c4::csubstr ss);
|
||||||
|
bool operator<= (std::string const& s, c4::csubstr ss);
|
||||||
|
bool operator< (std::string const& s, c4::csubstr ss);
|
||||||
|
|
||||||
|
size_t to_chars(c4::substr buf, std::string const& s);
|
||||||
|
bool from_chars(c4::csubstr buf, std::string * s);
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // DOXYGEN
|
||||||
|
#endif // _C4_STD_STRING_FWD_HPP_
|
71
dep/rapidyaml/include/c4/std/string_view.hpp
Normal file
71
dep/rapidyaml/include/c4/std/string_view.hpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef _C4_STD_STRING_VIEW_HPP_
|
||||||
|
#define _C4_STD_STRING_VIEW_HPP_
|
||||||
|
|
||||||
|
/** @file string_view.hpp */
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/language.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (C4_CPP >= 17 && defined(__cpp_lib_string_view))
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/substr.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** create a csubstr from an existing std::string_view. */
|
||||||
|
C4_ALWAYS_INLINE c4::csubstr to_csubstr(std::string_view s) noexcept
|
||||||
|
{
|
||||||
|
return c4::csubstr(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) == 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) != 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) >= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) > 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) <= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::string_view s) { return ss.compare(s.data(), s.size()) < 0; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE bool operator== (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) == 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator!= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) != 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator<= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) >= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator< (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) > 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator>= (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) <= 0; }
|
||||||
|
C4_ALWAYS_INLINE bool operator> (std::string_view s, c4::csubstr ss) { return ss.compare(s.data(), s.size()) < 0; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** copy an std::string_view to a writeable substr */
|
||||||
|
inline size_t to_chars(c4::substr buf, std::string_view s)
|
||||||
|
{
|
||||||
|
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
|
||||||
|
size_t sz = s.size();
|
||||||
|
size_t len = buf.len < sz ? buf.len : sz;
|
||||||
|
// calling memcpy with null strings is undefined behavior
|
||||||
|
// and will wreak havoc in calling code's branches.
|
||||||
|
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
|
||||||
|
if(len)
|
||||||
|
{
|
||||||
|
C4_ASSERT(s.data() != nullptr);
|
||||||
|
C4_ASSERT(buf.str != nullptr);
|
||||||
|
memcpy(buf.str, s.data(), len);
|
||||||
|
}
|
||||||
|
return sz; // return the number of needed chars
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // C4_STRING_VIEW_AVAILABLE
|
||||||
|
|
||||||
|
#endif // _C4_STD_STRING_VIEW_HPP_
|
184
dep/rapidyaml/include/c4/std/tuple.hpp
Normal file
184
dep/rapidyaml/include/c4/std/tuple.hpp
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
#ifndef _C4_STD_TUPLE_HPP_
|
||||||
|
#define _C4_STD_TUPLE_HPP_
|
||||||
|
|
||||||
|
/** @file tuple.hpp */
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/format.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
/** this is a work in progress */
|
||||||
|
#undef C4_TUPLE_TO_CHARS
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
#ifdef C4_TUPLE_TO_CHARS
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template< size_t Curr, class... Types >
|
||||||
|
struct tuple_helper
|
||||||
|
{
|
||||||
|
static size_t do_cat(substr buf, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
size_t num = to_chars(buf, std::get<Curr>(tp));
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num += tuple_helper< Curr+1, Types... >::do_cat(buf, tp);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t do_uncat(csubstr buf, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
size_t num = from_str_trim(buf, &std::get<Curr>(tp));
|
||||||
|
if(num == csubstr::npos) return csubstr::npos;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num += tuple_helper< Curr+1, Types... >::do_uncat(buf, tp);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class Sep >
|
||||||
|
static size_t do_catsep_more(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
size_t ret = to_chars(buf, sep), num = ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = to_chars(buf, std::get<Curr>(tp));
|
||||||
|
num += ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = tuple_helper< Curr+1, Types... >::do_catsep_more(buf, sep, tp);
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class Sep >
|
||||||
|
static size_t do_uncatsep_more(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
size_t ret = from_str_trim(buf, &sep), num = ret;
|
||||||
|
if(ret == csubstr::npos) return csubstr::npos;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = from_str_trim(buf, &std::get<Curr>(tp));
|
||||||
|
if(ret == csubstr::npos) return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = tuple_helper< Curr+1, Types... >::do_uncatsep_more(buf, sep, tp);
|
||||||
|
if(ret == csubstr::npos) return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t do_format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
auto pos = fmt.find("{}");
|
||||||
|
if(pos != csubstr::npos)
|
||||||
|
{
|
||||||
|
size_t num = to_chars(buf, fmt.sub(0, pos));
|
||||||
|
size_t out = num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = to_chars(buf, std::get<Curr>(tp));
|
||||||
|
out += num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = tuple_helper< Curr+1, Types... >::do_format(buf, fmt.sub(pos + 2), tp);
|
||||||
|
out += num;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return format(buf, fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
auto pos = fmt.find("{}");
|
||||||
|
if(pos != csubstr::npos)
|
||||||
|
{
|
||||||
|
size_t num = pos;
|
||||||
|
size_t out = num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = from_str_trim(buf, &std::get<Curr>(tp));
|
||||||
|
out += num;
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num = tuple_helper< Curr+1, Types... >::do_unformat(buf, fmt.sub(pos + 2), tp);
|
||||||
|
out += num;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return tuple_helper< sizeof...(Types), Types... >::do_unformat(buf, fmt, tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @todo VS compilation fails for this class */
|
||||||
|
template< class... Types >
|
||||||
|
struct tuple_helper< sizeof...(Types), Types... >
|
||||||
|
{
|
||||||
|
static size_t do_cat(substr /*buf*/, std::tuple<Types...> const& /*tp*/) { return 0; }
|
||||||
|
static size_t do_uncat(csubstr /*buf*/, std::tuple<Types...> & /*tp*/) { return 0; }
|
||||||
|
|
||||||
|
template< class Sep > static size_t do_catsep_more(substr /*buf*/, Sep const& /*sep*/, std::tuple<Types...> const& /*tp*/) { return 0; }
|
||||||
|
template< class Sep > static size_t do_uncatsep_more(csubstr /*buf*/, Sep & /*sep*/, std::tuple<Types...> & /*tp*/) { return 0; }
|
||||||
|
|
||||||
|
static size_t do_format(substr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
|
||||||
|
{
|
||||||
|
return to_chars(buf, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t do_unformat(csubstr buf, csubstr fmt, std::tuple<Types...> const& /*tp*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template< class... Types >
|
||||||
|
inline size_t cat(substr buf, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
return detail::tuple_helper< 0, Types... >::do_cat(buf, tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class... Types >
|
||||||
|
inline size_t uncat(csubstr buf, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
return detail::tuple_helper< 0, Types... >::do_uncat(buf, tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class Sep, class... Types >
|
||||||
|
inline size_t catsep(substr buf, Sep const& sep, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
size_t num = to_chars(buf, std::cref(std::get<0>(tp)));
|
||||||
|
buf = buf.len >= num ? buf.sub(num) : substr{};
|
||||||
|
num += detail::tuple_helper< 1, Types... >::do_catsep_more(buf, sep, tp);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class Sep, class... Types >
|
||||||
|
inline size_t uncatsep(csubstr buf, Sep & sep, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
size_t ret = from_str_trim(buf, &std::get<0>(tp)), num = ret;
|
||||||
|
if(ret == csubstr::npos) return csubstr::npos;
|
||||||
|
buf = buf.len >= ret ? buf.sub(ret) : substr{};
|
||||||
|
ret = detail::tuple_helper< 1, Types... >::do_uncatsep_more(buf, sep, tp);
|
||||||
|
if(ret == csubstr::npos) return csubstr::npos;
|
||||||
|
num += ret;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class... Types >
|
||||||
|
inline size_t format(substr buf, csubstr fmt, std::tuple< Types... > const& tp)
|
||||||
|
{
|
||||||
|
return detail::tuple_helper< 0, Types... >::do_format(buf, fmt, tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class... Types >
|
||||||
|
inline size_t unformat(csubstr buf, csubstr fmt, std::tuple< Types... > & tp)
|
||||||
|
{
|
||||||
|
return detail::tuple_helper< 0, Types... >::do_unformat(buf, fmt, tp);
|
||||||
|
}
|
||||||
|
#endif // C4_TUPLE_TO_CHARS
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_STD_TUPLE_HPP_ */
|
88
dep/rapidyaml/include/c4/std/vector.hpp
Normal file
88
dep/rapidyaml/include/c4/std/vector.hpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef _C4_STD_VECTOR_HPP_
|
||||||
|
#define _C4_STD_VECTOR_HPP_
|
||||||
|
|
||||||
|
/** @file vector.hpp provides conversion and comparison facilities
|
||||||
|
* from/between std::vector<char> to c4::substr and c4::csubstr.
|
||||||
|
* @todo add to_span() and friends
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/substr.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** get a substr (writeable string view) of an existing std::vector<char> */
|
||||||
|
template<class Alloc>
|
||||||
|
c4::substr to_substr(std::vector<char, Alloc> &vec)
|
||||||
|
{
|
||||||
|
char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
|
||||||
|
return c4::substr(data, vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get a csubstr (read-only string) view of an existing std::vector<char> */
|
||||||
|
template<class Alloc>
|
||||||
|
c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec)
|
||||||
|
{
|
||||||
|
const char *data = vec.empty() ? nullptr : vec.data(); // data() may or may not return a null pointer.
|
||||||
|
return c4::csubstr(data, vec.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// comparisons between substrings and std::vector<char>
|
||||||
|
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss != to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss == to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss >= to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss > to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss <= to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s) { return ss < to_csubstr(s); }
|
||||||
|
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss != to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss == to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss <= to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss < to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss >= to_csubstr(s); }
|
||||||
|
template<class Alloc> C4_ALWAYS_INLINE bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss) { return ss > to_csubstr(s); }
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** copy a std::vector<char> to a writeable string view */
|
||||||
|
template<class Alloc>
|
||||||
|
inline size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s)
|
||||||
|
{
|
||||||
|
C4_ASSERT(!buf.overlaps(to_csubstr(s)));
|
||||||
|
size_t len = buf.len < s.size() ? buf.len : s.size();
|
||||||
|
// calling memcpy with null strings is undefined behavior
|
||||||
|
// and will wreak havoc in calling code's branches.
|
||||||
|
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
|
||||||
|
if(len > 0)
|
||||||
|
{
|
||||||
|
memcpy(buf.str, s.data(), len);
|
||||||
|
}
|
||||||
|
return s.size(); // return the number of needed chars
|
||||||
|
}
|
||||||
|
|
||||||
|
/** copy a string view to an existing std::vector<char> */
|
||||||
|
template<class Alloc>
|
||||||
|
inline bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s)
|
||||||
|
{
|
||||||
|
s->resize(buf.len);
|
||||||
|
C4_ASSERT(!buf.overlaps(to_csubstr(*s)));
|
||||||
|
// calling memcpy with null strings is undefined behavior
|
||||||
|
// and will wreak havoc in calling code's branches.
|
||||||
|
// see https://github.com/biojppm/rapidyaml/pull/264#issuecomment-1262133637
|
||||||
|
if(buf.len > 0)
|
||||||
|
{
|
||||||
|
memcpy(&(*s)[0], buf.str, buf.len);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_STD_VECTOR_HPP_
|
66
dep/rapidyaml/include/c4/std/vector_fwd.hpp
Normal file
66
dep/rapidyaml/include/c4/std/vector_fwd.hpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef _C4_STD_VECTOR_FWD_HPP_
|
||||||
|
#define _C4_STD_VECTOR_FWD_HPP_
|
||||||
|
|
||||||
|
/** @file vector_fwd.hpp */
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
// forward declarations for std::vector
|
||||||
|
#if defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_MSC_VER)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
__pragma(warning(push))
|
||||||
|
__pragma(warning(disable : 4643))
|
||||||
|
#endif
|
||||||
|
namespace std {
|
||||||
|
template<typename> class allocator;
|
||||||
|
#ifdef _GLIBCXX_DEBUG
|
||||||
|
inline namespace __debug {
|
||||||
|
template<typename T, typename Alloc> class vector;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<typename T, typename Alloc> class vector;
|
||||||
|
#endif
|
||||||
|
} // namespace std
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
__pragma(warning(pop))
|
||||||
|
#endif
|
||||||
|
#elif defined(_LIBCPP_ABI_NAMESPACE)
|
||||||
|
namespace std {
|
||||||
|
inline namespace _LIBCPP_ABI_NAMESPACE {
|
||||||
|
template<typename> class allocator;
|
||||||
|
template<typename T, typename Alloc> class vector;
|
||||||
|
} // namespace _LIBCPP_ABI_NAMESPACE
|
||||||
|
} // namespace std
|
||||||
|
#else
|
||||||
|
#error "unknown standard library"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef C4CORE_SINGLE_HEADER
|
||||||
|
#include "c4/substr_fwd.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
template<class Alloc> c4::substr to_substr(std::vector<char, Alloc> &vec);
|
||||||
|
template<class Alloc> c4::csubstr to_csubstr(std::vector<char, Alloc> const& vec);
|
||||||
|
|
||||||
|
template<class Alloc> bool operator!= (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool operator== (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool operator>= (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool operator> (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool operator<= (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool operator< (c4::csubstr ss, std::vector<char, Alloc> const& s);
|
||||||
|
|
||||||
|
template<class Alloc> bool operator!= (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
template<class Alloc> bool operator== (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
template<class Alloc> bool operator>= (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
template<class Alloc> bool operator> (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
template<class Alloc> bool operator<= (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
template<class Alloc> bool operator< (std::vector<char, Alloc> const& s, c4::csubstr ss);
|
||||||
|
|
||||||
|
template<class Alloc> size_t to_chars(c4::substr buf, std::vector<char, Alloc> const& s);
|
||||||
|
template<class Alloc> bool from_chars(c4::csubstr buf, std::vector<char, Alloc> * s);
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_STD_VECTOR_FWD_HPP_
|
2218
dep/rapidyaml/include/c4/substr.hpp
Normal file
2218
dep/rapidyaml/include/c4/substr.hpp
Normal file
File diff suppressed because it is too large
Load diff
16
dep/rapidyaml/include/c4/substr_fwd.hpp
Normal file
16
dep/rapidyaml/include/c4/substr_fwd.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef _C4_SUBSTR_FWD_HPP_
|
||||||
|
#define _C4_SUBSTR_FWD_HPP_
|
||||||
|
|
||||||
|
#include "c4/export.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
template<class C> struct basic_substring;
|
||||||
|
using csubstr = C4CORE_EXPORT basic_substring<const char>;
|
||||||
|
using substr = C4CORE_EXPORT basic_substring<char>;
|
||||||
|
#endif // !DOXYGEN
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_SUBSTR_FWD_HPP_ */
|
68
dep/rapidyaml/include/c4/szconv.hpp
Normal file
68
dep/rapidyaml/include/c4/szconv.hpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef _C4_SZCONV_HPP_
|
||||||
|
#define _C4_SZCONV_HPP_
|
||||||
|
|
||||||
|
/** @file szconv.hpp utilities to deal safely with narrowing conversions */
|
||||||
|
|
||||||
|
#include "c4/config.hpp"
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
/** @todo this would be so much easier with calls to numeric_limits::max()... */
|
||||||
|
template<class SizeOut, class SizeIn>
|
||||||
|
struct is_narrower_size : std::conditional
|
||||||
|
<
|
||||||
|
(std::is_signed<SizeOut>::value == std::is_signed<SizeIn>::value)
|
||||||
|
?
|
||||||
|
(sizeof(SizeOut) < sizeof(SizeIn))
|
||||||
|
:
|
||||||
|
(
|
||||||
|
(sizeof(SizeOut) < sizeof(SizeIn))
|
||||||
|
||
|
||||||
|
(
|
||||||
|
(sizeof(SizeOut) == sizeof(SizeIn))
|
||||||
|
&&
|
||||||
|
(std::is_signed<SizeOut>::value && std::is_unsigned<SizeIn>::value)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
std::true_type,
|
||||||
|
std::false_type
|
||||||
|
>::type
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<SizeIn >::value, "must be integral type");
|
||||||
|
static_assert(std::is_integral<SizeOut>::value, "must be integral type");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** when SizeOut is wider than SizeIn, assignment can occur without reservations */
|
||||||
|
template<class SizeOut, class SizeIn>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if< ! is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
|
||||||
|
szconv(SizeIn sz) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<SizeOut>(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** when SizeOut is narrower than SizeIn, narrowing will occur, so we check
|
||||||
|
* for overflow. Note that this check is done only if C4_XASSERT is enabled.
|
||||||
|
* @see C4_XASSERT */
|
||||||
|
template<class SizeOut, class SizeIn>
|
||||||
|
C4_ALWAYS_INLINE
|
||||||
|
typename std::enable_if<is_narrower_size<SizeOut, SizeIn>::value, SizeOut>::type
|
||||||
|
szconv(SizeIn sz) C4_NOEXCEPT_X
|
||||||
|
{
|
||||||
|
C4_XASSERT(sz >= 0);
|
||||||
|
C4_XASSERT_MSG((SizeIn)sz <= (SizeIn)std::numeric_limits<SizeOut>::max(), "size conversion overflow: in=%zu", (size_t)sz);
|
||||||
|
SizeOut szo = static_cast<SizeOut>(sz);
|
||||||
|
return szo;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_SZCONV_HPP_ */
|
503
dep/rapidyaml/include/c4/types.hpp
Normal file
503
dep/rapidyaml/include/c4/types.hpp
Normal file
|
@ -0,0 +1,503 @@
|
||||||
|
#ifndef _C4_TYPES_HPP_
|
||||||
|
#define _C4_TYPES_HPP_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#include <utility> // for integer_sequence and friends
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "c4/preprocessor.hpp"
|
||||||
|
#include "c4/language.hpp"
|
||||||
|
|
||||||
|
/** @file types.hpp basic types, and utility macros and traits for types.
|
||||||
|
* @ingroup basic_headers */
|
||||||
|
|
||||||
|
/** @defgroup types Type utilities */
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
/** @defgroup intrinsic_types Intrinsic types
|
||||||
|
* @ingroup types
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
using cbyte = const char; /**< a constant byte */
|
||||||
|
using byte = char; /**< a mutable byte */
|
||||||
|
|
||||||
|
using i8 = int8_t;
|
||||||
|
using i16 = int16_t;
|
||||||
|
using i32 = int32_t;
|
||||||
|
using i64 = int64_t;
|
||||||
|
using u8 = uint8_t;
|
||||||
|
using u16 = uint16_t;
|
||||||
|
using u32 = uint32_t;
|
||||||
|
using u64 = uint64_t;
|
||||||
|
|
||||||
|
using f32 = float;
|
||||||
|
using f64 = double;
|
||||||
|
|
||||||
|
using ssize_t = typename std::make_signed<size_t>::type;
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/** @defgroup utility_types Utility types
|
||||||
|
* @ingroup types
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
// some tag types
|
||||||
|
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#if __GNUC__ >= 6
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-const-variable"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** a tag type for initializing the containers with variadic arguments a la
|
||||||
|
* initializer_list, minus the initializer_list overload problems.
|
||||||
|
*/
|
||||||
|
struct aggregate_t {};
|
||||||
|
/** @see aggregate_t */
|
||||||
|
constexpr const aggregate_t aggregate{};
|
||||||
|
|
||||||
|
/** a tag type for specifying the initial capacity of allocatable contiguous storage */
|
||||||
|
struct with_capacity_t {};
|
||||||
|
/** @see with_capacity_t */
|
||||||
|
constexpr const with_capacity_t with_capacity{};
|
||||||
|
|
||||||
|
/** a tag type for disambiguating template parameter packs in variadic template overloads */
|
||||||
|
struct varargs_t {};
|
||||||
|
/** @see with_capacity_t */
|
||||||
|
constexpr const varargs_t varargs{};
|
||||||
|
|
||||||
|
#if !defined(__clang__) && defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/** whether a value should be used in place of a const-reference in argument passing. */
|
||||||
|
template<class T>
|
||||||
|
struct cref_uses_val
|
||||||
|
{
|
||||||
|
enum { value = (
|
||||||
|
std::is_scalar<T>::value
|
||||||
|
||
|
||||||
|
(
|
||||||
|
#if C4_CPP >= 20
|
||||||
|
(std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value)
|
||||||
|
#else
|
||||||
|
std::is_pod<T>::value
|
||||||
|
#endif
|
||||||
|
&&
|
||||||
|
sizeof(T) <= sizeof(size_t))) };
|
||||||
|
};
|
||||||
|
/** utility macro to override the default behaviour for c4::fastcref<T>
|
||||||
|
@see fastcref */
|
||||||
|
#define C4_CREF_USES_VAL(T) \
|
||||||
|
template<> \
|
||||||
|
struct cref_uses_val<T> \
|
||||||
|
{ \
|
||||||
|
enum { value = true }; \
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Whether to use pass-by-value or pass-by-const-reference in a function argument
|
||||||
|
* or return type. */
|
||||||
|
template<class T>
|
||||||
|
using fastcref = typename std::conditional<c4::cref_uses_val<T>::value, T, T const&>::type;
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/** Just what its name says. Useful sometimes as a default empty policy class. */
|
||||||
|
struct EmptyStruct
|
||||||
|
{
|
||||||
|
template<class... T> EmptyStruct(T && ...){}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Just what its name says. Useful sometimes as a default policy class to
|
||||||
|
* be inherited from. */
|
||||||
|
struct EmptyStructVirtual
|
||||||
|
{
|
||||||
|
virtual ~EmptyStructVirtual() = default;
|
||||||
|
template<class... T> EmptyStructVirtual(T && ...){}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** */
|
||||||
|
template<class T>
|
||||||
|
struct inheritfrom : public T {};
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// Utilities to make a class obey size restrictions (eg, min size or size multiple of).
|
||||||
|
// DirectX usually makes this restriction with uniform buffers.
|
||||||
|
// This is also useful for padding to prevent false-sharing.
|
||||||
|
|
||||||
|
/** how many bytes must be added to size such that the result is at least minsize? */
|
||||||
|
C4_ALWAYS_INLINE constexpr size_t min_remainder(size_t size, size_t minsize) noexcept
|
||||||
|
{
|
||||||
|
return size < minsize ? minsize-size : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** how many bytes must be added to size such that the result is a multiple of multipleof? */
|
||||||
|
C4_ALWAYS_INLINE constexpr size_t mult_remainder(size_t size, size_t multipleof) noexcept
|
||||||
|
{
|
||||||
|
return (((size % multipleof) != 0) ? (multipleof-(size % multipleof)) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* force the following class to be tightly packed. */
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
/** pad a class with more bytes at the end.
|
||||||
|
* @see http://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly */
|
||||||
|
template<class T, size_t BytesToPadAtEnd>
|
||||||
|
struct Padded : public T
|
||||||
|
{
|
||||||
|
using T::T;
|
||||||
|
using T::operator=;
|
||||||
|
Padded(T const& val) : T(val) {}
|
||||||
|
Padded(T && val) : T(val) {}
|
||||||
|
char ___c4padspace___[BytesToPadAtEnd];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
/** When the padding argument is 0, we cannot declare the char[] array. */
|
||||||
|
template<class T>
|
||||||
|
struct Padded<T, 0> : public T
|
||||||
|
{
|
||||||
|
using T::T;
|
||||||
|
using T::operator=;
|
||||||
|
Padded(T const& val) : T(val) {}
|
||||||
|
Padded(T && val) : T(val) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** make T have a size which is at least Min bytes */
|
||||||
|
template<class T, size_t Min>
|
||||||
|
using MinSized = Padded<T, min_remainder(sizeof(T), Min)>;
|
||||||
|
|
||||||
|
/** make T have a size which is a multiple of Mult bytes */
|
||||||
|
template<class T, size_t Mult>
|
||||||
|
using MultSized = Padded<T, mult_remainder(sizeof(T), Mult)>;
|
||||||
|
|
||||||
|
/** make T have a size which is simultaneously:
|
||||||
|
* -bigger or equal than Min
|
||||||
|
* -a multiple of Mult */
|
||||||
|
template<class T, size_t Min, size_t Mult>
|
||||||
|
using MinMultSized = MultSized<MinSized<T, Min>, Mult>;
|
||||||
|
|
||||||
|
/** make T be suitable for use as a uniform buffer. (at least with DirectX). */
|
||||||
|
template<class T>
|
||||||
|
using UbufSized = MinMultSized<T, 64, 16>;
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define C4_NO_COPY_CTOR(ty) ty(ty const&) = delete
|
||||||
|
#define C4_NO_MOVE_CTOR(ty) ty(ty &&) = delete
|
||||||
|
#define C4_NO_COPY_ASSIGN(ty) ty& operator=(ty const&) = delete
|
||||||
|
#define C4_NO_MOVE_ASSIGN(ty) ty& operator=(ty &&) = delete
|
||||||
|
#define C4_DEFAULT_COPY_CTOR(ty) ty(ty const&) noexcept = default
|
||||||
|
#define C4_DEFAULT_MOVE_CTOR(ty) ty(ty &&) noexcept = default
|
||||||
|
#define C4_DEFAULT_COPY_ASSIGN(ty) ty& operator=(ty const&) noexcept = default
|
||||||
|
#define C4_DEFAULT_MOVE_ASSIGN(ty) ty& operator=(ty &&) noexcept = default
|
||||||
|
|
||||||
|
#define C4_NO_COPY_OR_MOVE_CTOR(ty) \
|
||||||
|
C4_NO_COPY_CTOR(ty); \
|
||||||
|
C4_NO_MOVE_CTOR(ty)
|
||||||
|
|
||||||
|
#define C4_NO_COPY_OR_MOVE_ASSIGN(ty) \
|
||||||
|
C4_NO_COPY_ASSIGN(ty); \
|
||||||
|
C4_NO_MOVE_ASSIGN(ty)
|
||||||
|
|
||||||
|
#define C4_NO_COPY_OR_MOVE(ty) \
|
||||||
|
C4_NO_COPY_OR_MOVE_CTOR(ty); \
|
||||||
|
C4_NO_COPY_OR_MOVE_ASSIGN(ty)
|
||||||
|
|
||||||
|
#define C4_DEFAULT_COPY_AND_MOVE_CTOR(ty) \
|
||||||
|
C4_DEFAULT_COPY_CTOR(ty); \
|
||||||
|
C4_DEFAULT_MOVE_CTOR(ty)
|
||||||
|
|
||||||
|
#define C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty) \
|
||||||
|
C4_DEFAULT_COPY_ASSIGN(ty); \
|
||||||
|
C4_DEFAULT_MOVE_ASSIGN(ty)
|
||||||
|
|
||||||
|
#define C4_DEFAULT_COPY_AND_MOVE(ty) \
|
||||||
|
C4_DEFAULT_COPY_AND_MOVE_CTOR(ty); \
|
||||||
|
C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty)
|
||||||
|
|
||||||
|
/** @see https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable */
|
||||||
|
#define C4_MUST_BE_TRIVIAL_COPY(ty) \
|
||||||
|
static_assert(std::is_trivially_copyable<ty>::value, #ty " must be trivially copyable")
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @defgroup traits_types Type traits utilities
|
||||||
|
* @ingroup types
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/10821380/is-t-an-instance-of-a-template-in-c
|
||||||
|
template<template<typename...> class X, typename T> struct is_instance_of_tpl : std::false_type {};
|
||||||
|
template<template<typename...> class X, typename... Y> struct is_instance_of_tpl<X, X<Y...>> : std::true_type {};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** SFINAE. use this macro to enable a template function overload
|
||||||
|
based on a compile-time condition.
|
||||||
|
@code
|
||||||
|
// define an overload for a non-pod type
|
||||||
|
template<class T, C4_REQUIRE_T(std::is_pod<T>::value)>
|
||||||
|
void foo() { std::cout << "pod type\n"; }
|
||||||
|
|
||||||
|
// define an overload for a non-pod type
|
||||||
|
template<class T, C4_REQUIRE_T(!std::is_pod<T>::value)>
|
||||||
|
void foo() { std::cout << "nonpod type\n"; }
|
||||||
|
|
||||||
|
struct non_pod
|
||||||
|
{
|
||||||
|
non_pod() : name("asdfkjhasdkjh") {}
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
foo<float>(); // prints "pod type"
|
||||||
|
foo<non_pod>(); // prints "nonpod type"
|
||||||
|
}
|
||||||
|
@endcode */
|
||||||
|
#define C4_REQUIRE_T(cond) typename std::enable_if<cond, bool>::type* = nullptr
|
||||||
|
|
||||||
|
/** enable_if for a return type
|
||||||
|
* @see C4_REQUIRE_T */
|
||||||
|
#define C4_REQUIRE_R(cond, type_) typename std::enable_if<cond, type_>::type
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** define a traits class reporting whether a type provides a member typedef */
|
||||||
|
#define C4_DEFINE_HAS_TYPEDEF(member_typedef) \
|
||||||
|
template<typename T> \
|
||||||
|
struct has_##stype \
|
||||||
|
{ \
|
||||||
|
private: \
|
||||||
|
\
|
||||||
|
typedef char yes; \
|
||||||
|
typedef struct { char array[2]; } no; \
|
||||||
|
\
|
||||||
|
template<typename C> \
|
||||||
|
static yes _test(typename C::member_typedef*); \
|
||||||
|
\
|
||||||
|
template<typename C> \
|
||||||
|
static no _test(...); \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
\
|
||||||
|
enum { value = (sizeof(_test<T>(0)) == sizeof(yes)) }; \
|
||||||
|
\
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup type_declarations Type declaration utilities
|
||||||
|
* @ingroup types
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
#define _c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I) \
|
||||||
|
\
|
||||||
|
using size_type = I; \
|
||||||
|
using ssize_type = typename std::make_signed<I>::type; \
|
||||||
|
using difference_type = typename std::make_signed<I>::type; \
|
||||||
|
\
|
||||||
|
using value_type = T; \
|
||||||
|
using pointer = T*; \
|
||||||
|
using const_pointer = T const*; \
|
||||||
|
using reference = T&; \
|
||||||
|
using const_reference = T const&
|
||||||
|
|
||||||
|
#define _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I) \
|
||||||
|
\
|
||||||
|
using size_type = I; \
|
||||||
|
using ssize_type = typename std::make_signed<I>::type; \
|
||||||
|
using difference_type = typename std::make_signed<I>::type; \
|
||||||
|
\
|
||||||
|
template<I n> using value_type = typename std::tuple_element< n, std::tuple<interior_types...>>::type; \
|
||||||
|
template<I n> using pointer = value_type<n>*; \
|
||||||
|
template<I n> using const_pointer = value_type<n> const*; \
|
||||||
|
template<I n> using reference = value_type<n>&; \
|
||||||
|
template<I n> using const_reference = value_type<n> const&
|
||||||
|
|
||||||
|
|
||||||
|
#define _c4_DEFINE_ARRAY_TYPES(T, I) \
|
||||||
|
\
|
||||||
|
_c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I); \
|
||||||
|
\
|
||||||
|
using iterator = T*; \
|
||||||
|
using const_iterator = T const*; \
|
||||||
|
using reverse_iterator = std::reverse_iterator<T*>; \
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<T const*>
|
||||||
|
|
||||||
|
|
||||||
|
#define _c4_DEFINE_TUPLE_ARRAY_TYPES(interior_types, I) \
|
||||||
|
\
|
||||||
|
_c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I); \
|
||||||
|
\
|
||||||
|
template<I n> using iterator = value_type<n>*; \
|
||||||
|
template<I n> using const_iterator = value_type<n> const*; \
|
||||||
|
template<I n> using reverse_iterator = std::reverse_iterator< value_type<n>*>; \
|
||||||
|
template<I n> using const_reverse_iterator = std::reverse_iterator< value_type<n> const*>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/** @defgroup compatility_utilities Backport implementation of some Modern C++ utilities
|
||||||
|
* @ingroup types
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// index_sequence and friends are available only for C++14 and later.
|
||||||
|
// A C++11 implementation is provided here.
|
||||||
|
// This implementation was copied over from clang.
|
||||||
|
// see http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687
|
||||||
|
|
||||||
|
#if __cplusplus > 201103L
|
||||||
|
|
||||||
|
using std::integer_sequence;
|
||||||
|
using std::index_sequence;
|
||||||
|
using std::make_integer_sequence;
|
||||||
|
using std::make_index_sequence;
|
||||||
|
using std::index_sequence_for;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/** C++11 implementation of integer sequence
|
||||||
|
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
|
||||||
|
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
|
||||||
|
template<class _Tp, _Tp... _Ip>
|
||||||
|
struct integer_sequence
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<_Tp>::value,
|
||||||
|
"std::integer_sequence can only be instantiated with an integral type" );
|
||||||
|
using value_type = _Tp;
|
||||||
|
static constexpr size_t size() noexcept { return sizeof...(_Ip); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** C++11 implementation of index sequence
|
||||||
|
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
|
||||||
|
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
|
||||||
|
template<size_t... _Ip>
|
||||||
|
using index_sequence = integer_sequence<size_t, _Ip...>;
|
||||||
|
|
||||||
|
/** @cond DONT_DOCUMENT_THIS */
|
||||||
|
namespace __detail {
|
||||||
|
|
||||||
|
template<typename _Tp, size_t ..._Extra>
|
||||||
|
struct __repeat;
|
||||||
|
|
||||||
|
template<typename _Tp, _Tp ..._Np, size_t ..._Extra>
|
||||||
|
struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...>
|
||||||
|
{
|
||||||
|
using type = integer_sequence<_Tp,
|
||||||
|
_Np...,
|
||||||
|
sizeof...(_Np) + _Np...,
|
||||||
|
2 * sizeof...(_Np) + _Np...,
|
||||||
|
3 * sizeof...(_Np) + _Np...,
|
||||||
|
4 * sizeof...(_Np) + _Np...,
|
||||||
|
5 * sizeof...(_Np) + _Np...,
|
||||||
|
6 * sizeof...(_Np) + _Np...,
|
||||||
|
7 * sizeof...(_Np) + _Np...,
|
||||||
|
_Extra...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t _Np> struct __parity;
|
||||||
|
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
|
||||||
|
|
||||||
|
template<> struct __make<0> { using type = integer_sequence<size_t>; };
|
||||||
|
template<> struct __make<1> { using type = integer_sequence<size_t, 0>; };
|
||||||
|
template<> struct __make<2> { using type = integer_sequence<size_t, 0, 1>; };
|
||||||
|
template<> struct __make<3> { using type = integer_sequence<size_t, 0, 1, 2>; };
|
||||||
|
template<> struct __make<4> { using type = integer_sequence<size_t, 0, 1, 2, 3>; };
|
||||||
|
template<> struct __make<5> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4>; };
|
||||||
|
template<> struct __make<6> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5>; };
|
||||||
|
template<> struct __make<7> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6>; };
|
||||||
|
|
||||||
|
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
|
||||||
|
template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
|
||||||
|
template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
|
||||||
|
|
||||||
|
template<typename _Tp, typename _Up>
|
||||||
|
struct __convert
|
||||||
|
{
|
||||||
|
template<typename> struct __result;
|
||||||
|
template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...>>
|
||||||
|
{
|
||||||
|
using type = integer_sequence<_Up, _Np...>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _Tp>
|
||||||
|
struct __convert<_Tp, _Tp>
|
||||||
|
{
|
||||||
|
template<typename _Up> struct __result
|
||||||
|
{
|
||||||
|
using type = _Up;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _Tp, _Tp _Np>
|
||||||
|
using __make_integer_sequence_unchecked = typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
|
||||||
|
|
||||||
|
template<class _Tp, _Tp _Ep>
|
||||||
|
struct __make_integer_sequence
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<_Tp>::value,
|
||||||
|
"std::make_integer_sequence can only be instantiated with an integral type" );
|
||||||
|
static_assert(0 <= _Ep, "std::make_integer_sequence input shall not be negative");
|
||||||
|
typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace __detail
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
|
||||||
|
/** C++11 implementation of index sequence
|
||||||
|
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
|
||||||
|
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
|
||||||
|
template<class _Tp, _Tp _Np>
|
||||||
|
using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type;
|
||||||
|
|
||||||
|
/** C++11 implementation of index sequence
|
||||||
|
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
|
||||||
|
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
|
||||||
|
template<size_t _Np>
|
||||||
|
using make_index_sequence = make_integer_sequence<size_t, _Np>;
|
||||||
|
|
||||||
|
/** C++11 implementation of index sequence
|
||||||
|
* @see https://en.cppreference.com/w/cpp/utility/integer_sequence
|
||||||
|
* @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */
|
||||||
|
template<class... _Tp>
|
||||||
|
using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_TYPES_HPP_ */
|
16
dep/rapidyaml/include/c4/utf.hpp
Normal file
16
dep/rapidyaml/include/c4/utf.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef C4_UTF_HPP_
|
||||||
|
#define C4_UTF_HPP_
|
||||||
|
|
||||||
|
#include "c4/language.hpp"
|
||||||
|
#include "c4/substr_fwd.hpp"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
substr decode_code_point(substr out, csubstr code_point);
|
||||||
|
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, const uint32_t code);
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // C4_UTF_HPP_
|
10
dep/rapidyaml/include/c4/windows.hpp
Normal file
10
dep/rapidyaml/include/c4/windows.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _C4_WINDOWS_HPP_
|
||||||
|
#define _C4_WINDOWS_HPP_
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
#include "c4/windows_push.hpp"
|
||||||
|
#include <windows.h>
|
||||||
|
#include "c4/windows_pop.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_WINDOWS_HPP_ */
|
41
dep/rapidyaml/include/c4/windows_pop.hpp
Normal file
41
dep/rapidyaml/include/c4/windows_pop.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef _C4_WINDOWS_POP_HPP_
|
||||||
|
#define _C4_WINDOWS_POP_HPP_
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
|
||||||
|
#ifdef _c4_AMD64_
|
||||||
|
# undef _c4_AMD64_
|
||||||
|
# undef _AMD64_
|
||||||
|
#endif
|
||||||
|
#ifdef _c4_X86_
|
||||||
|
# undef _c4_X86_
|
||||||
|
# undef _X86_
|
||||||
|
#endif
|
||||||
|
#ifdef _c4_ARM_
|
||||||
|
# undef _c4_ARM_
|
||||||
|
# undef _ARM_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _c4_NOMINMAX
|
||||||
|
# undef _c4_NOMINMAX
|
||||||
|
# undef NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NOGDI
|
||||||
|
# undef _c4_NOGDI
|
||||||
|
# undef NOGDI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VC_EXTRALEAN
|
||||||
|
# undef _c4_VC_EXTRALEAN
|
||||||
|
# undef VC_EXTRALEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32_LEAN_AND_MEAN
|
||||||
|
# undef _c4_WIN32_LEAN_AND_MEAN
|
||||||
|
# undef WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(_WIN64) || defined(_WIN32) */
|
||||||
|
|
||||||
|
#endif /* _C4_WINDOWS_POP_HPP_ */
|
102
dep/rapidyaml/include/c4/windows_push.hpp
Normal file
102
dep/rapidyaml/include/c4/windows_push.hpp
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#ifndef _C4_WINDOWS_PUSH_HPP_
|
||||||
|
#define _C4_WINDOWS_PUSH_HPP_
|
||||||
|
|
||||||
|
/** @file windows_push.hpp sets up macros to include windows header files
|
||||||
|
* without pulling in all of <windows.h>
|
||||||
|
*
|
||||||
|
* @see #include windows_pop.hpp to undefine these macros
|
||||||
|
*
|
||||||
|
* @see https://aras-p.info/blog/2018/01/12/Minimizing-windows.h/ */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
|
||||||
|
#if defined(_M_AMD64)
|
||||||
|
# ifndef _AMD64_
|
||||||
|
# define _c4_AMD64_
|
||||||
|
# define _AMD64_
|
||||||
|
# endif
|
||||||
|
#elif defined(_M_IX86)
|
||||||
|
# ifndef _X86_
|
||||||
|
# define _c4_X86_
|
||||||
|
# define _X86_
|
||||||
|
# endif
|
||||||
|
#elif defined(_M_ARM64)
|
||||||
|
# ifndef _ARM64_
|
||||||
|
# define _c4_ARM64_
|
||||||
|
# define _ARM64_
|
||||||
|
# endif
|
||||||
|
#elif defined(_M_ARM)
|
||||||
|
# ifndef _ARM_
|
||||||
|
# define _c4_ARM_
|
||||||
|
# define _ARM_
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
# define _c4_NOMINMAX
|
||||||
|
# define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NOGDI
|
||||||
|
# define _c4_NOGDI
|
||||||
|
# define NOGDI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VC_EXTRALEAN
|
||||||
|
# define _c4_VC_EXTRALEAN
|
||||||
|
# define VC_EXTRALEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define _c4_WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If defined, the following flags inhibit definition
|
||||||
|
* of the indicated items.
|
||||||
|
*
|
||||||
|
* NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
|
||||||
|
* NOVIRTUALKEYCODES - VK_*
|
||||||
|
* NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
|
||||||
|
* NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
|
||||||
|
* NOSYSMETRICS - SM_*
|
||||||
|
* NOMENUS - MF_*
|
||||||
|
* NOICONS - IDI_*
|
||||||
|
* NOKEYSTATES - MK_*
|
||||||
|
* NOSYSCOMMANDS - SC_*
|
||||||
|
* NORASTEROPS - Binary and Tertiary raster ops
|
||||||
|
* NOSHOWWINDOW - SW_*
|
||||||
|
* OEMRESOURCE - OEM Resource values
|
||||||
|
* NOATOM - Atom Manager routines
|
||||||
|
* NOCLIPBOARD - Clipboard routines
|
||||||
|
* NOCOLOR - Screen colors
|
||||||
|
* NOCTLMGR - Control and Dialog routines
|
||||||
|
* NODRAWTEXT - DrawText() and DT_*
|
||||||
|
* NOGDI - All GDI defines and routines
|
||||||
|
* NOKERNEL - All KERNEL defines and routines
|
||||||
|
* NOUSER - All USER defines and routines
|
||||||
|
* NONLS - All NLS defines and routines
|
||||||
|
* NOMB - MB_* and MessageBox()
|
||||||
|
* NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
|
||||||
|
* NOMETAFILE - typedef METAFILEPICT
|
||||||
|
* NOMINMAX - Macros min(a,b) and max(a,b)
|
||||||
|
* NOMSG - typedef MSG and associated routines
|
||||||
|
* NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
|
||||||
|
* NOSCROLL - SB_* and scrolling routines
|
||||||
|
* NOSERVICE - All Service Controller routines, SERVICE_ equates, etc.
|
||||||
|
* NOSOUND - Sound driver routines
|
||||||
|
* NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
|
||||||
|
* NOWH - SetWindowsHook and WH_*
|
||||||
|
* NOWINOFFSETS - GWL_*, GCL_*, associated routines
|
||||||
|
* NOCOMM - COMM driver routines
|
||||||
|
* NOKANJI - Kanji support stuff.
|
||||||
|
* NOHELP - Help engine interface.
|
||||||
|
* NOPROFILER - Profiler interface.
|
||||||
|
* NODEFERWINDOWPOS - DeferWindowPos routines
|
||||||
|
* NOMCX - Modem Configuration Extensions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* defined(_WIN64) || defined(_WIN32) */
|
||||||
|
|
||||||
|
#endif /* _C4_WINDOWS_PUSH_HPP_ */
|
282
dep/rapidyaml/include/c4/yml/common.hpp
Normal file
282
dep/rapidyaml/include/c4/yml/common.hpp
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
#ifndef _C4_YML_COMMON_HPP_
|
||||||
|
#define _C4_YML_COMMON_HPP_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <c4/substr.hpp>
|
||||||
|
#include <c4/yml/export.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RYML_USE_ASSERT
|
||||||
|
# define RYML_USE_ASSERT C4_USE_ASSERT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if RYML_USE_ASSERT
|
||||||
|
# define RYML_ASSERT(cond) RYML_CHECK(cond)
|
||||||
|
# define RYML_ASSERT_MSG(cond, msg) RYML_CHECK_MSG(cond, msg)
|
||||||
|
#else
|
||||||
|
# define RYML_ASSERT(cond)
|
||||||
|
# define RYML_ASSERT_MSG(cond, msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(NDEBUG) || defined(C4_NO_DEBUG_BREAK)
|
||||||
|
# define RYML_DEBUG_BREAK()
|
||||||
|
#else
|
||||||
|
# define RYML_DEBUG_BREAK() \
|
||||||
|
{ \
|
||||||
|
if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
|
||||||
|
{ \
|
||||||
|
C4_DEBUG_BREAK(); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define RYML_CHECK(cond) \
|
||||||
|
do { \
|
||||||
|
if(!(cond)) \
|
||||||
|
{ \
|
||||||
|
RYML_DEBUG_BREAK() \
|
||||||
|
c4::yml::error("check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define RYML_CHECK_MSG(cond, msg) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if(!(cond)) \
|
||||||
|
{ \
|
||||||
|
RYML_DEBUG_BREAK() \
|
||||||
|
c4::yml::error(msg ": check failed: " #cond, c4::yml::Location(__FILE__, __LINE__, 0)); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#if C4_CPP >= 14
|
||||||
|
# define RYML_DEPRECATED(msg) [[deprecated(msg)]]
|
||||||
|
#else
|
||||||
|
# if defined(_MSC_VER)
|
||||||
|
# define RYML_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||||
|
# else // defined(__GNUC__) || defined(__clang__)
|
||||||
|
# define RYML_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
enum : size_t {
|
||||||
|
/** a null position */
|
||||||
|
npos = size_t(-1),
|
||||||
|
/** an index to none */
|
||||||
|
NONE = size_t(-1)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//! holds a position into a source buffer
|
||||||
|
struct RYML_EXPORT LineCol
|
||||||
|
{
|
||||||
|
//! number of bytes from the beginning of the source buffer
|
||||||
|
size_t offset;
|
||||||
|
//! line
|
||||||
|
size_t line;
|
||||||
|
//! column
|
||||||
|
size_t col;
|
||||||
|
|
||||||
|
LineCol() : offset(), line(), col() {}
|
||||||
|
//! construct from line and column
|
||||||
|
LineCol(size_t l, size_t c) : offset(0), line(l), col(c) {}
|
||||||
|
//! construct from offset, line and column
|
||||||
|
LineCol(size_t o, size_t l, size_t c) : offset(o), line(l), col(c) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! a source file position
|
||||||
|
struct RYML_EXPORT Location : public LineCol
|
||||||
|
{
|
||||||
|
csubstr name;
|
||||||
|
|
||||||
|
operator bool () const { return !name.empty() || line != 0 || offset != 0; }
|
||||||
|
|
||||||
|
Location() : LineCol(), name() {}
|
||||||
|
Location( size_t l, size_t c) : LineCol{ l, c}, name( ) {}
|
||||||
|
Location( csubstr n, size_t l, size_t c) : LineCol{ l, c}, name(n) {}
|
||||||
|
Location( csubstr n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(n) {}
|
||||||
|
Location(const char *n, size_t l, size_t c) : LineCol{ l, c}, name(to_csubstr(n)) {}
|
||||||
|
Location(const char *n, size_t b, size_t l, size_t c) : LineCol{b, l, c}, name(to_csubstr(n)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** the type of the function used to report errors. This function must
|
||||||
|
* interrupt execution, either by raising an exception or calling
|
||||||
|
* std::abort().
|
||||||
|
*
|
||||||
|
* @warning the error callback must never return: it must either abort
|
||||||
|
* or throw an exception. Otherwise, the parser will enter into an
|
||||||
|
* infinite loop, or the program may crash. */
|
||||||
|
using pfn_error = void (*)(const char* msg, size_t msg_len, Location location, void *user_data);
|
||||||
|
/** the type of the function used to allocate memory */
|
||||||
|
using pfn_allocate = void* (*)(size_t len, void* hint, void *user_data);
|
||||||
|
/** the type of the function used to free memory */
|
||||||
|
using pfn_free = void (*)(void* mem, size_t size, void *user_data);
|
||||||
|
|
||||||
|
/** trigger an error: call the current error callback. */
|
||||||
|
RYML_EXPORT void error(const char *msg, size_t msg_len, Location loc);
|
||||||
|
/** @overload error */
|
||||||
|
inline void error(const char *msg, size_t msg_len)
|
||||||
|
{
|
||||||
|
error(msg, msg_len, Location{});
|
||||||
|
}
|
||||||
|
/** @overload error */
|
||||||
|
template<size_t N>
|
||||||
|
inline void error(const char (&msg)[N], Location loc)
|
||||||
|
{
|
||||||
|
error(msg, N-1, loc);
|
||||||
|
}
|
||||||
|
/** @overload error */
|
||||||
|
template<size_t N>
|
||||||
|
inline void error(const char (&msg)[N])
|
||||||
|
{
|
||||||
|
error(msg, N-1, Location{});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** a c-style callbacks class
|
||||||
|
*
|
||||||
|
* @warning the error callback must never return: it must either abort
|
||||||
|
* or throw an exception. Otherwise, the parser will enter into an
|
||||||
|
* infinite loop, or the program may crash. */
|
||||||
|
struct RYML_EXPORT Callbacks
|
||||||
|
{
|
||||||
|
void * m_user_data;
|
||||||
|
pfn_allocate m_allocate;
|
||||||
|
pfn_free m_free;
|
||||||
|
pfn_error m_error;
|
||||||
|
|
||||||
|
Callbacks();
|
||||||
|
Callbacks(void *user_data, pfn_allocate alloc, pfn_free free, pfn_error error_);
|
||||||
|
|
||||||
|
bool operator!= (Callbacks const& that) const { return !operator==(that); }
|
||||||
|
bool operator== (Callbacks const& that) const
|
||||||
|
{
|
||||||
|
return (m_user_data == that.m_user_data &&
|
||||||
|
m_allocate == that.m_allocate &&
|
||||||
|
m_free == that.m_free &&
|
||||||
|
m_error == that.m_error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** set the global callbacks.
|
||||||
|
*
|
||||||
|
* @warning the error callback must never return: it must either abort
|
||||||
|
* or throw an exception. Otherwise, the parser will enter into an
|
||||||
|
* infinite loop, or the program may crash. */
|
||||||
|
RYML_EXPORT void set_callbacks(Callbacks const& c);
|
||||||
|
/// get the global callbacks
|
||||||
|
RYML_EXPORT Callbacks const& get_callbacks();
|
||||||
|
/// set the global callbacks back to their defaults
|
||||||
|
RYML_EXPORT void reset_callbacks();
|
||||||
|
|
||||||
|
/// @cond dev
|
||||||
|
#define _RYML_CB_ERR(cb, msg_literal) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
const char msg[] = msg_literal; \
|
||||||
|
RYML_DEBUG_BREAK() \
|
||||||
|
(cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \
|
||||||
|
} while(0)
|
||||||
|
#define _RYML_CB_CHECK(cb, cond) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if(!(cond)) \
|
||||||
|
{ \
|
||||||
|
const char msg[] = "check failed: " #cond; \
|
||||||
|
RYML_DEBUG_BREAK() \
|
||||||
|
(cb).m_error(msg, sizeof(msg), c4::yml::Location(__FILE__, 0, __LINE__, 0), (cb).m_user_data); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#ifdef RYML_USE_ASSERT
|
||||||
|
#define _RYML_CB_ASSERT(cb, cond) _RYML_CB_CHECK((cb), (cond))
|
||||||
|
#else
|
||||||
|
#define _RYML_CB_ASSERT(cb, cond) do {} while(0)
|
||||||
|
#endif
|
||||||
|
#define _RYML_CB_ALLOC_HINT(cb, T, num, hint) (T*) (cb).m_allocate((num) * sizeof(T), (hint), (cb).m_user_data)
|
||||||
|
#define _RYML_CB_ALLOC(cb, T, num) _RYML_CB_ALLOC_HINT((cb), (T), (num), nullptr)
|
||||||
|
#define _RYML_CB_FREE(cb, buf, T, num) \
|
||||||
|
do { \
|
||||||
|
(cb).m_free((buf), (num) * sizeof(T), (cb).m_user_data); \
|
||||||
|
(buf) = nullptr; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<int8_t signedval, uint8_t unsignedval>
|
||||||
|
struct _charconstant_t
|
||||||
|
: public std::conditional<std::is_signed<char>::value,
|
||||||
|
std::integral_constant<int8_t, signedval>,
|
||||||
|
std::integral_constant<uint8_t, unsignedval>>::type
|
||||||
|
{};
|
||||||
|
#define _RYML_CHCONST(signedval, unsignedval) ::c4::yml::detail::_charconstant_t<INT8_C(signedval), UINT8_C(unsignedval)>::value
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
struct _SubstrWriter
|
||||||
|
{
|
||||||
|
substr buf;
|
||||||
|
size_t pos;
|
||||||
|
_SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) {}
|
||||||
|
void append(csubstr s)
|
||||||
|
{
|
||||||
|
C4_ASSERT(!s.overlaps(buf));
|
||||||
|
if(pos + s.len <= buf.len)
|
||||||
|
memcpy(buf.str + pos, s.str, s.len);
|
||||||
|
pos += s.len;
|
||||||
|
}
|
||||||
|
void append(char c)
|
||||||
|
{
|
||||||
|
if(pos < buf.len)
|
||||||
|
buf.str[pos] = c;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
void append_n(char c, size_t numtimes)
|
||||||
|
{
|
||||||
|
if(pos + numtimes < buf.len)
|
||||||
|
memset(buf.str + pos, c, numtimes);
|
||||||
|
pos += numtimes;
|
||||||
|
}
|
||||||
|
size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; }
|
||||||
|
size_t excess() const { return pos > buf.len ? pos - buf.len : 0; }
|
||||||
|
//! get the part written so far
|
||||||
|
csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
|
||||||
|
//! get the part that is still free to write to (the remainder)
|
||||||
|
substr rem() { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
|
||||||
|
|
||||||
|
size_t advance(size_t more) { pos += more; return pos; }
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_YML_COMMON_HPP_ */
|
137
dep/rapidyaml/include/c4/yml/detail/parser_dbg.hpp
Normal file
137
dep/rapidyaml/include/c4/yml/detail/parser_dbg.hpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#ifndef _C4_YML_DETAIL_PARSER_DBG_HPP_
|
||||||
|
#define _C4_YML_DETAIL_PARSER_DBG_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_COMMON_HPP_
|
||||||
|
#include "../common.hpp"
|
||||||
|
#endif
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some debugging scaffolds
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4068/*unknown pragma*/)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||||
|
//#pragma GCC diagnostic ignored "-Wpragma-system-header-outside-header"
|
||||||
|
#pragma GCC system_header
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Werror"
|
||||||
|
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||||
|
|
||||||
|
// some debugging scaffolds
|
||||||
|
#ifdef RYML_DBG
|
||||||
|
#include <c4/dump.hpp>
|
||||||
|
namespace c4 {
|
||||||
|
inline void _dbg_dumper(csubstr s) { fwrite(s.str, 1, s.len, stdout); };
|
||||||
|
template<class ...Args>
|
||||||
|
void _dbg_printf(c4::csubstr fmt, Args&& ...args)
|
||||||
|
{
|
||||||
|
static char writebuf[256];
|
||||||
|
auto results = c4::format_dump_resume<&_dbg_dumper>(writebuf, fmt, std::forward<Args>(args)...);
|
||||||
|
// resume writing if the results failed to fit the buffer
|
||||||
|
if(C4_UNLIKELY(results.bufsize > sizeof(writebuf))) // bufsize will be that of the largest element serialized. Eg int(1), will require 1 byte.
|
||||||
|
{
|
||||||
|
results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
|
||||||
|
if(C4_UNLIKELY(results.bufsize > sizeof(writebuf)))
|
||||||
|
{
|
||||||
|
results = format_dump_resume<&_dbg_dumper>(results, writebuf, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
# define _c4dbgt(fmt, ...) this->_dbg ("{}:{}: " fmt , __FILE__, __LINE__, ## __VA_ARGS__)
|
||||||
|
# define _c4dbgpf(fmt, ...) _dbg_printf("{}:{}: " fmt "\n", __FILE__, __LINE__, ## __VA_ARGS__)
|
||||||
|
# define _c4dbgp(msg) _dbg_printf("{}:{}: " msg "\n", __FILE__, __LINE__ )
|
||||||
|
# define _c4dbgq(msg) _dbg_printf(msg "\n")
|
||||||
|
# define _c4err(fmt, ...) \
|
||||||
|
do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
|
||||||
|
this->_err("ERROR:\n" "{}:{}: " fmt, __FILE__, __LINE__, ## __VA_ARGS__); } while(0)
|
||||||
|
#else
|
||||||
|
# define _c4dbgt(fmt, ...)
|
||||||
|
# define _c4dbgpf(fmt, ...)
|
||||||
|
# define _c4dbgp(msg)
|
||||||
|
# define _c4dbgq(msg)
|
||||||
|
# define _c4err(fmt, ...) \
|
||||||
|
do { if(c4::is_debugger_attached()) { C4_DEBUG_BREAK(); } \
|
||||||
|
this->_err("ERROR: " fmt, ## __VA_ARGS__); } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _c4prsp(sp) sp
|
||||||
|
#define _c4presc(s) __c4presc(s.str, s.len)
|
||||||
|
inline c4::csubstr _c4prc(const char &C4_RESTRICT c)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '\n': return c4::csubstr("\\n");
|
||||||
|
case '\t': return c4::csubstr("\\t");
|
||||||
|
case '\0': return c4::csubstr("\\0");
|
||||||
|
case '\r': return c4::csubstr("\\r");
|
||||||
|
case '\f': return c4::csubstr("\\f");
|
||||||
|
case '\b': return c4::csubstr("\\b");
|
||||||
|
case '\v': return c4::csubstr("\\v");
|
||||||
|
case '\a': return c4::csubstr("\\a");
|
||||||
|
default: return c4::csubstr(&c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void __c4presc(const char *s, size_t len)
|
||||||
|
{
|
||||||
|
size_t prev = 0;
|
||||||
|
for(size_t i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
switch(s[i])
|
||||||
|
{
|
||||||
|
case '\n' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('n'); putchar('\n'); prev = i+1; break;
|
||||||
|
case '\t' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('t'); prev = i+1; break;
|
||||||
|
case '\0' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('0'); prev = i+1; break;
|
||||||
|
case '\r' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('r'); prev = i+1; break;
|
||||||
|
case '\f' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('f'); prev = i+1; break;
|
||||||
|
case '\b' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('b'); prev = i+1; break;
|
||||||
|
case '\v' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('v'); prev = i+1; break;
|
||||||
|
case '\a' : fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('a'); prev = i+1; break;
|
||||||
|
case '\x1b': fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('e'); prev = i+1; break;
|
||||||
|
case -0x3e/*0xc2u*/:
|
||||||
|
if(i+1 < len)
|
||||||
|
{
|
||||||
|
if(s[i+1] == -0x60/*0xa0u*/)
|
||||||
|
{
|
||||||
|
fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('_'); prev = i+2; ++i;
|
||||||
|
}
|
||||||
|
else if(s[i+1] == -0x7b/*0x85u*/)
|
||||||
|
{
|
||||||
|
fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('N'); prev = i+2; ++i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case -0x1e/*0xe2u*/:
|
||||||
|
if(i+2 < len && s[i+1] == -0x80/*0x80u*/)
|
||||||
|
{
|
||||||
|
if(s[i+2] == -0x58/*0xa8u*/)
|
||||||
|
{
|
||||||
|
fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('L'); prev = i+3; i += 2;
|
||||||
|
}
|
||||||
|
else if(s[i+2] == -0x57/*0xa9u*/)
|
||||||
|
{
|
||||||
|
fwrite(s+prev, 1, i-prev, stdout); putchar('\\'); putchar('P'); prev = i+3; i += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fwrite(s + prev, 1, len - prev, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _C4_YML_DETAIL_PARSER_DBG_HPP_ */
|
274
dep/rapidyaml/include/c4/yml/detail/stack.hpp
Normal file
274
dep/rapidyaml/include/c4/yml/detail/stack.hpp
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
#ifndef _C4_YML_DETAIL_STACK_HPP_
|
||||||
|
#define _C4_YML_DETAIL_STACK_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_COMMON_HPP_
|
||||||
|
#include "../common.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RYML_DBG
|
||||||
|
# include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/** A lightweight contiguous stack with SSO. This avoids a dependency on std. */
|
||||||
|
template<class T, size_t N=16>
|
||||||
|
class stack
|
||||||
|
{
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
|
||||||
|
static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");
|
||||||
|
|
||||||
|
enum : size_t { sso_size = N };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
T m_buf[N];
|
||||||
|
T * m_stack;
|
||||||
|
size_t m_size;
|
||||||
|
size_t m_capacity;
|
||||||
|
Callbacks m_callbacks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
constexpr static bool is_contiguous() { return true; }
|
||||||
|
|
||||||
|
stack(Callbacks const& cb)
|
||||||
|
: m_buf()
|
||||||
|
, m_stack(m_buf)
|
||||||
|
, m_size(0)
|
||||||
|
, m_capacity(N)
|
||||||
|
, m_callbacks(cb) {}
|
||||||
|
stack() : stack(get_callbacks()) {}
|
||||||
|
~stack()
|
||||||
|
{
|
||||||
|
_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
stack(stack const& that) noexcept : stack(that.m_callbacks)
|
||||||
|
{
|
||||||
|
resize(that.m_size);
|
||||||
|
_cp(&that);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack(stack &&that) noexcept : stack(that.m_callbacks)
|
||||||
|
{
|
||||||
|
_mv(&that);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack& operator= (stack const& that) noexcept
|
||||||
|
{
|
||||||
|
_cb(that.m_callbacks);
|
||||||
|
resize(that.m_size);
|
||||||
|
_cp(&that);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack& operator= (stack &&that) noexcept
|
||||||
|
{
|
||||||
|
_cb(that.m_callbacks);
|
||||||
|
_mv(&that);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
size_t size() const { return m_size; }
|
||||||
|
size_t empty() const { return m_size == 0; }
|
||||||
|
size_t capacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(size_t sz)
|
||||||
|
{
|
||||||
|
reserve(sz);
|
||||||
|
m_size = sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t sz);
|
||||||
|
|
||||||
|
void push(T const& C4_RESTRICT n)
|
||||||
|
{
|
||||||
|
RYML_ASSERT((const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);
|
||||||
|
if(m_size == m_capacity)
|
||||||
|
{
|
||||||
|
size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||||
|
reserve(cap);
|
||||||
|
}
|
||||||
|
m_stack[m_size] = n;
|
||||||
|
++m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_top()
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_size > 0);
|
||||||
|
if(m_size == m_capacity)
|
||||||
|
{
|
||||||
|
size_t cap = m_capacity == 0 ? N : 2 * m_capacity;
|
||||||
|
reserve(cap);
|
||||||
|
}
|
||||||
|
m_stack[m_size] = m_stack[m_size - 1];
|
||||||
|
++m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& C4_RESTRICT pop()
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_size > 0);
|
||||||
|
--m_size;
|
||||||
|
return m_stack[m_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
|
||||||
|
C4_ALWAYS_INLINE T & C4_RESTRICT top() { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { RYML_ASSERT(m_size > 0); return m_stack[0]; }
|
||||||
|
C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { RYML_ASSERT(m_size > 0); return m_stack[0]; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE T const& C4_RESTRICT top(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
|
||||||
|
C4_ALWAYS_INLINE T & C4_RESTRICT top(size_t i) { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||||
|
C4_ALWAYS_INLINE T & C4_RESTRICT bottom(size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||||
|
C4_ALWAYS_INLINE T & C4_RESTRICT operator[](size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
using iterator = T *;
|
||||||
|
using const_iterator = T const *;
|
||||||
|
|
||||||
|
iterator begin() { return m_stack; }
|
||||||
|
iterator end () { return m_stack + m_size; }
|
||||||
|
|
||||||
|
const_iterator begin() const { return (const_iterator)m_stack; }
|
||||||
|
const_iterator end () const { return (const_iterator)m_stack + m_size; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void _free();
|
||||||
|
void _cp(stack const* C4_RESTRICT that);
|
||||||
|
void _mv(stack * that);
|
||||||
|
void _cb(Callbacks const& cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T, size_t N>
|
||||||
|
void stack<T, N>::reserve(size_t sz)
|
||||||
|
{
|
||||||
|
if(sz <= m_size)
|
||||||
|
return;
|
||||||
|
if(sz <= N)
|
||||||
|
{
|
||||||
|
m_stack = m_buf;
|
||||||
|
m_capacity = N;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
T *buf = (T*) m_callbacks.m_allocate(sz * sizeof(T), m_stack, m_callbacks.m_user_data);
|
||||||
|
memcpy(buf, m_stack, m_size * sizeof(T));
|
||||||
|
if(m_stack != m_buf)
|
||||||
|
{
|
||||||
|
m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||||
|
}
|
||||||
|
m_stack = buf;
|
||||||
|
m_capacity = sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T, size_t N>
|
||||||
|
void stack<T, N>::_free()
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_stack != nullptr); // this structure cannot be memset() to zero
|
||||||
|
if(m_stack != m_buf)
|
||||||
|
{
|
||||||
|
m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);
|
||||||
|
m_stack = m_buf;
|
||||||
|
m_size = N;
|
||||||
|
m_capacity = N;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_capacity == N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T, size_t N>
|
||||||
|
void stack<T, N>::_cp(stack const* C4_RESTRICT that)
|
||||||
|
{
|
||||||
|
if(that->m_stack != that->m_buf)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(that->m_capacity > N);
|
||||||
|
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RYML_ASSERT(that->m_capacity <= N);
|
||||||
|
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||||
|
}
|
||||||
|
memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));
|
||||||
|
m_size = that->m_size;
|
||||||
|
m_capacity = that->m_size < N ? N : that->m_size;
|
||||||
|
m_callbacks = that->m_callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T, size_t N>
|
||||||
|
void stack<T, N>::_mv(stack * that)
|
||||||
|
{
|
||||||
|
if(that->m_stack != that->m_buf)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(that->m_capacity > N);
|
||||||
|
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||||
|
m_stack = that->m_stack;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RYML_ASSERT(that->m_capacity <= N);
|
||||||
|
RYML_ASSERT(that->m_size <= that->m_capacity);
|
||||||
|
memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));
|
||||||
|
m_stack = m_buf;
|
||||||
|
}
|
||||||
|
m_size = that->m_size;
|
||||||
|
m_capacity = that->m_capacity;
|
||||||
|
m_callbacks = that->m_callbacks;
|
||||||
|
// make sure no deallocation happens on destruction
|
||||||
|
RYML_ASSERT(that->m_stack != m_buf);
|
||||||
|
that->m_stack = that->m_buf;
|
||||||
|
that->m_capacity = N;
|
||||||
|
that->m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class T, size_t N>
|
||||||
|
void stack<T, N>::_cb(Callbacks const& cb)
|
||||||
|
{
|
||||||
|
if(cb != m_callbacks)
|
||||||
|
{
|
||||||
|
_free();
|
||||||
|
m_callbacks = cb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_YML_DETAIL_STACK_HPP_ */
|
960
dep/rapidyaml/include/c4/yml/emit.def.hpp
Normal file
960
dep/rapidyaml/include/c4/yml/emit.def.hpp
Normal file
|
@ -0,0 +1,960 @@
|
||||||
|
#ifndef _C4_YML_EMIT_DEF_HPP_
|
||||||
|
#define _C4_YML_EMIT_DEF_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_EMIT_HPP_
|
||||||
|
#include "c4/yml/emit.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess)
|
||||||
|
{
|
||||||
|
if(t.empty())
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(t.callbacks(), id == NONE);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
_RYML_CB_CHECK(t.callbacks(), id < t.capacity());
|
||||||
|
m_tree = &t;
|
||||||
|
if(type == EMIT_YAML)
|
||||||
|
_emit_yaml(id);
|
||||||
|
else if(type == EMIT_JSON)
|
||||||
|
_do_visit_json(id);
|
||||||
|
else
|
||||||
|
_RYML_CB_ERR(m_tree->callbacks(), "unknown emit type");
|
||||||
|
return this->Writer::_get(error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, bool error_on_excess)
|
||||||
|
{
|
||||||
|
if(t.empty())
|
||||||
|
return {};
|
||||||
|
return this->emit_as(type, t, t.root_id(), error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
substr Emitter<Writer>::emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
|
||||||
|
return this->emit_as(type, *n.tree(), n.id(), error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_emit_yaml(size_t id)
|
||||||
|
{
|
||||||
|
// save branches in the visitor by doing the initial stream/doc
|
||||||
|
// logic here, sparing the need to check stream/val/keyval inside
|
||||||
|
// the visitor functions
|
||||||
|
auto dispatch = [this](size_t node){
|
||||||
|
NodeType ty = m_tree->type(node);
|
||||||
|
if(ty.marked_flow_sl())
|
||||||
|
_do_visit_flow_sl(node, 0);
|
||||||
|
else if(ty.marked_flow_ml())
|
||||||
|
_do_visit_flow_ml(node, 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_do_visit_block(node, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(!m_tree->is_root(id))
|
||||||
|
{
|
||||||
|
if(m_tree->is_container(id) && !m_tree->type(id).marked_flow())
|
||||||
|
{
|
||||||
|
size_t ilevel = 0;
|
||||||
|
if(m_tree->has_key(id))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(m_tree->key(id));
|
||||||
|
this->Writer::_do_write(":\n");
|
||||||
|
++ilevel;
|
||||||
|
}
|
||||||
|
_do_visit_block_container(id, ilevel, ilevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *btd = m_tree->tag_directives().b;
|
||||||
|
auto *etd = m_tree->tag_directives().e;
|
||||||
|
auto write_tag_directives = [&btd, etd, this](size_t next_node){
|
||||||
|
auto end = btd;
|
||||||
|
while(end < etd)
|
||||||
|
{
|
||||||
|
if(end->next_node_id > next_node)
|
||||||
|
break;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
for( ; btd != end; ++btd)
|
||||||
|
{
|
||||||
|
if(next_node != m_tree->first_child(m_tree->parent(next_node)))
|
||||||
|
this->Writer::_do_write("...\n");
|
||||||
|
this->Writer::_do_write("%TAG ");
|
||||||
|
this->Writer::_do_write(btd->handle);
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
this->Writer::_do_write(btd->prefix);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(m_tree->is_stream(id))
|
||||||
|
{
|
||||||
|
if(m_tree->first_child(id) != NONE)
|
||||||
|
write_tag_directives(m_tree->first_child(id));
|
||||||
|
for(size_t child = m_tree->first_child(id); child != NONE; child = m_tree->next_sibling(child))
|
||||||
|
{
|
||||||
|
dispatch(child);
|
||||||
|
if(m_tree->next_sibling(child) != NONE)
|
||||||
|
write_tag_directives(m_tree->next_sibling(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(m_tree->is_container(id))
|
||||||
|
{
|
||||||
|
dispatch(id);
|
||||||
|
}
|
||||||
|
else if(m_tree->is_doc(id))
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->is_container(id)); // checked above
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_val(id)); // so it must be a val
|
||||||
|
_write_doc(id);
|
||||||
|
}
|
||||||
|
else if(m_tree->is_keyval(id))
|
||||||
|
{
|
||||||
|
_writek(id, 0);
|
||||||
|
this->Writer::_do_write(": ");
|
||||||
|
_writev(id, 0);
|
||||||
|
if(!m_tree->type(id).marked_flow())
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else if(m_tree->is_val(id))
|
||||||
|
{
|
||||||
|
//this->Writer::_do_write("- ");
|
||||||
|
_writev(id, 0);
|
||||||
|
if(!m_tree->type(id).marked_flow())
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else if(m_tree->type(id) == NOTYPE)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_RYML_CB_ERR(m_tree->callbacks(), "unknown type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_doc(size_t id)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_tree->is_doc(id));
|
||||||
|
if(!m_tree->is_root(id))
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_tree->is_stream(m_tree->parent(id)));
|
||||||
|
this->Writer::_do_write("---");
|
||||||
|
}
|
||||||
|
if(!m_tree->has_val(id)) // this is more frequent
|
||||||
|
{
|
||||||
|
if(m_tree->has_val_tag(id))
|
||||||
|
{
|
||||||
|
if(!m_tree->is_root(id))
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
_write_tag(m_tree->val_tag(id));
|
||||||
|
}
|
||||||
|
if(m_tree->has_val_anchor(id))
|
||||||
|
{
|
||||||
|
if(!m_tree->is_root(id))
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
this->Writer::_do_write('&');
|
||||||
|
this->Writer::_do_write(m_tree->val_anchor(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // docval
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_tree->has_val(id));
|
||||||
|
RYML_ASSERT(!m_tree->has_key(id));
|
||||||
|
if(!m_tree->is_root(id))
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
_writev(id, 0);
|
||||||
|
}
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_do_visit_flow_sl(size_t node, size_t ilevel)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(!m_tree->is_stream(node));
|
||||||
|
RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
|
||||||
|
RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
|
||||||
|
|
||||||
|
if(m_tree->is_doc(node))
|
||||||
|
{
|
||||||
|
_write_doc(node);
|
||||||
|
if(!m_tree->has_children(node))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(m_tree->is_container(node))
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node));
|
||||||
|
|
||||||
|
bool spc = false; // write a space
|
||||||
|
|
||||||
|
if(m_tree->has_key(node))
|
||||||
|
{
|
||||||
|
_writek(node, ilevel);
|
||||||
|
this->Writer::_do_write(':');
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->has_val_tag(node))
|
||||||
|
{
|
||||||
|
if(spc)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
_write_tag(m_tree->val_tag(node));
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->has_val_anchor(node))
|
||||||
|
{
|
||||||
|
if(spc)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
this->Writer::_do_write('&');
|
||||||
|
this->Writer::_do_write(m_tree->val_anchor(node));
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(spc)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
|
||||||
|
if(m_tree->is_map(node))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('{');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_seq(node));
|
||||||
|
this->Writer::_do_write('[');
|
||||||
|
}
|
||||||
|
} // container
|
||||||
|
|
||||||
|
for(size_t child = m_tree->first_child(node), count = 0; child != NONE; child = m_tree->next_sibling(child))
|
||||||
|
{
|
||||||
|
if(count++)
|
||||||
|
this->Writer::_do_write(',');
|
||||||
|
if(m_tree->is_keyval(child))
|
||||||
|
{
|
||||||
|
_writek(child, ilevel);
|
||||||
|
this->Writer::_do_write(": ");
|
||||||
|
_writev(child, ilevel);
|
||||||
|
}
|
||||||
|
else if(m_tree->is_val(child))
|
||||||
|
{
|
||||||
|
_writev(child, ilevel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// with single-line flow, we can never go back to block
|
||||||
|
_do_visit_flow_sl(child, ilevel + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->is_map(node))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('}');
|
||||||
|
}
|
||||||
|
else if(m_tree->is_seq(node))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_do_visit_flow_ml(size_t id, size_t ilevel, size_t do_indent)
|
||||||
|
{
|
||||||
|
C4_UNUSED(id);
|
||||||
|
C4_UNUSED(ilevel);
|
||||||
|
C4_UNUSED(do_indent);
|
||||||
|
RYML_CHECK(false/*not implemented*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_do_visit_block_container(size_t node, size_t next_level, size_t do_indent)
|
||||||
|
{
|
||||||
|
RepC ind = indent_to(do_indent * next_level);
|
||||||
|
|
||||||
|
if(m_tree->is_seq(node))
|
||||||
|
{
|
||||||
|
for(size_t child = m_tree->first_child(node); child != NONE; child = m_tree->next_sibling(child))
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), !m_tree->has_key(child));
|
||||||
|
if(m_tree->is_val(child))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
this->Writer::_do_write("- ");
|
||||||
|
_writev(child, next_level);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(child));
|
||||||
|
NodeType ty = m_tree->type(child);
|
||||||
|
if(ty.marked_flow_sl())
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
this->Writer::_do_write("- ");
|
||||||
|
_do_visit_flow_sl(child, 0u);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else if(ty.marked_flow_ml())
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
this->Writer::_do_write("- ");
|
||||||
|
_do_visit_flow_ml(child, next_level, do_indent);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_do_visit_block(child, next_level, do_indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_indent = true;
|
||||||
|
ind = indent_to(do_indent * next_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // map
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_map(node));
|
||||||
|
for(size_t ich = m_tree->first_child(node); ich != NONE; ich = m_tree->next_sibling(ich))
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->has_key(ich));
|
||||||
|
if(m_tree->is_keyval(ich))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
_writek(ich, next_level);
|
||||||
|
this->Writer::_do_write(": ");
|
||||||
|
_writev(ich, next_level);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), m_tree->is_container(ich));
|
||||||
|
NodeType ty = m_tree->type(ich);
|
||||||
|
if(ty.marked_flow_sl())
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
_do_visit_flow_sl(ich, 0u);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else if(ty.marked_flow_ml())
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
_do_visit_flow_ml(ich, 0u);
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_do_visit_block(ich, next_level, do_indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_indent = true;
|
||||||
|
ind = indent_to(do_indent * next_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_do_visit_block(size_t node, size_t ilevel, size_t do_indent)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(!m_tree->is_stream(node));
|
||||||
|
RYML_ASSERT(m_tree->is_container(node) || m_tree->is_doc(node));
|
||||||
|
RYML_ASSERT(m_tree->is_root(node) || (m_tree->parent_is_map(node) || m_tree->parent_is_seq(node)));
|
||||||
|
RepC ind = indent_to(do_indent * ilevel);
|
||||||
|
|
||||||
|
if(m_tree->is_doc(node))
|
||||||
|
{
|
||||||
|
_write_doc(node);
|
||||||
|
if(!m_tree->has_children(node))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(m_tree->is_container(node))
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_tree->is_map(node) || m_tree->is_seq(node));
|
||||||
|
|
||||||
|
bool spc = false; // write a space
|
||||||
|
bool nl = false; // write a newline
|
||||||
|
|
||||||
|
if(m_tree->has_key(node))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
_writek(node, ilevel);
|
||||||
|
this->Writer::_do_write(':');
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
else if(!m_tree->is_root(node))
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(ind);
|
||||||
|
this->Writer::_do_write('-');
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->has_val_tag(node))
|
||||||
|
{
|
||||||
|
if(spc)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
_write_tag(m_tree->val_tag(node));
|
||||||
|
spc = true;
|
||||||
|
nl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->has_val_anchor(node))
|
||||||
|
{
|
||||||
|
if(spc)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
this->Writer::_do_write('&');
|
||||||
|
this->Writer::_do_write(m_tree->val_anchor(node));
|
||||||
|
spc = true;
|
||||||
|
nl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->has_children(node))
|
||||||
|
{
|
||||||
|
if(m_tree->has_key(node))
|
||||||
|
nl = true;
|
||||||
|
else
|
||||||
|
if(!m_tree->is_root(node) && !nl)
|
||||||
|
spc = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(m_tree->is_seq(node))
|
||||||
|
this->Writer::_do_write(" []\n");
|
||||||
|
else if(m_tree->is_map(node))
|
||||||
|
this->Writer::_do_write(" {}\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(spc && !nl)
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
|
||||||
|
do_indent = 0;
|
||||||
|
if(nl)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
do_indent = 1;
|
||||||
|
}
|
||||||
|
} // container
|
||||||
|
|
||||||
|
size_t next_level = ilevel + 1;
|
||||||
|
if(m_tree->is_root(node) || m_tree->is_doc(node))
|
||||||
|
next_level = ilevel; // do not indent at top level
|
||||||
|
|
||||||
|
_do_visit_block_container(node, next_level, do_indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_do_visit_json(size_t id)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(m_tree->callbacks(), !m_tree->is_stream(id)); // JSON does not have streams
|
||||||
|
if(m_tree->is_keyval(id))
|
||||||
|
{
|
||||||
|
_writek_json(id);
|
||||||
|
this->Writer::_do_write(": ");
|
||||||
|
_writev_json(id);
|
||||||
|
}
|
||||||
|
else if(m_tree->is_val(id))
|
||||||
|
{
|
||||||
|
_writev_json(id);
|
||||||
|
}
|
||||||
|
else if(m_tree->is_container(id))
|
||||||
|
{
|
||||||
|
if(m_tree->has_key(id))
|
||||||
|
{
|
||||||
|
_writek_json(id);
|
||||||
|
this->Writer::_do_write(": ");
|
||||||
|
}
|
||||||
|
if(m_tree->is_seq(id))
|
||||||
|
this->Writer::_do_write('[');
|
||||||
|
else if(m_tree->is_map(id))
|
||||||
|
this->Writer::_do_write('{');
|
||||||
|
} // container
|
||||||
|
|
||||||
|
for(size_t ich = m_tree->first_child(id); ich != NONE; ich = m_tree->next_sibling(ich))
|
||||||
|
{
|
||||||
|
if(ich != m_tree->first_child(id))
|
||||||
|
this->Writer::_do_write(',');
|
||||||
|
_do_visit_json(ich);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_tree->is_seq(id))
|
||||||
|
this->Writer::_do_write(']');
|
||||||
|
else if(m_tree->is_map(id))
|
||||||
|
this->Writer::_do_write('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t ilevel)
|
||||||
|
{
|
||||||
|
if( ! sc.tag.empty())
|
||||||
|
{
|
||||||
|
_write_tag(sc.tag);
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
}
|
||||||
|
if(flags.has_anchor())
|
||||||
|
{
|
||||||
|
RYML_ASSERT(flags.is_ref() != flags.has_anchor());
|
||||||
|
RYML_ASSERT( ! sc.anchor.empty());
|
||||||
|
this->Writer::_do_write('&');
|
||||||
|
this->Writer::_do_write(sc.anchor);
|
||||||
|
this->Writer::_do_write(' ');
|
||||||
|
}
|
||||||
|
else if(flags.is_ref())
|
||||||
|
{
|
||||||
|
if(sc.anchor != "<<")
|
||||||
|
this->Writer::_do_write('*');
|
||||||
|
this->Writer::_do_write(sc.anchor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the style flags only have one of KEY or VAL
|
||||||
|
_RYML_CB_ASSERT(m_tree->callbacks(), ((flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE)) == 0) || (((flags&_WIP_KEY_STYLE) == 0) != ((flags&_WIP_VAL_STYLE) == 0)));
|
||||||
|
|
||||||
|
auto style_marks = flags & (_WIP_KEY_STYLE|_WIP_VAL_STYLE);
|
||||||
|
if(style_marks & (_WIP_KEY_LITERAL|_WIP_VAL_LITERAL))
|
||||||
|
{
|
||||||
|
_write_scalar_literal(sc.scalar, ilevel, flags.has_key());
|
||||||
|
}
|
||||||
|
else if(style_marks & (_WIP_KEY_FOLDED|_WIP_VAL_FOLDED))
|
||||||
|
{
|
||||||
|
_write_scalar_folded(sc.scalar, ilevel, flags.has_key());
|
||||||
|
}
|
||||||
|
else if(style_marks & (_WIP_KEY_SQUO|_WIP_VAL_SQUO))
|
||||||
|
{
|
||||||
|
_write_scalar_squo(sc.scalar, ilevel);
|
||||||
|
}
|
||||||
|
else if(style_marks & (_WIP_KEY_DQUO|_WIP_VAL_DQUO))
|
||||||
|
{
|
||||||
|
_write_scalar_dquo(sc.scalar, ilevel);
|
||||||
|
}
|
||||||
|
else if(style_marks & (_WIP_KEY_PLAIN|_WIP_VAL_PLAIN))
|
||||||
|
{
|
||||||
|
_write_scalar_plain(sc.scalar, ilevel);
|
||||||
|
}
|
||||||
|
else if(!style_marks)
|
||||||
|
{
|
||||||
|
size_t first_non_nl = sc.scalar.first_not_of('\n');
|
||||||
|
bool all_newlines = first_non_nl == npos;
|
||||||
|
bool has_leading_ws = (!all_newlines) && sc.scalar.sub(first_non_nl).begins_with_any(" \t");
|
||||||
|
bool do_literal = ((!sc.scalar.empty() && all_newlines) || (has_leading_ws && !sc.scalar.trim(' ').empty()));
|
||||||
|
if(do_literal)
|
||||||
|
{
|
||||||
|
_write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < sc.scalar.len; ++i)
|
||||||
|
{
|
||||||
|
if(sc.scalar.str[i] == '\n')
|
||||||
|
{
|
||||||
|
_write_scalar_literal(sc.scalar, ilevel, flags.has_key(), /*explicit_indentation*/has_leading_ws);
|
||||||
|
goto wrote_special;
|
||||||
|
}
|
||||||
|
// todo: check for escaped characters requiring double quotes
|
||||||
|
}
|
||||||
|
_write_scalar(sc.scalar, flags.is_quoted());
|
||||||
|
wrote_special:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_RYML_CB_ERR(m_tree->callbacks(), "not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags)
|
||||||
|
{
|
||||||
|
if(C4_UNLIKELY( ! sc.tag.empty()))
|
||||||
|
_RYML_CB_ERR(m_tree->callbacks(), "JSON does not have tags");
|
||||||
|
if(C4_UNLIKELY(flags.has_anchor()))
|
||||||
|
_RYML_CB_ERR(m_tree->callbacks(), "JSON does not have anchors");
|
||||||
|
_write_scalar_json(sc.scalar, flags.has_key(), flags.is_quoted());
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _rymlindent_nextline() for(size_t lv = 0; lv < ilevel+1; ++lv) { this->Writer::_do_write(' '); this->Writer::_do_write(' '); }
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_literal(csubstr s, size_t ilevel, bool explicit_key, bool explicit_indentation)
|
||||||
|
{
|
||||||
|
if(explicit_key)
|
||||||
|
this->Writer::_do_write("? ");
|
||||||
|
csubstr trimmed = s.trimr("\n\r");
|
||||||
|
size_t numnewlines_at_end = s.len - trimmed.len - s.sub(trimmed.len).count('\r');
|
||||||
|
//
|
||||||
|
if(!explicit_indentation)
|
||||||
|
this->Writer::_do_write('|');
|
||||||
|
else
|
||||||
|
this->Writer::_do_write("|2");
|
||||||
|
//
|
||||||
|
if(numnewlines_at_end > 1 || (trimmed.len == 0 && s.len > 0)/*only newlines*/)
|
||||||
|
this->Writer::_do_write("+\n");
|
||||||
|
else if(numnewlines_at_end == 1)
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
else
|
||||||
|
this->Writer::_do_write("-\n");
|
||||||
|
//
|
||||||
|
if(trimmed.len)
|
||||||
|
{
|
||||||
|
size_t pos = 0; // tracks the last character that was already written
|
||||||
|
for(size_t i = 0; i < trimmed.len; ++i)
|
||||||
|
{
|
||||||
|
if(trimmed[i] != '\n')
|
||||||
|
continue;
|
||||||
|
// write everything up to this point
|
||||||
|
csubstr since_pos = trimmed.range(pos, i+1); // include the newline
|
||||||
|
_rymlindent_nextline()
|
||||||
|
this->Writer::_do_write(since_pos);
|
||||||
|
pos = i+1; // already written
|
||||||
|
}
|
||||||
|
if(pos < trimmed.len)
|
||||||
|
{
|
||||||
|
_rymlindent_nextline()
|
||||||
|
this->Writer::_do_write(trimmed.sub(pos));
|
||||||
|
}
|
||||||
|
if(numnewlines_at_end)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
--numnewlines_at_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < numnewlines_at_end; ++i)
|
||||||
|
{
|
||||||
|
_rymlindent_nextline()
|
||||||
|
if(i+1 < numnewlines_at_end || explicit_key)
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
if(explicit_key && !numnewlines_at_end)
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_folded(csubstr s, size_t ilevel, bool explicit_key)
|
||||||
|
{
|
||||||
|
if(explicit_key)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write("? ");
|
||||||
|
}
|
||||||
|
RYML_ASSERT(s.find("\r") == csubstr::npos);
|
||||||
|
csubstr trimmed = s.trimr('\n');
|
||||||
|
size_t numnewlines_at_end = s.len - trimmed.len;
|
||||||
|
if(numnewlines_at_end == 0)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(">-\n");
|
||||||
|
}
|
||||||
|
else if(numnewlines_at_end == 1)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(">\n");
|
||||||
|
}
|
||||||
|
else if(numnewlines_at_end > 1)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(">+\n");
|
||||||
|
}
|
||||||
|
if(trimmed.len)
|
||||||
|
{
|
||||||
|
size_t pos = 0; // tracks the last character that was already written
|
||||||
|
for(size_t i = 0; i < trimmed.len; ++i)
|
||||||
|
{
|
||||||
|
if(trimmed[i] != '\n')
|
||||||
|
continue;
|
||||||
|
// write everything up to this point
|
||||||
|
csubstr since_pos = trimmed.range(pos, i+1); // include the newline
|
||||||
|
pos = i+1; // because of the newline
|
||||||
|
_rymlindent_nextline()
|
||||||
|
this->Writer::_do_write(since_pos);
|
||||||
|
this->Writer::_do_write('\n'); // write the newline twice
|
||||||
|
}
|
||||||
|
if(pos < trimmed.len)
|
||||||
|
{
|
||||||
|
_rymlindent_nextline()
|
||||||
|
this->Writer::_do_write(trimmed.sub(pos));
|
||||||
|
}
|
||||||
|
if(numnewlines_at_end)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
--numnewlines_at_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < numnewlines_at_end; ++i)
|
||||||
|
{
|
||||||
|
_rymlindent_nextline()
|
||||||
|
if(i+1 < numnewlines_at_end || explicit_key)
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
if(explicit_key && !numnewlines_at_end)
|
||||||
|
this->Writer::_do_write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_squo(csubstr s, size_t ilevel)
|
||||||
|
{
|
||||||
|
size_t pos = 0; // tracks the last character that was already written
|
||||||
|
this->Writer::_do_write('\'');
|
||||||
|
for(size_t i = 0; i < s.len; ++i)
|
||||||
|
{
|
||||||
|
if(s[i] == '\n')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i+1);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (including) this char
|
||||||
|
this->Writer::_do_write('\n'); // write the character again
|
||||||
|
if(i + 1 < s.len)
|
||||||
|
_rymlindent_nextline() // indent the next line
|
||||||
|
pos = i+1;
|
||||||
|
}
|
||||||
|
else if(s[i] == '\'')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i+1);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (including) this char
|
||||||
|
this->Writer::_do_write('\''); // write the character again
|
||||||
|
pos = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write missing characters at the end of the string
|
||||||
|
if(pos < s.len)
|
||||||
|
this->Writer::_do_write(s.sub(pos));
|
||||||
|
this->Writer::_do_write('\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_dquo(csubstr s, size_t ilevel)
|
||||||
|
{
|
||||||
|
size_t pos = 0; // tracks the last character that was already written
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
for(size_t i = 0; i < s.len; ++i)
|
||||||
|
{
|
||||||
|
const char curr = s.str[i];
|
||||||
|
if(curr == '"' || curr == '\\')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (excluding) this char
|
||||||
|
this->Writer::_do_write('\\'); // write the escape
|
||||||
|
this->Writer::_do_write(curr); // write the char
|
||||||
|
pos = i+1;
|
||||||
|
}
|
||||||
|
else if(s[i] == '\n')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i+1);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (including) this newline
|
||||||
|
this->Writer::_do_write('\n'); // write the newline again
|
||||||
|
if(i + 1 < s.len)
|
||||||
|
_rymlindent_nextline() // indent the next line
|
||||||
|
pos = i+1;
|
||||||
|
if(i+1 < s.len) // escape leading whitespace after the newline
|
||||||
|
{
|
||||||
|
const char next = s.str[i+1];
|
||||||
|
if(next == ' ' || next == '\t')
|
||||||
|
this->Writer::_do_write('\\');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(curr == ' ' || curr == '\t')
|
||||||
|
{
|
||||||
|
// escape trailing whitespace before a newline
|
||||||
|
size_t next = s.first_not_of(" \t\r", i);
|
||||||
|
if(next != npos && s[next] == '\n')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (excluding) this char
|
||||||
|
this->Writer::_do_write('\\'); // escape the whitespace
|
||||||
|
pos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(C4_UNLIKELY(curr == '\r'))
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (excluding) this char
|
||||||
|
this->Writer::_do_write("\\r"); // write the escaped char
|
||||||
|
pos = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write missing characters at the end of the string
|
||||||
|
if(pos < s.len)
|
||||||
|
{
|
||||||
|
csubstr sub = s.sub(pos);
|
||||||
|
this->Writer::_do_write(sub);
|
||||||
|
}
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_plain(csubstr s, size_t ilevel)
|
||||||
|
{
|
||||||
|
size_t pos = 0; // tracks the last character that was already written
|
||||||
|
for(size_t i = 0; i < s.len; ++i)
|
||||||
|
{
|
||||||
|
const char curr = s.str[i];
|
||||||
|
if(curr == '\n')
|
||||||
|
{
|
||||||
|
csubstr sub = s.range(pos, i+1);
|
||||||
|
this->Writer::_do_write(sub); // write everything up to (including) this newline
|
||||||
|
this->Writer::_do_write('\n'); // write the newline again
|
||||||
|
if(i + 1 < s.len)
|
||||||
|
_rymlindent_nextline() // indent the next line
|
||||||
|
pos = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write missing characters at the end of the string
|
||||||
|
if(pos < s.len)
|
||||||
|
{
|
||||||
|
csubstr sub = s.sub(pos);
|
||||||
|
this->Writer::_do_write(sub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _rymlindent_nextline
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar(csubstr s, bool was_quoted)
|
||||||
|
{
|
||||||
|
// this block of code needed to be moved to before the needs_quotes
|
||||||
|
// assignment to work around a g++ optimizer bug where (s.str != nullptr)
|
||||||
|
// was evaluated as true even if s.str was actually a nullptr (!!!)
|
||||||
|
if(s.len == size_t(0))
|
||||||
|
{
|
||||||
|
if(was_quoted || s.str != nullptr)
|
||||||
|
this->Writer::_do_write("''");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool needs_quotes = (
|
||||||
|
was_quoted
|
||||||
|
||
|
||||||
|
(
|
||||||
|
( ! s.is_number())
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
// has leading whitespace
|
||||||
|
// looks like reference or anchor
|
||||||
|
// would be treated as a directive
|
||||||
|
// see https://www.yaml.info/learn/quote.html#noplain
|
||||||
|
s.begins_with_any(" \n\t\r*&%@`")
|
||||||
|
||
|
||||||
|
s.begins_with("<<")
|
||||||
|
||
|
||||||
|
// has trailing whitespace
|
||||||
|
s.ends_with_any(" \n\t\r")
|
||||||
|
||
|
||||||
|
// has special chars
|
||||||
|
(s.first_of("#:-?,\n{}[]'\"") != npos)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if( ! needs_quotes)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const bool has_dquotes = s.first_of( '"') != npos;
|
||||||
|
const bool has_squotes = s.first_of('\'') != npos;
|
||||||
|
if(!has_squotes && has_dquotes)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write('\'');
|
||||||
|
this->Writer::_do_write(s);
|
||||||
|
this->Writer::_do_write('\'');
|
||||||
|
}
|
||||||
|
else if(has_squotes && !has_dquotes)
|
||||||
|
{
|
||||||
|
RYML_ASSERT(s.count('\n') == 0);
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
this->Writer::_do_write(s);
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_write_scalar_squo(s, /*FIXME FIXME FIXME*/0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Writer>
|
||||||
|
void Emitter<Writer>::_write_scalar_json(csubstr s, bool as_key, bool use_quotes)
|
||||||
|
{
|
||||||
|
if((!use_quotes)
|
||||||
|
// json keys require quotes
|
||||||
|
&& (!as_key)
|
||||||
|
&& (
|
||||||
|
// do not quote special cases
|
||||||
|
(s == "true" || s == "false" || s == "null")
|
||||||
|
|| (
|
||||||
|
// do not quote numbers
|
||||||
|
(s.is_number()
|
||||||
|
&& (
|
||||||
|
// quote integral numbers if they have a leading 0
|
||||||
|
// https://github.com/biojppm/rapidyaml/issues/291
|
||||||
|
(!(s.len > 1 && s.begins_with('0')))
|
||||||
|
// do not quote reals with leading 0
|
||||||
|
// https://github.com/biojppm/rapidyaml/issues/313
|
||||||
|
|| (s.find('.') != csubstr::npos) ))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this->Writer::_do_write(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
for(size_t i = 0; i < s.len; ++i)
|
||||||
|
{
|
||||||
|
switch(s.str[i])
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\\"");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\n");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\t");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\\\");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\r");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\b");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
this->Writer ::_do_write(s.range(pos, i));
|
||||||
|
this->Writer ::_do_write("\\f");
|
||||||
|
pos = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pos < s.len)
|
||||||
|
{
|
||||||
|
csubstr sub = s.sub(pos);
|
||||||
|
this->Writer::_do_write(sub);
|
||||||
|
}
|
||||||
|
this->Writer::_do_write('"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_YML_EMIT_DEF_HPP_ */
|
490
dep/rapidyaml/include/c4/yml/emit.hpp
Normal file
490
dep/rapidyaml/include/c4/yml/emit.hpp
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
#ifndef _C4_YML_EMIT_HPP_
|
||||||
|
#define _C4_YML_EMIT_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_WRITER_HPP_
|
||||||
|
#include "./writer.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _C4_YML_TREE_HPP_
|
||||||
|
#include "./tree.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _C4_YML_NODE_HPP_
|
||||||
|
#include "./node.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define RYML_DEPRECATE_EMIT \
|
||||||
|
RYML_DEPRECATED("use emit_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
|
||||||
|
#ifdef emit
|
||||||
|
#error "emit is defined, likely from a Qt include. This will cause a compilation error. See https://github.com/biojppm/rapidyaml/issues/120"
|
||||||
|
#endif
|
||||||
|
#define RYML_DEPRECATE_EMITRS \
|
||||||
|
RYML_DEPRECATED("use emitrs_yaml() instead. See https://github.com/biojppm/rapidyaml/issues/120")
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
template<class Writer> class Emitter;
|
||||||
|
|
||||||
|
template<class OStream>
|
||||||
|
using EmitterOStream = Emitter<WriterOStream<OStream>>;
|
||||||
|
using EmitterFile = Emitter<WriterFile>;
|
||||||
|
using EmitterBuf = Emitter<WriterBuf>;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMIT_YAML = 0,
|
||||||
|
EMIT_JSON = 1
|
||||||
|
} EmitType_e;
|
||||||
|
|
||||||
|
|
||||||
|
/** mark a tree or node to be emitted as json */
|
||||||
|
struct as_json
|
||||||
|
{
|
||||||
|
Tree const* tree;
|
||||||
|
size_t node;
|
||||||
|
as_json(Tree const& t) : tree(&t), node(t.empty() ? NONE : t.root_id()) {}
|
||||||
|
as_json(Tree const& t, size_t id) : tree(&t), node(id) {}
|
||||||
|
as_json(ConstNodeRef const& n) : tree(n.tree()), node(n.id()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class Writer>
|
||||||
|
class Emitter : public Writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
using Writer::Writer;
|
||||||
|
|
||||||
|
/** emit!
|
||||||
|
*
|
||||||
|
* When writing to a buffer, returns a substr of the emitted YAML.
|
||||||
|
* If the given buffer has insufficient space, the returned span will
|
||||||
|
* be null and its size will be the needed space. No writes are done
|
||||||
|
* after the end of the buffer.
|
||||||
|
*
|
||||||
|
* When writing to a file, the returned substr will be null, but its
|
||||||
|
* length will be set to the number of bytes written. */
|
||||||
|
substr emit_as(EmitType_e type, Tree const& t, size_t id, bool error_on_excess);
|
||||||
|
/** emit starting at the root node */
|
||||||
|
substr emit_as(EmitType_e type, Tree const& t, bool error_on_excess=true);
|
||||||
|
/** emit the given node */
|
||||||
|
substr emit_as(EmitType_e type, ConstNodeRef const& n, bool error_on_excess=true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Tree const* C4_RESTRICT m_tree;
|
||||||
|
|
||||||
|
void _emit_yaml(size_t id);
|
||||||
|
void _do_visit_flow_sl(size_t id, size_t ilevel=0);
|
||||||
|
void _do_visit_flow_ml(size_t id, size_t ilevel=0, size_t do_indent=1);
|
||||||
|
void _do_visit_block(size_t id, size_t ilevel=0, size_t do_indent=1);
|
||||||
|
void _do_visit_block_container(size_t id, size_t next_level, size_t do_indent);
|
||||||
|
void _do_visit_json(size_t id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void _write(NodeScalar const& C4_RESTRICT sc, NodeType flags, size_t level);
|
||||||
|
void _write_json(NodeScalar const& C4_RESTRICT sc, NodeType flags);
|
||||||
|
|
||||||
|
void _write_doc(size_t id);
|
||||||
|
void _write_scalar(csubstr s, bool was_quoted);
|
||||||
|
void _write_scalar_json(csubstr s, bool as_key, bool was_quoted);
|
||||||
|
void _write_scalar_literal(csubstr s, size_t level, bool as_key, bool explicit_indentation=false);
|
||||||
|
void _write_scalar_folded(csubstr s, size_t level, bool as_key);
|
||||||
|
void _write_scalar_squo(csubstr s, size_t level);
|
||||||
|
void _write_scalar_dquo(csubstr s, size_t level);
|
||||||
|
void _write_scalar_plain(csubstr s, size_t level);
|
||||||
|
|
||||||
|
void _write_tag(csubstr tag)
|
||||||
|
{
|
||||||
|
if(!tag.begins_with('!'))
|
||||||
|
this->Writer::_do_write('!');
|
||||||
|
this->Writer::_do_write(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum : type_bits {
|
||||||
|
_keysc = (KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | ~(VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
|
||||||
|
_valsc = ~(KEY|KEYREF|KEYANCH|KEYQUO|_WIP_KEY_STYLE) | (VAL|VALREF|VALANCH|VALQUO|_WIP_VAL_STYLE),
|
||||||
|
_keysc_json = (KEY) | ~(VAL),
|
||||||
|
_valsc_json = ~(KEY) | (VAL),
|
||||||
|
};
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE void _writek(size_t id, size_t level) { _write(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~_valsc, level); }
|
||||||
|
C4_ALWAYS_INLINE void _writev(size_t id, size_t level) { _write(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~_keysc, level); }
|
||||||
|
|
||||||
|
C4_ALWAYS_INLINE void _writek_json(size_t id) { _write_json(m_tree->keysc(id), m_tree->_p(id)->m_type.type & ~(VAL)); }
|
||||||
|
C4_ALWAYS_INLINE void _writev_json(size_t id) { _write_json(m_tree->valsc(id), m_tree->_p(id)->m_type.type & ~(KEY)); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** emit YAML to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written. */
|
||||||
|
inline size_t emit_yaml(Tree const& t, size_t id, FILE *f)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_YAML, t, id, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, size_t id, FILE *f)
|
||||||
|
{
|
||||||
|
return emit_yaml(t, id, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written. */
|
||||||
|
inline size_t emit_json(Tree const& t, size_t id, FILE *f)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_JSON, t, id, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit YAML to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written.
|
||||||
|
* @overload */
|
||||||
|
inline size_t emit_yaml(Tree const& t, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_YAML, t, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline size_t emit(Tree const& t, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
return emit_yaml(t, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written.
|
||||||
|
* @overload */
|
||||||
|
inline size_t emit_json(Tree const& t, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_JSON, t, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit YAML to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written.
|
||||||
|
* @overload */
|
||||||
|
inline size_t emit_yaml(ConstNodeRef const& r, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_YAML, r, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline size_t emit(ConstNodeRef const& r, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
return emit_yaml(r, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given file. A null file defaults to stdout.
|
||||||
|
* Return the number of bytes written.
|
||||||
|
* @overload */
|
||||||
|
inline size_t emit_json(ConstNodeRef const& r, FILE *f=nullptr)
|
||||||
|
{
|
||||||
|
EmitterFile em(f);
|
||||||
|
return em.emit_as(EMIT_JSON, r, /*error_on_excess*/true).len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** emit YAML to an STL-like ostream */
|
||||||
|
template<class OStream>
|
||||||
|
inline OStream& operator<< (OStream& s, Tree const& t)
|
||||||
|
{
|
||||||
|
EmitterOStream<OStream> em(s);
|
||||||
|
em.emit_as(EMIT_YAML, t);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit YAML to an STL-like ostream
|
||||||
|
* @overload */
|
||||||
|
template<class OStream>
|
||||||
|
inline OStream& operator<< (OStream& s, ConstNodeRef const& n)
|
||||||
|
{
|
||||||
|
EmitterOStream<OStream> em(s);
|
||||||
|
em.emit_as(EMIT_YAML, n);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit json to an STL-like stream */
|
||||||
|
template<class OStream>
|
||||||
|
inline OStream& operator<< (OStream& s, as_json const& j)
|
||||||
|
{
|
||||||
|
EmitterOStream<OStream> em(s);
|
||||||
|
em.emit_as(EMIT_JSON, *j.tree, j.node, true);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload */
|
||||||
|
inline substr emit_yaml(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_YAML, t, id, error_on_excess);
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
return emit_yaml(t, id, buf, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload */
|
||||||
|
inline substr emit_json(Tree const& t, size_t id, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_JSON, t, id, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload */
|
||||||
|
inline substr emit_yaml(Tree const& t, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_YAML, t, error_on_excess);
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline substr emit(Tree const& t, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
return emit_yaml(t, buf, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload */
|
||||||
|
inline substr emit_json(Tree const& t, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_JSON, t, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit YAML to the given buffer. Return a substr trimmed to the emitted YAML.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline substr emit_yaml(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_YAML, r, error_on_excess);
|
||||||
|
}
|
||||||
|
RYML_DEPRECATE_EMIT inline substr emit(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
return emit_yaml(r, buf, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit JSON to the given buffer. Return a substr trimmed to the emitted JSON.
|
||||||
|
* @param error_on_excess Raise an error if the space in the buffer is insufficient.
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline substr emit_json(ConstNodeRef const& r, substr buf, bool error_on_excess=true)
|
||||||
|
{
|
||||||
|
EmitterBuf em(buf);
|
||||||
|
return em.emit_as(EMIT_JSON, r, error_on_excess);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** emit+resize: emit YAML to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_yaml(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
substr buf = to_substr(*cont);
|
||||||
|
substr ret = emit_yaml(t, id, buf, /*error_on_excess*/false);
|
||||||
|
if(ret.str == nullptr && ret.len > 0)
|
||||||
|
{
|
||||||
|
cont->resize(ret.len);
|
||||||
|
buf = to_substr(*cont);
|
||||||
|
ret = emit_yaml(t, id, buf, /*error_on_excess*/true);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
return emitrs_yaml(t, id, cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: emit JSON to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_json(Tree const& t, size_t id, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
substr buf = to_substr(*cont);
|
||||||
|
substr ret = emit_json(t, id, buf, /*error_on_excess*/false);
|
||||||
|
if(ret.str == nullptr && ret.len > 0)
|
||||||
|
{
|
||||||
|
cont->resize(ret.len);
|
||||||
|
buf = to_substr(*cont);
|
||||||
|
ret = emit_json(t, id, buf, /*error_on_excess*/true);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit+resize: emit YAML to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_yaml(Tree const& t, size_t id)
|
||||||
|
{
|
||||||
|
CharOwningContainer c;
|
||||||
|
emitrs_yaml(t, id, &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t, size_t id)
|
||||||
|
{
|
||||||
|
CharOwningContainer c;
|
||||||
|
emitrs_yaml(t, id, &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: emit JSON to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_json(Tree const& t, size_t id)
|
||||||
|
{
|
||||||
|
CharOwningContainer c;
|
||||||
|
emitrs_json(t, id, &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit+resize: YAML to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_yaml(Tree const& t, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
if(t.empty())
|
||||||
|
return {};
|
||||||
|
return emitrs_yaml(t, t.root_id(), cont);
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS substr emitrs(Tree const& t, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
return emitrs_yaml(t, cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: JSON to the given std::string/std::vector-like
|
||||||
|
* container, resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_json(Tree const& t, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
if(t.empty())
|
||||||
|
return {};
|
||||||
|
return emitrs_json(t, t.root_id(), cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit+resize: YAML to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_yaml(Tree const& t)
|
||||||
|
{
|
||||||
|
CharOwningContainer c;
|
||||||
|
if(t.empty())
|
||||||
|
return c;
|
||||||
|
emitrs_yaml(t, t.root_id(), &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(Tree const& t)
|
||||||
|
{
|
||||||
|
return emitrs_yaml<CharOwningContainer>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: JSON to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_json(Tree const& t)
|
||||||
|
{
|
||||||
|
CharOwningContainer c;
|
||||||
|
if(t.empty())
|
||||||
|
return c;
|
||||||
|
emitrs_json(t, t.root_id(), &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit+resize: YAML to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_yaml(ConstNodeRef const& n, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
|
||||||
|
return emitrs_yaml(*n.tree(), n.id(), cont);
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS substr emitrs(ConstNodeRef const& n, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
return emitrs_yaml(n, cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: JSON to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
substr emitrs_json(ConstNodeRef const& n, CharOwningContainer * cont)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
|
||||||
|
return emitrs_json(*n.tree(), n.id(), cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** emit+resize: YAML to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted YAML. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_yaml(ConstNodeRef const& n)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
|
||||||
|
CharOwningContainer c;
|
||||||
|
emitrs_yaml(*n.tree(), n.id(), &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
RYML_DEPRECATE_EMITRS CharOwningContainer emitrs(ConstNodeRef const& n)
|
||||||
|
{
|
||||||
|
return emitrs_yaml<CharOwningContainer>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** emit+resize: JSON to the given std::string/std::vector-like container,
|
||||||
|
* resizing it as needed to fit the emitted JSON. */
|
||||||
|
template<class CharOwningContainer>
|
||||||
|
CharOwningContainer emitrs_json(ConstNodeRef const& n)
|
||||||
|
{
|
||||||
|
_RYML_CB_CHECK(n.tree()->callbacks(), n.valid());
|
||||||
|
CharOwningContainer c;
|
||||||
|
emitrs_json(*n.tree(), n.id(), &c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#undef RYML_DEPRECATE_EMIT
|
||||||
|
#undef RYML_DEPRECATE_EMITRS
|
||||||
|
|
||||||
|
#include "c4/yml/emit.def.hpp"
|
||||||
|
|
||||||
|
#endif /* _C4_YML_EMIT_HPP_ */
|
18
dep/rapidyaml/include/c4/yml/export.hpp
Normal file
18
dep/rapidyaml/include/c4/yml/export.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef C4_YML_EXPORT_HPP_
|
||||||
|
#define C4_YML_EXPORT_HPP_
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef RYML_SHARED
|
||||||
|
#ifdef RYML_EXPORTS
|
||||||
|
#define RYML_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define RYML_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define RYML_EXPORT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define RYML_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* C4_YML_EXPORT_HPP_ */
|
1280
dep/rapidyaml/include/c4/yml/node.hpp
Normal file
1280
dep/rapidyaml/include/c4/yml/node.hpp
Normal file
File diff suppressed because it is too large
Load diff
706
dep/rapidyaml/include/c4/yml/parse.hpp
Normal file
706
dep/rapidyaml/include/c4/yml/parse.hpp
Normal file
|
@ -0,0 +1,706 @@
|
||||||
|
#ifndef _C4_YML_PARSE_HPP_
|
||||||
|
#define _C4_YML_PARSE_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_TREE_HPP_
|
||||||
|
#include "c4/yml/tree.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _C4_YML_NODE_HPP_
|
||||||
|
#include "c4/yml/node.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _C4_YML_DETAIL_STACK_HPP_
|
||||||
|
#include "c4/yml/detail/stack.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
struct RYML_EXPORT ParserOptions
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef enum : uint32_t {
|
||||||
|
LOCATIONS = (1 << 0),
|
||||||
|
DEFAULTS = 0,
|
||||||
|
} Flags_e;
|
||||||
|
|
||||||
|
uint32_t flags = DEFAULTS;
|
||||||
|
public:
|
||||||
|
ParserOptions() = default;
|
||||||
|
|
||||||
|
/** @name source location tracking */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/** enable/disable source location tracking */
|
||||||
|
ParserOptions& locations(bool enabled)
|
||||||
|
{
|
||||||
|
if(enabled)
|
||||||
|
flags |= LOCATIONS;
|
||||||
|
else
|
||||||
|
flags &= ~LOCATIONS;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool locations() const { return (flags & LOCATIONS) != 0u; }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
class RYML_EXPORT Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name construction and assignment */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
Parser(Callbacks const& cb, ParserOptions opts={});
|
||||||
|
Parser(ParserOptions opts={}) : Parser(get_callbacks(), opts) {}
|
||||||
|
~Parser();
|
||||||
|
|
||||||
|
Parser(Parser &&);
|
||||||
|
Parser(Parser const&);
|
||||||
|
Parser& operator=(Parser &&);
|
||||||
|
Parser& operator=(Parser const&);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name modifiers */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/** Reserve a certain capacity for the parsing stack.
|
||||||
|
* This should be larger than the expected depth of the parsed
|
||||||
|
* YAML tree.
|
||||||
|
*
|
||||||
|
* The parsing stack is the only (potential) heap memory used by
|
||||||
|
* the parser.
|
||||||
|
*
|
||||||
|
* If the requested capacity is below the default
|
||||||
|
* stack size of 16, the memory is used directly in the parser
|
||||||
|
* object; otherwise it will be allocated from the heap.
|
||||||
|
*
|
||||||
|
* @note this reserves memory only for the parser itself; all the
|
||||||
|
* allocations for the parsed tree will go through the tree's
|
||||||
|
* allocator.
|
||||||
|
*
|
||||||
|
* @note the tree and the arena can (and should) also be reserved. */
|
||||||
|
void reserve_stack(size_t capacity)
|
||||||
|
{
|
||||||
|
m_stack.reserve(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reserve a certain capacity for the array used to track node
|
||||||
|
* locations in the source buffer. */
|
||||||
|
void reserve_locations(size_t num_source_lines)
|
||||||
|
{
|
||||||
|
_resize_locations(num_source_lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reserve a certain capacity for the character arena used to
|
||||||
|
* filter scalars. */
|
||||||
|
void reserve_filter_arena(size_t num_characters)
|
||||||
|
{
|
||||||
|
_resize_filter_arena(num_characters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name getters and modifiers */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/** Get the current callbacks in the parser. */
|
||||||
|
Callbacks callbacks() const { return m_stack.m_callbacks; }
|
||||||
|
|
||||||
|
/** Get the name of the latest file parsed by this object. */
|
||||||
|
csubstr filename() const { return m_file; }
|
||||||
|
|
||||||
|
/** Get the latest YAML buffer parsed by this object. */
|
||||||
|
csubstr source() const { return m_buf; }
|
||||||
|
|
||||||
|
size_t stack_capacity() const { return m_stack.capacity(); }
|
||||||
|
size_t locations_capacity() const { return m_newline_offsets_capacity; }
|
||||||
|
size_t filter_arena_capacity() const { return m_filter_arena.len; }
|
||||||
|
|
||||||
|
ParserOptions const& options() const { return m_options; }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name parse_in_place */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/** Create a new tree and parse into its root.
|
||||||
|
* The tree is created with the callbacks currently in the parser. */
|
||||||
|
Tree parse_in_place(csubstr filename, substr src)
|
||||||
|
{
|
||||||
|
Tree t(callbacks());
|
||||||
|
t.reserve(_estimate_capacity(src));
|
||||||
|
this->parse_in_place(filename, src, &t, t.root_id());
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse into an existing tree, starting at its root node.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_place(csubstr filename, substr src, Tree *t)
|
||||||
|
{
|
||||||
|
this->parse_in_place(filename, src, t, t->root_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse into an existing node.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_place(csubstr filename, substr src, Tree *t, size_t node_id);
|
||||||
|
// ^^^^^^^^^^^^^ this is the workhorse overload; everything else is syntactic candy
|
||||||
|
|
||||||
|
/** Parse into an existing node.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_place(csubstr filename, substr src, NodeRef node)
|
||||||
|
{
|
||||||
|
this->parse_in_place(filename, src, node.tree(), node.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") Tree parse(csubstr filename, substr src) { return parse_in_place(filename, src); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t) { parse_in_place(filename, src, t); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t, size_t node_id) { parse_in_place(filename, src, t, node_id); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, NodeRef node) { parse_in_place(filename, src, node); }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name parse_in_arena: copy the YAML source buffer to the
|
||||||
|
* tree's arena, then parse the copy in situ
|
||||||
|
*
|
||||||
|
* @note overloads receiving a substr YAML buffer are intentionally
|
||||||
|
* left undefined, such that calling parse_in_arena() with a substr
|
||||||
|
* will cause a linker error. This is to prevent an accidental
|
||||||
|
* copy of the source buffer to the tree's arena, because substr
|
||||||
|
* is implicitly convertible to csubstr. If you really intend to parse
|
||||||
|
* a mutable buffer in the tree's arena, convert it first to immutable
|
||||||
|
* by assigning the substr to a csubstr prior to calling parse_in_arena().
|
||||||
|
* This is not needed for parse_in_place() because csubstr is not
|
||||||
|
* implicitly convertible to substr. */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
// READ THE NOTE ABOVE!
|
||||||
|
#define RYML_DONT_PARSE_SUBSTR_IN_ARENA "Do not pass a (mutable) substr to parse_in_arena(); if you have a substr, it should be parsed in place. Consider using parse_in_place() instead, or convert the buffer to csubstr prior to calling. This function is deliberately left undefined and will cause a linker error."
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr csrc);
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t);
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t, size_t node_id);
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, NodeRef node);
|
||||||
|
|
||||||
|
/** Create a new tree and parse into its root.
|
||||||
|
* The immutable YAML source is first copied to the tree's arena,
|
||||||
|
* and parsed from there.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
Tree parse_in_arena(csubstr filename, csubstr csrc)
|
||||||
|
{
|
||||||
|
Tree t(callbacks());
|
||||||
|
substr src = t.copy_to_arena(csrc);
|
||||||
|
t.reserve(_estimate_capacity(csrc));
|
||||||
|
this->parse_in_place(filename, src, &t, t.root_id());
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse into an existing tree, starting at its root node.
|
||||||
|
* The immutable YAML source is first copied to the tree's arena,
|
||||||
|
* and parsed from there.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_arena(csubstr filename, csubstr csrc, Tree *t)
|
||||||
|
{
|
||||||
|
substr src = t->copy_to_arena(csrc);
|
||||||
|
this->parse_in_place(filename, src, t, t->root_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse into a specific node in an existing tree.
|
||||||
|
* The immutable YAML source is first copied to the tree's arena,
|
||||||
|
* and parsed from there.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_arena(csubstr filename, csubstr csrc, Tree *t, size_t node_id)
|
||||||
|
{
|
||||||
|
substr src = t->copy_to_arena(csrc);
|
||||||
|
this->parse_in_place(filename, src, t, node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parse into a specific node in an existing tree.
|
||||||
|
* The immutable YAML source is first copied to the tree's arena,
|
||||||
|
* and parsed from there.
|
||||||
|
* The callbacks in the tree are kept, and used to allocate
|
||||||
|
* the tree members, if any allocation is required. */
|
||||||
|
void parse_in_arena(csubstr filename, csubstr csrc, NodeRef node)
|
||||||
|
{
|
||||||
|
substr src = node.tree()->copy_to_arena(csrc);
|
||||||
|
this->parse_in_place(filename, src, node.tree(), node.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") Tree parse(csubstr filename, csubstr csrc) { return parse_in_arena(filename, csrc); }
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t) { parse_in_arena(filename, csrc, t); }
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t, size_t node_id) { parse_in_arena(filename, csrc, t, node_id); }
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, NodeRef node) { parse_in_arena(filename, csrc, node); }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @name locations */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/** Get the location of a node of the last tree to be parsed by this parser. */
|
||||||
|
Location location(Tree const& tree, size_t node_id) const;
|
||||||
|
/** Get the location of a node of the last tree to be parsed by this parser. */
|
||||||
|
Location location(ConstNodeRef node) const;
|
||||||
|
/** Get the string starting at a particular location, to the end
|
||||||
|
* of the parsed source buffer. */
|
||||||
|
csubstr location_contents(Location const& loc) const;
|
||||||
|
/** Given a pointer to a buffer position, get the location. @p val
|
||||||
|
* must be pointing to somewhere in the source buffer that was
|
||||||
|
* last parsed by this object. */
|
||||||
|
Location val_location(const char *val) const;
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BLOCK_LITERAL, //!< keep newlines (|)
|
||||||
|
BLOCK_FOLD //!< replace newline with single space (>)
|
||||||
|
} BlockStyle_e;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CHOMP_CLIP, //!< single newline at end (default)
|
||||||
|
CHOMP_STRIP, //!< no newline at end (-)
|
||||||
|
CHOMP_KEEP //!< all newlines from end (+)
|
||||||
|
} BlockChomp_e;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
using flag_t = int;
|
||||||
|
|
||||||
|
static size_t _estimate_capacity(csubstr src) { size_t c = _count_nlines(src); c = c >= 16 ? c : 16; return c; }
|
||||||
|
|
||||||
|
void _reset();
|
||||||
|
|
||||||
|
bool _finished_file() const;
|
||||||
|
bool _finished_line() const;
|
||||||
|
|
||||||
|
csubstr _peek_next_line(size_t pos=npos) const;
|
||||||
|
bool _advance_to_peeked();
|
||||||
|
void _scan_line();
|
||||||
|
|
||||||
|
csubstr _slurp_doc_scalar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param [out] quoted
|
||||||
|
* Will only be written to if this method returns true.
|
||||||
|
* Will be set to true if the scanned scalar was quoted, by '', "", > or |.
|
||||||
|
*/
|
||||||
|
bool _scan_scalar_seq_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
|
||||||
|
bool _scan_scalar_map_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
|
||||||
|
bool _scan_scalar_seq_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
|
||||||
|
bool _scan_scalar_map_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
|
||||||
|
bool _scan_scalar_unk(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
|
||||||
|
|
||||||
|
csubstr _scan_comment();
|
||||||
|
csubstr _scan_squot_scalar();
|
||||||
|
csubstr _scan_dquot_scalar();
|
||||||
|
csubstr _scan_block();
|
||||||
|
substr _scan_plain_scalar_blck(csubstr currscalar, csubstr peeked_line, size_t indentation);
|
||||||
|
substr _scan_plain_scalar_flow(csubstr currscalar, csubstr peeked_line);
|
||||||
|
substr _scan_complex_key(csubstr currscalar, csubstr peeked_line);
|
||||||
|
csubstr _scan_to_next_nonempty_line(size_t indentation);
|
||||||
|
csubstr _extend_scanned_scalar(csubstr currscalar);
|
||||||
|
|
||||||
|
csubstr _filter_squot_scalar(const substr s);
|
||||||
|
csubstr _filter_dquot_scalar(substr s);
|
||||||
|
csubstr _filter_plain_scalar(substr s, size_t indentation);
|
||||||
|
csubstr _filter_block_scalar(substr s, BlockStyle_e style, BlockChomp_e chomp, size_t indentation);
|
||||||
|
template<bool backslash_is_escape, bool keep_trailing_whitespace>
|
||||||
|
bool _filter_nl(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos, size_t indentation);
|
||||||
|
template<bool keep_trailing_whitespace>
|
||||||
|
void _filter_ws(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos);
|
||||||
|
bool _apply_chomp(substr buf, size_t *C4_RESTRICT pos, BlockChomp_e chomp);
|
||||||
|
|
||||||
|
void _handle_finished_file();
|
||||||
|
void _handle_line();
|
||||||
|
|
||||||
|
bool _handle_indentation();
|
||||||
|
|
||||||
|
bool _handle_unk();
|
||||||
|
bool _handle_map_flow();
|
||||||
|
bool _handle_map_blck();
|
||||||
|
bool _handle_seq_flow();
|
||||||
|
bool _handle_seq_blck();
|
||||||
|
bool _handle_top();
|
||||||
|
bool _handle_types();
|
||||||
|
bool _handle_key_anchors_and_refs();
|
||||||
|
bool _handle_val_anchors_and_refs();
|
||||||
|
void _move_val_tag_to_key_tag();
|
||||||
|
void _move_key_tag_to_val_tag();
|
||||||
|
void _move_key_tag2_to_key_tag();
|
||||||
|
void _move_val_anchor_to_key_anchor();
|
||||||
|
void _move_key_anchor_to_val_anchor();
|
||||||
|
|
||||||
|
void _push_level(bool explicit_flow_chars = false);
|
||||||
|
void _pop_level();
|
||||||
|
|
||||||
|
void _start_unk(bool as_child=true);
|
||||||
|
|
||||||
|
void _start_map(bool as_child=true);
|
||||||
|
void _start_map_unk(bool as_child);
|
||||||
|
void _stop_map();
|
||||||
|
|
||||||
|
void _start_seq(bool as_child=true);
|
||||||
|
void _stop_seq();
|
||||||
|
|
||||||
|
void _start_seqimap();
|
||||||
|
void _stop_seqimap();
|
||||||
|
|
||||||
|
void _start_doc(bool as_child=true);
|
||||||
|
void _stop_doc();
|
||||||
|
void _start_new_doc(csubstr rem);
|
||||||
|
void _end_stream();
|
||||||
|
|
||||||
|
NodeData* _append_val(csubstr val, flag_t quoted=false);
|
||||||
|
NodeData* _append_key_val(csubstr val, flag_t val_quoted=false);
|
||||||
|
bool _rval_dash_start_or_continue_seq();
|
||||||
|
|
||||||
|
void _store_scalar(csubstr s, flag_t is_quoted);
|
||||||
|
csubstr _consume_scalar();
|
||||||
|
void _move_scalar_from_top();
|
||||||
|
|
||||||
|
inline NodeData* _append_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_val({nullptr, size_t(0)}); }
|
||||||
|
inline NodeData* _append_key_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_key_val({nullptr, size_t(0)}); }
|
||||||
|
inline void _store_scalar_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); _store_scalar({nullptr, size_t(0)}, false); }
|
||||||
|
|
||||||
|
void _set_indentation(size_t behind);
|
||||||
|
void _save_indentation(size_t behind=0);
|
||||||
|
bool _maybe_set_indentation_from_anchor_or_tag();
|
||||||
|
|
||||||
|
void _write_key_anchor(size_t node_id);
|
||||||
|
void _write_val_anchor(size_t node_id);
|
||||||
|
|
||||||
|
void _handle_directive(csubstr directive);
|
||||||
|
|
||||||
|
void _skipchars(char c);
|
||||||
|
template<size_t N>
|
||||||
|
void _skipchars(const char (&chars)[N]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static size_t _count_nlines(csubstr src);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef enum : flag_t {
|
||||||
|
RTOP = 0x01 << 0, ///< reading at top level
|
||||||
|
RUNK = 0x01 << 1, ///< reading an unknown: must determine whether scalar, map or seq
|
||||||
|
RMAP = 0x01 << 2, ///< reading a map
|
||||||
|
RSEQ = 0x01 << 3, ///< reading a seq
|
||||||
|
FLOW = 0x01 << 4, ///< reading is inside explicit flow chars: [] or {}
|
||||||
|
QMRK = 0x01 << 5, ///< reading an explicit key (`? key`)
|
||||||
|
RKEY = 0x01 << 6, ///< reading a scalar as key
|
||||||
|
RVAL = 0x01 << 7, ///< reading a scalar as val
|
||||||
|
RNXT = 0x01 << 8, ///< read next val or keyval
|
||||||
|
SSCL = 0x01 << 9, ///< there's a stored scalar
|
||||||
|
QSCL = 0x01 << 10, ///< stored scalar was quoted
|
||||||
|
RSET = 0x01 << 11, ///< the (implicit) map being read is a !!set. @see https://yaml.org/type/set.html
|
||||||
|
NDOC = 0x01 << 12, ///< no document mode. a document has ended and another has not started yet.
|
||||||
|
//! reading an implicit map nested in an explicit seq.
|
||||||
|
//! eg, {key: [key2: value2, key3: value3]}
|
||||||
|
//! is parsed as {key: [{key2: value2}, {key3: value3}]}
|
||||||
|
RSEQIMAP = 0x01 << 13,
|
||||||
|
} State_e;
|
||||||
|
|
||||||
|
struct LineContents
|
||||||
|
{
|
||||||
|
csubstr full; ///< the full line, including newlines on the right
|
||||||
|
csubstr stripped; ///< the stripped line, excluding newlines on the right
|
||||||
|
csubstr rem; ///< the stripped line remainder; initially starts at the first non-space character
|
||||||
|
size_t indentation; ///< the number of spaces on the beginning of the line
|
||||||
|
|
||||||
|
LineContents() : full(), stripped(), rem(), indentation() {}
|
||||||
|
|
||||||
|
void reset_with_next_line(csubstr buf, size_t pos);
|
||||||
|
|
||||||
|
void reset(csubstr full_, csubstr stripped_)
|
||||||
|
{
|
||||||
|
full = full_;
|
||||||
|
stripped = stripped_;
|
||||||
|
rem = stripped_;
|
||||||
|
// find the first column where the character is not a space
|
||||||
|
indentation = full.first_not_of(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t current_col() const
|
||||||
|
{
|
||||||
|
return current_col(rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t current_col(csubstr s) const
|
||||||
|
{
|
||||||
|
RYML_ASSERT(s.str >= full.str);
|
||||||
|
RYML_ASSERT(full.is_super(s));
|
||||||
|
size_t col = static_cast<size_t>(s.str - full.str);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
flag_t flags;
|
||||||
|
size_t level;
|
||||||
|
size_t node_id; // don't hold a pointer to the node as it will be relocated during tree resizes
|
||||||
|
csubstr scalar;
|
||||||
|
size_t scalar_col; // the column where the scalar (or its quotes) begin
|
||||||
|
|
||||||
|
Location pos;
|
||||||
|
LineContents line_contents;
|
||||||
|
size_t indref;
|
||||||
|
|
||||||
|
State() : flags(), level(), node_id(), scalar(), scalar_col(), pos(), line_contents(), indref() {}
|
||||||
|
|
||||||
|
void reset(const char *file, size_t node_id_)
|
||||||
|
{
|
||||||
|
flags = RUNK|RTOP;
|
||||||
|
level = 0;
|
||||||
|
pos.name = to_csubstr(file);
|
||||||
|
pos.offset = 0;
|
||||||
|
pos.line = 1;
|
||||||
|
pos.col = 1;
|
||||||
|
node_id = node_id_;
|
||||||
|
scalar_col = 0;
|
||||||
|
scalar.clear();
|
||||||
|
indref = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void _line_progressed(size_t ahead);
|
||||||
|
void _line_ended();
|
||||||
|
void _line_ended_undo();
|
||||||
|
|
||||||
|
void _prepare_pop()
|
||||||
|
{
|
||||||
|
RYML_ASSERT(m_stack.size() > 1);
|
||||||
|
State const& curr = m_stack.top();
|
||||||
|
State & next = m_stack.top(1);
|
||||||
|
next.pos = curr.pos;
|
||||||
|
next.line_contents = curr.line_contents;
|
||||||
|
next.scalar = curr.scalar;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool _at_line_begin() const
|
||||||
|
{
|
||||||
|
return m_state->line_contents.rem.begin() == m_state->line_contents.full.begin();
|
||||||
|
}
|
||||||
|
inline bool _at_line_end() const
|
||||||
|
{
|
||||||
|
csubstr r = m_state->line_contents.rem;
|
||||||
|
return r.empty() || r.begins_with(' ', r.len);
|
||||||
|
}
|
||||||
|
inline bool _token_is_from_this_line(csubstr token) const
|
||||||
|
{
|
||||||
|
return token.is_sub(m_state->line_contents.full);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NodeData * node(State const* s) const { return m_tree->get(s->node_id); }
|
||||||
|
inline NodeData * node(State const& s) const { return m_tree->get(s .node_id); }
|
||||||
|
inline NodeData * node(size_t node_id) const { return m_tree->get( node_id); }
|
||||||
|
|
||||||
|
inline bool has_all(flag_t f) const { return (m_state->flags & f) == f; }
|
||||||
|
inline bool has_any(flag_t f) const { return (m_state->flags & f) != 0; }
|
||||||
|
inline bool has_none(flag_t f) const { return (m_state->flags & f) == 0; }
|
||||||
|
|
||||||
|
static inline bool has_all(flag_t f, State const* s) { return (s->flags & f) == f; }
|
||||||
|
static inline bool has_any(flag_t f, State const* s) { return (s->flags & f) != 0; }
|
||||||
|
static inline bool has_none(flag_t f, State const* s) { return (s->flags & f) == 0; }
|
||||||
|
|
||||||
|
inline void set_flags(flag_t f) { set_flags(f, m_state); }
|
||||||
|
inline void add_flags(flag_t on) { add_flags(on, m_state); }
|
||||||
|
inline void addrem_flags(flag_t on, flag_t off) { addrem_flags(on, off, m_state); }
|
||||||
|
inline void rem_flags(flag_t off) { rem_flags(off, m_state); }
|
||||||
|
|
||||||
|
void set_flags(flag_t f, State * s);
|
||||||
|
void add_flags(flag_t on, State * s);
|
||||||
|
void addrem_flags(flag_t on, flag_t off, State * s);
|
||||||
|
void rem_flags(flag_t off, State * s);
|
||||||
|
|
||||||
|
void _resize_filter_arena(size_t num_characters);
|
||||||
|
void _grow_filter_arena(size_t num_characters);
|
||||||
|
substr _finish_filter_arena(substr dst, size_t pos);
|
||||||
|
|
||||||
|
void _prepare_locations();
|
||||||
|
void _resize_locations(size_t sz);
|
||||||
|
bool _locations_dirty() const;
|
||||||
|
|
||||||
|
bool _location_from_cont(Tree const& tree, size_t node, Location *C4_RESTRICT loc) const;
|
||||||
|
bool _location_from_node(Tree const& tree, size_t node, Location *C4_RESTRICT loc, size_t level) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void _free();
|
||||||
|
void _clr();
|
||||||
|
void _cp(Parser const* that);
|
||||||
|
void _mv(Parser *that);
|
||||||
|
|
||||||
|
#ifdef RYML_DBG
|
||||||
|
template<class ...Args> void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const;
|
||||||
|
#endif
|
||||||
|
template<class ...Args> void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
|
||||||
|
template<class DumpFn> void _fmt_msg(DumpFn &&dumpfn) const;
|
||||||
|
static csubstr _prfl(substr buf, flag_t v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ParserOptions m_options;
|
||||||
|
|
||||||
|
csubstr m_file;
|
||||||
|
substr m_buf;
|
||||||
|
|
||||||
|
size_t m_root_id;
|
||||||
|
Tree * m_tree;
|
||||||
|
|
||||||
|
detail::stack<State> m_stack;
|
||||||
|
State * m_state;
|
||||||
|
|
||||||
|
size_t m_key_tag_indentation;
|
||||||
|
size_t m_key_tag2_indentation;
|
||||||
|
csubstr m_key_tag;
|
||||||
|
csubstr m_key_tag2;
|
||||||
|
size_t m_val_tag_indentation;
|
||||||
|
csubstr m_val_tag;
|
||||||
|
|
||||||
|
bool m_key_anchor_was_before;
|
||||||
|
size_t m_key_anchor_indentation;
|
||||||
|
csubstr m_key_anchor;
|
||||||
|
size_t m_val_anchor_indentation;
|
||||||
|
csubstr m_val_anchor;
|
||||||
|
|
||||||
|
substr m_filter_arena;
|
||||||
|
|
||||||
|
size_t *m_newline_offsets;
|
||||||
|
size_t m_newline_offsets_size;
|
||||||
|
size_t m_newline_offsets_capacity;
|
||||||
|
csubstr m_newline_offsets_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @name parse_in_place
|
||||||
|
*
|
||||||
|
* @desc parse a mutable YAML source buffer.
|
||||||
|
*
|
||||||
|
* @note These freestanding functions use a temporary parser object,
|
||||||
|
* and are convenience functions to easily parse YAML without the need
|
||||||
|
* to instantiate a separate parser. Note that some properties
|
||||||
|
* (notably node locations in the original source code) are only
|
||||||
|
* available through the parser object after it has parsed the
|
||||||
|
* code. If you need access to any of these properties, use
|
||||||
|
* Parser::parse_in_place() */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
inline Tree parse_in_place( substr yaml ) { Parser np; return np.parse_in_place({} , yaml); } //!< parse in-situ a modifiable YAML source buffer.
|
||||||
|
inline Tree parse_in_place(csubstr filename, substr yaml ) { Parser np; return np.parse_in_place(filename, yaml); } //!< parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
|
||||||
|
inline void parse_in_place( substr yaml, Tree *t ) { Parser np; np.parse_in_place({} , yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
|
||||||
|
inline void parse_in_place(csubstr filename, substr yaml, Tree *t ) { Parser np; np.parse_in_place(filename, yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
|
||||||
|
inline void parse_in_place( substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({} , yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
|
||||||
|
inline void parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
|
||||||
|
inline void parse_in_place( substr yaml, NodeRef node ) { Parser np; np.parse_in_place({} , yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
|
||||||
|
inline void parse_in_place(csubstr filename, substr yaml, NodeRef node ) { Parser np; np.parse_in_place(filename, yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
|
||||||
|
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse( substr yaml ) { Parser np; return np.parse_in_place({} , yaml); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse(csubstr filename, substr yaml ) { Parser np; return np.parse_in_place(filename, yaml); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, Tree *t ) { Parser np; np.parse_in_place({} , yaml, t); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t ) { Parser np; np.parse_in_place(filename, yaml, t); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({} , yaml, t, node_id); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse( substr yaml, NodeRef node ) { Parser np; np.parse_in_place({} , yaml, node); }
|
||||||
|
RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, NodeRef node ) { Parser np; np.parse_in_place(filename, yaml, node); }
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @name parse_in_arena
|
||||||
|
* @desc parse a read-only YAML source buffer, copying it first to the tree's arena.
|
||||||
|
*
|
||||||
|
* @note These freestanding functions use a temporary parser object,
|
||||||
|
* and are convenience functions to easily parse YAML without the need
|
||||||
|
* to instantiate a separate parser. Note that some properties
|
||||||
|
* (notably node locations in the original source code) are only
|
||||||
|
* available through the parser object after it has parsed the
|
||||||
|
* code. If you need access to any of these properties, use
|
||||||
|
* Parser::parse_in_arena().
|
||||||
|
*
|
||||||
|
* @note overloads receiving a substr YAML buffer are intentionally
|
||||||
|
* left undefined, such that calling parse_in_arena() with a substr
|
||||||
|
* will cause a linker error. This is to prevent an accidental
|
||||||
|
* copy of the source buffer to the tree's arena, because substr
|
||||||
|
* is implicitly convertible to csubstr. If you really intend to parse
|
||||||
|
* a mutable buffer in the tree's arena, convert it first to immutable
|
||||||
|
* by assigning the substr to a csubstr prior to calling parse_in_arena().
|
||||||
|
* This is not needed for parse_in_place() because csubstr is not
|
||||||
|
* implicitly convertible to substr. */
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
/* READ THE NOTE ABOVE! */
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena( substr yaml );
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr yaml );
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t );
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t );
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, Tree *t, size_t node_id);
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id);
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena( substr yaml, NodeRef node );
|
||||||
|
RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, NodeRef node );
|
||||||
|
|
||||||
|
inline Tree parse_in_arena( csubstr yaml ) { Parser np; return np.parse_in_arena({} , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
inline Tree parse_in_arena(csubstr filename, csubstr yaml ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
inline void parse_in_arena( csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena({} , yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
inline void parse_in_arena( csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({} , yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
inline void parse_in_arena( csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena({} , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
inline void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse( csubstr yaml ) { Parser np; return np.parse_in_arena({} , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse(csubstr filename, csubstr yaml ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse( csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena({} , yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse( csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({} , yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse( csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena({} , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
|
||||||
|
RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, NodeRef node ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _C4_YML_PARSE_HPP_ */
|
99
dep/rapidyaml/include/c4/yml/preprocess.hpp
Normal file
99
dep/rapidyaml/include/c4/yml/preprocess.hpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#ifndef _C4_YML_PREPROCESS_HPP_
|
||||||
|
#define _C4_YML_PREPROCESS_HPP_
|
||||||
|
|
||||||
|
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
|
||||||
|
|
||||||
|
/** @defgroup Preprocessors Preprocessor functions
|
||||||
|
*
|
||||||
|
* These are the existing preprocessors:
|
||||||
|
*
|
||||||
|
* @code{.cpp}
|
||||||
|
* size_t preprocess_json(csubstr json, substr buf)
|
||||||
|
* size_t preprocess_rxmap(csubstr json, substr buf)
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _C4_YML_COMMON_HPP_
|
||||||
|
#include "./common.hpp"
|
||||||
|
#endif
|
||||||
|
#include <c4/substr.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
using Preprocessor = size_t(csubstr, substr);
|
||||||
|
template<Preprocessor PP, class CharContainer>
|
||||||
|
substr preprocess_into_container(csubstr input, CharContainer *out)
|
||||||
|
{
|
||||||
|
// try to write once. the preprocessor will stop writing at the end of
|
||||||
|
// the container, but will process all the input to determine the
|
||||||
|
// required container size.
|
||||||
|
size_t sz = PP(input, to_substr(*out));
|
||||||
|
// if the container size is not enough, resize, and run again in the
|
||||||
|
// resized container
|
||||||
|
if(sz > out->size())
|
||||||
|
{
|
||||||
|
out->resize(sz);
|
||||||
|
sz = PP(input, to_substr(*out));
|
||||||
|
}
|
||||||
|
return to_substr(*out).first(sz);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** @name preprocess_rxmap
|
||||||
|
* Convert flow-type relaxed maps (with implicit bools) into strict YAML
|
||||||
|
* flow map.
|
||||||
|
*
|
||||||
|
* @code{.yaml}
|
||||||
|
* {a, b, c, d: [e, f], g: {a, b}}
|
||||||
|
* # is converted into this:
|
||||||
|
* {a: 1, b: 1, c: 1, d: [e, f], g: {a, b}}
|
||||||
|
* @endcode
|
||||||
|
|
||||||
|
* @note this is NOT recursive - conversion happens only in the top-level map
|
||||||
|
* @param rxmap A relaxed map
|
||||||
|
* @param buf output buffer
|
||||||
|
* @param out output container
|
||||||
|
*/
|
||||||
|
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/** Write into a given output buffer. This function is safe to call with
|
||||||
|
* empty or small buffers; it won't write beyond the end of the buffer.
|
||||||
|
*
|
||||||
|
* @return the number of characters required for output
|
||||||
|
*/
|
||||||
|
RYML_EXPORT size_t preprocess_rxmap(csubstr rxmap, substr buf);
|
||||||
|
|
||||||
|
|
||||||
|
/** Write into an existing container. It is resized to contained the output.
|
||||||
|
* @return a substr of the container
|
||||||
|
* @overload preprocess_rxmap */
|
||||||
|
template<class CharContainer>
|
||||||
|
substr preprocess_rxmap(csubstr rxmap, CharContainer *out)
|
||||||
|
{
|
||||||
|
return detail::preprocess_into_container<preprocess_rxmap>(rxmap, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Create a container with the result.
|
||||||
|
* @overload preprocess_rxmap */
|
||||||
|
template<class CharContainer>
|
||||||
|
CharContainer preprocess_rxmap(csubstr rxmap)
|
||||||
|
{
|
||||||
|
CharContainer out;
|
||||||
|
preprocess_rxmap(rxmap, &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_YML_PREPROCESS_HPP_ */
|
45
dep/rapidyaml/include/c4/yml/std/map.hpp
Normal file
45
dep/rapidyaml/include/c4/yml/std/map.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef _C4_YML_STD_MAP_HPP_
|
||||||
|
#define _C4_YML_STD_MAP_HPP_
|
||||||
|
|
||||||
|
/** @file map.hpp write/read std::map to/from a YAML tree. */
|
||||||
|
|
||||||
|
#include "c4/yml/node.hpp"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
// std::map requires child nodes in the data
|
||||||
|
// tree hierarchy (a MAP node in ryml parlance).
|
||||||
|
// So it should be serialized via write()/read().
|
||||||
|
|
||||||
|
template<class K, class V, class Less, class Alloc>
|
||||||
|
void write(c4::yml::NodeRef *n, std::map<K, V, Less, Alloc> const& m)
|
||||||
|
{
|
||||||
|
*n |= c4::yml::MAP;
|
||||||
|
for(auto const& C4_RESTRICT p : m)
|
||||||
|
{
|
||||||
|
auto ch = n->append_child();
|
||||||
|
ch << c4::yml::key(p.first);
|
||||||
|
ch << p.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class K, class V, class Less, class Alloc>
|
||||||
|
bool read(c4::yml::ConstNodeRef const& n, std::map<K, V, Less, Alloc> * m)
|
||||||
|
{
|
||||||
|
K k{};
|
||||||
|
V v{};
|
||||||
|
for(auto const& C4_RESTRICT ch : n)
|
||||||
|
{
|
||||||
|
ch >> c4::yml::key(k);
|
||||||
|
ch >> v;
|
||||||
|
m->emplace(std::make_pair(std::move(k), std::move(v)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_YML_STD_MAP_HPP_
|
8
dep/rapidyaml/include/c4/yml/std/std.hpp
Normal file
8
dep/rapidyaml/include/c4/yml/std/std.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef _C4_YML_STD_STD_HPP_
|
||||||
|
#define _C4_YML_STD_STD_HPP_
|
||||||
|
|
||||||
|
#include "c4/yml/std/string.hpp"
|
||||||
|
#include "c4/yml/std/vector.hpp"
|
||||||
|
#include "c4/yml/std/map.hpp"
|
||||||
|
|
||||||
|
#endif // _C4_YML_STD_STD_HPP_
|
9
dep/rapidyaml/include/c4/yml/std/string.hpp
Normal file
9
dep/rapidyaml/include/c4/yml/std/string.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef C4_YML_STD_STRING_HPP_
|
||||||
|
#define C4_YML_STD_STRING_HPP_
|
||||||
|
|
||||||
|
/** @file string.hpp substring conversions for/from std::string */
|
||||||
|
|
||||||
|
// everything we need is implemented here:
|
||||||
|
#include <c4/std/string.hpp>
|
||||||
|
|
||||||
|
#endif // C4_YML_STD_STRING_HPP_
|
53
dep/rapidyaml/include/c4/yml/std/vector.hpp
Normal file
53
dep/rapidyaml/include/c4/yml/std/vector.hpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef _C4_YML_STD_VECTOR_HPP_
|
||||||
|
#define _C4_YML_STD_VECTOR_HPP_
|
||||||
|
|
||||||
|
#include "c4/yml/node.hpp"
|
||||||
|
#include <c4/std/vector.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
// vector is a sequence-like type, and it requires child nodes
|
||||||
|
// in the data tree hierarchy (a SEQ node in ryml parlance).
|
||||||
|
// So it should be serialized via write()/read().
|
||||||
|
|
||||||
|
|
||||||
|
template<class V, class Alloc>
|
||||||
|
void write(c4::yml::NodeRef *n, std::vector<V, Alloc> const& vec)
|
||||||
|
{
|
||||||
|
*n |= c4::yml::SEQ;
|
||||||
|
for(auto const& v : vec)
|
||||||
|
n->append_child() << v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class V, class Alloc>
|
||||||
|
bool read(c4::yml::ConstNodeRef const& n, std::vector<V, Alloc> *vec)
|
||||||
|
{
|
||||||
|
vec->resize(n.num_children());
|
||||||
|
size_t pos = 0;
|
||||||
|
for(auto const ch : n)
|
||||||
|
ch >> (*vec)[pos++];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** specialization: std::vector<bool> uses std::vector<bool>::reference as
|
||||||
|
* the return value of its operator[]. */
|
||||||
|
template<class Alloc>
|
||||||
|
bool read(c4::yml::ConstNodeRef const& n, std::vector<bool, Alloc> *vec)
|
||||||
|
{
|
||||||
|
vec->resize(n.num_children());
|
||||||
|
size_t pos = 0;
|
||||||
|
bool tmp;
|
||||||
|
for(auto const ch : n)
|
||||||
|
{
|
||||||
|
ch >> tmp;
|
||||||
|
(*vec)[pos++] = tmp;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif // _C4_YML_STD_VECTOR_HPP_
|
1496
dep/rapidyaml/include/c4/yml/tree.hpp
Normal file
1496
dep/rapidyaml/include/c4/yml/tree.hpp
Normal file
File diff suppressed because it is too large
Load diff
229
dep/rapidyaml/include/c4/yml/writer.hpp
Normal file
229
dep/rapidyaml/include/c4/yml/writer.hpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
#ifndef _C4_YML_WRITER_HPP_
|
||||||
|
#define _C4_YML_WRITER_HPP_
|
||||||
|
|
||||||
|
#ifndef _C4_YML_COMMON_HPP_
|
||||||
|
#include "./common.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <c4/substr.hpp>
|
||||||
|
#include <stdio.h> // fwrite(), fputc()
|
||||||
|
#include <string.h> // memcpy()
|
||||||
|
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
|
||||||
|
/** Repeat-Character: a character to be written a number of times. */
|
||||||
|
struct RepC
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
size_t num_times;
|
||||||
|
};
|
||||||
|
inline RepC indent_to(size_t num_levels)
|
||||||
|
{
|
||||||
|
return {' ', size_t(2) * num_levels};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** A writer that outputs to a file. Defaults to stdout. */
|
||||||
|
struct WriterFile
|
||||||
|
{
|
||||||
|
FILE * m_file;
|
||||||
|
size_t m_pos;
|
||||||
|
|
||||||
|
WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}
|
||||||
|
|
||||||
|
inline substr _get(bool /*error_on_excess*/)
|
||||||
|
{
|
||||||
|
substr sp;
|
||||||
|
sp.str = nullptr;
|
||||||
|
sp.len = m_pos;
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline void _do_write(const char (&a)[N])
|
||||||
|
{
|
||||||
|
fwrite(a, sizeof(char), N - 1, m_file);
|
||||||
|
m_pos += N - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(csubstr sp)
|
||||||
|
{
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif
|
||||||
|
if(sp.empty()) return;
|
||||||
|
fwrite(sp.str, sizeof(csubstr::char_type), sp.len, m_file);
|
||||||
|
m_pos += sp.len;
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(const char c)
|
||||||
|
{
|
||||||
|
fputc(c, m_file);
|
||||||
|
++m_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(RepC const rc)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < rc.num_times; ++i)
|
||||||
|
{
|
||||||
|
fputc(rc.c, m_file);
|
||||||
|
}
|
||||||
|
m_pos += rc.num_times;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** A writer that outputs to an STL-like ostream. */
|
||||||
|
template<class OStream>
|
||||||
|
struct WriterOStream
|
||||||
|
{
|
||||||
|
OStream& m_stream;
|
||||||
|
size_t m_pos;
|
||||||
|
|
||||||
|
WriterOStream(OStream &s) : m_stream(s), m_pos(0) {}
|
||||||
|
|
||||||
|
inline substr _get(bool /*error_on_excess*/)
|
||||||
|
{
|
||||||
|
substr sp;
|
||||||
|
sp.str = nullptr;
|
||||||
|
sp.len = m_pos;
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline void _do_write(const char (&a)[N])
|
||||||
|
{
|
||||||
|
m_stream.write(a, N - 1);
|
||||||
|
m_pos += N - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(csubstr sp)
|
||||||
|
{
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif
|
||||||
|
if(sp.empty()) return;
|
||||||
|
m_stream.write(sp.str, sp.len);
|
||||||
|
m_pos += sp.len;
|
||||||
|
#if defined(__clang__)
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(const char c)
|
||||||
|
{
|
||||||
|
m_stream.put(c);
|
||||||
|
++m_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(RepC const rc)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < rc.num_times; ++i)
|
||||||
|
{
|
||||||
|
m_stream.put(rc.c);
|
||||||
|
}
|
||||||
|
m_pos += rc.num_times;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** a writer to a substr */
|
||||||
|
struct WriterBuf
|
||||||
|
{
|
||||||
|
substr m_buf;
|
||||||
|
size_t m_pos;
|
||||||
|
|
||||||
|
WriterBuf(substr sp) : m_buf(sp), m_pos(0) {}
|
||||||
|
|
||||||
|
inline substr _get(bool error_on_excess)
|
||||||
|
{
|
||||||
|
if(m_pos <= m_buf.len)
|
||||||
|
{
|
||||||
|
return m_buf.first(m_pos);
|
||||||
|
}
|
||||||
|
if(error_on_excess)
|
||||||
|
{
|
||||||
|
c4::yml::error("not enough space in the given buffer");
|
||||||
|
}
|
||||||
|
substr sp;
|
||||||
|
sp.str = nullptr;
|
||||||
|
sp.len = m_pos;
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline void _do_write(const char (&a)[N])
|
||||||
|
{
|
||||||
|
RYML_ASSERT( ! m_buf.overlaps(a));
|
||||||
|
if(m_pos + N-1 <= m_buf.len)
|
||||||
|
{
|
||||||
|
memcpy(&(m_buf[m_pos]), a, N-1);
|
||||||
|
}
|
||||||
|
m_pos += N-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(csubstr sp)
|
||||||
|
{
|
||||||
|
if(sp.empty()) return;
|
||||||
|
RYML_ASSERT( ! sp.overlaps(m_buf));
|
||||||
|
if(m_pos + sp.len <= m_buf.len)
|
||||||
|
{
|
||||||
|
memcpy(&(m_buf[m_pos]), sp.str, sp.len);
|
||||||
|
}
|
||||||
|
m_pos += sp.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(const char c)
|
||||||
|
{
|
||||||
|
if(m_pos + 1 <= m_buf.len)
|
||||||
|
{
|
||||||
|
m_buf[m_pos] = c;
|
||||||
|
}
|
||||||
|
++m_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void _do_write(RepC const rc)
|
||||||
|
{
|
||||||
|
if(m_pos + rc.num_times <= m_buf.len)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < rc.num_times; ++i)
|
||||||
|
{
|
||||||
|
m_buf[m_pos + i] = rc.c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_pos += rc.num_times;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#endif /* _C4_YML_WRITER_HPP_ */
|
10
dep/rapidyaml/include/c4/yml/yml.hpp
Normal file
10
dep/rapidyaml/include/c4/yml/yml.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _C4_YML_YML_HPP_
|
||||||
|
#define _C4_YML_YML_HPP_
|
||||||
|
|
||||||
|
#include "c4/yml/tree.hpp"
|
||||||
|
#include "c4/yml/node.hpp"
|
||||||
|
#include "c4/yml/emit.hpp"
|
||||||
|
#include "c4/yml/parse.hpp"
|
||||||
|
#include "c4/yml/preprocess.hpp"
|
||||||
|
|
||||||
|
#endif // _C4_YML_YML_HPP_
|
391
dep/rapidyaml/include/ryml-gdbtypes.py
Normal file
391
dep/rapidyaml/include/ryml-gdbtypes.py
Normal file
|
@ -0,0 +1,391 @@
|
||||||
|
# To make this file known to Qt Creator using:
|
||||||
|
# Tools > Options > Debugger > Locals & Expressions > Extra Debugging Helpers
|
||||||
|
# Any contents here will be picked up by GDB, LLDB, and CDB based
|
||||||
|
# debugging in Qt Creator automatically.
|
||||||
|
|
||||||
|
|
||||||
|
# Example to display a simple type
|
||||||
|
# template<typename U, typename V> struct MapNode
|
||||||
|
# {
|
||||||
|
# U key;
|
||||||
|
# V data;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# def qdump__MapNode(d, value):
|
||||||
|
# d.putValue("This is the value column contents")
|
||||||
|
# d.putExpandable()
|
||||||
|
# if d.isExpanded():
|
||||||
|
# with Children(d):
|
||||||
|
# # Compact simple case.
|
||||||
|
# d.putSubItem("key", value["key"])
|
||||||
|
# # Same effect, with more customization possibilities.
|
||||||
|
# with SubItem(d, "data")
|
||||||
|
# d.putItem("data", value["data"])
|
||||||
|
|
||||||
|
# Check http://doc.qt.io/qtcreator/creator-debugging-helpers.html
|
||||||
|
# for more details or look at qttypes.py, stdtypes.py, boosttypes.py
|
||||||
|
# for more complex examples.
|
||||||
|
|
||||||
|
# to try parsing:
|
||||||
|
# env PYTHONPATH=/usr/share/qtcreator/debugger/ python src/ryml-gdbtypes.py
|
||||||
|
|
||||||
|
|
||||||
|
import dumper
|
||||||
|
#from dumper import Dumper, Value, Children, SubItem
|
||||||
|
#from dumper import SubItem, Children
|
||||||
|
from dumper import *
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# QtCreator makes it really hard to figure out problems in this code.
|
||||||
|
# So here are some debugging utilities.
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME. this decorator is not working; find out why.
|
||||||
|
def dbglog(func):
|
||||||
|
"""a decorator that logs entry and exit of functions"""
|
||||||
|
if not _DBG:
|
||||||
|
return func
|
||||||
|
def func_wrapper(*args, **kwargs):
|
||||||
|
_dbg_enter(func.__name__)
|
||||||
|
ret = func(*args, **kwargs)
|
||||||
|
_dbg_exit(func.__name__)
|
||||||
|
return ret
|
||||||
|
return func_wrapper
|
||||||
|
|
||||||
|
|
||||||
|
_DBG = False
|
||||||
|
_dbg_log = None
|
||||||
|
_dbg_stack = 0
|
||||||
|
def _dbg(*args, **kwargs):
|
||||||
|
global _dbg_log, _dbg_stack
|
||||||
|
if not _DBG:
|
||||||
|
return
|
||||||
|
if _dbg_log is None:
|
||||||
|
filename = os.path.join(os.path.dirname(__file__), "dbg.txt")
|
||||||
|
_dbg_log = open(filename, "w")
|
||||||
|
kwargs['file'] = _dbg_log
|
||||||
|
kwargs['flush'] = True
|
||||||
|
print(" " * _dbg_stack, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _dbg_enter(name):
|
||||||
|
global _dbg_stack
|
||||||
|
_dbg(name, "- enter")
|
||||||
|
_dbg_stack += 1
|
||||||
|
|
||||||
|
|
||||||
|
def _dbg_exit(name):
|
||||||
|
global _dbg_stack
|
||||||
|
_dbg_stack -= 1
|
||||||
|
_dbg(name, "- exit!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
NPOS = 18446744073709551615
|
||||||
|
MAX_SUBSTR_LEN_DISPLAY = 80
|
||||||
|
MAX_SUBSTR_LEN_EXPAND = 1000
|
||||||
|
|
||||||
|
|
||||||
|
def get_str_value(d, value, limit=0):
|
||||||
|
# adapted from dumper.py::Dumper::putCharArrayValue()
|
||||||
|
m_str = value["str"].pointer()
|
||||||
|
m_len = value["len"].integer()
|
||||||
|
if m_len == NPOS:
|
||||||
|
_dbg("getstr... 1", m_len)
|
||||||
|
m_str = "!!!!!<npos>!!!!!"
|
||||||
|
m_len = len(m_str)
|
||||||
|
return m_str, m_len
|
||||||
|
if limit == 0:
|
||||||
|
limit = d.displayStringLimit
|
||||||
|
elided, shown = d.computeLimit(m_len, limit)
|
||||||
|
mem = bytes(d.readRawMemory(m_str, shown))
|
||||||
|
mem = mem.decode('utf8')
|
||||||
|
return mem, m_len
|
||||||
|
|
||||||
|
|
||||||
|
def __display_csubstr(d, value, limit=0):
|
||||||
|
m_str, m_len = get_str_value(d, value)
|
||||||
|
safe_len = min(m_len, MAX_SUBSTR_LEN_DISPLAY)
|
||||||
|
disp = m_str[0:safe_len]
|
||||||
|
# ensure the string escapes characters like \n\r\t etc
|
||||||
|
disp = disp.encode('unicode_escape').decode('utf8')
|
||||||
|
# WATCHOUT. quotes in the string will make qtcreator hang!!!
|
||||||
|
disp = disp.replace('"', '\\"')
|
||||||
|
disp = disp.replace('\'', '\\')
|
||||||
|
if m_len <= MAX_SUBSTR_LEN_DISPLAY:
|
||||||
|
d.putValue(f"[{m_len}] '{disp}'")
|
||||||
|
else:
|
||||||
|
d.putValue(f"[{m_len}] '{disp}'...")
|
||||||
|
return m_str, m_len
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__csubstr(d, value):
|
||||||
|
m_str, m_len = __display_csubstr(d, value)
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
safe_len = min(m_len, MAX_SUBSTR_LEN_EXPAND)
|
||||||
|
for i in range(safe_len):
|
||||||
|
ct = d.createType('char')
|
||||||
|
d.putSubItem(safe_len, d.createValue(value["str"].pointer() + i, ct))
|
||||||
|
d.putSubItem("len", value["len"])
|
||||||
|
d.putPtrItem("str", value["str"].pointer())
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__substr(d, value):
|
||||||
|
qdump__c4__csubstr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__basic_substring(d, value):
|
||||||
|
qdump__c4__csubstr(d, value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__NodeScalar(d, value):
|
||||||
|
alen = value["anchor"]["len"].integer()
|
||||||
|
tlen = value["tag" ]["len"].integer()
|
||||||
|
m_str, m_len = get_str_value(d, value["scalar"])
|
||||||
|
if alen == 0 and tlen == 0:
|
||||||
|
d.putValue(f'\'{m_str}\'')
|
||||||
|
elif alen == 0 and tlen > 0:
|
||||||
|
d.putValue(f'\'{m_str}\' [Ta]')
|
||||||
|
elif alen > 0 and tlen == 0:
|
||||||
|
d.putValue(f'\'{m_str}\' [tA]')
|
||||||
|
elif alen > 0 and tlen > 0:
|
||||||
|
d.putValue(f'\'{m_str}\' [TA]')
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("[scalar]", value["scalar"])
|
||||||
|
if tlen > 0:
|
||||||
|
d.putSubItem("[tag]", value["tag"])
|
||||||
|
if alen > 0:
|
||||||
|
d.putSubItem("[anchor or ref]", value["anchor"])
|
||||||
|
|
||||||
|
|
||||||
|
def _format_enum_value(int_value, enum_map):
|
||||||
|
str_value = enum_map.get(int_value, None)
|
||||||
|
display = f'{int_value}' if str_value is None else f'{str_value} ({int_value})'
|
||||||
|
return display
|
||||||
|
|
||||||
|
|
||||||
|
def _format_bitmask_value(int_value, enum_map):
|
||||||
|
str_value = enum_map.get(int_value, None)
|
||||||
|
if str_value:
|
||||||
|
return f'{str_value} ({int_value})'
|
||||||
|
else:
|
||||||
|
out = ""
|
||||||
|
orig = int_value
|
||||||
|
# do in reverse to get compound flags first
|
||||||
|
for k, v in reversed(enum_map.items()):
|
||||||
|
if (k != 0):
|
||||||
|
if (int_value & k) == k:
|
||||||
|
if len(out) > 0:
|
||||||
|
out += '|'
|
||||||
|
out += v
|
||||||
|
int_value &= ~k
|
||||||
|
else:
|
||||||
|
if len(out) == 0 and int_value == 0:
|
||||||
|
return v
|
||||||
|
if out == "":
|
||||||
|
return f'{int_value}'
|
||||||
|
return f"{out} ({orig})"
|
||||||
|
|
||||||
|
|
||||||
|
def _c4bit(*ints):
|
||||||
|
ret = 0
|
||||||
|
for i in ints:
|
||||||
|
ret |= 1 << i
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
node_types = {
|
||||||
|
0: "NOTYPE",
|
||||||
|
_c4bit(0): "VAL" ,
|
||||||
|
_c4bit(1): "KEY" ,
|
||||||
|
_c4bit(2): "MAP" ,
|
||||||
|
_c4bit(3): "SEQ" ,
|
||||||
|
_c4bit(4): "DOC" ,
|
||||||
|
_c4bit(5,3): "STREAM",
|
||||||
|
_c4bit(6): "KEYREF" ,
|
||||||
|
_c4bit(7): "VALREF" ,
|
||||||
|
_c4bit(8): "KEYANCH" ,
|
||||||
|
_c4bit(9): "VALANCH" ,
|
||||||
|
_c4bit(10): "KEYTAG" ,
|
||||||
|
_c4bit(11): "VALTAG" ,
|
||||||
|
_c4bit(12): "VALQUO" ,
|
||||||
|
_c4bit(13): "KEYQUO" ,
|
||||||
|
_c4bit(1,0): "KEYVAL",
|
||||||
|
_c4bit(1,3): "KEYSEQ",
|
||||||
|
_c4bit(1,2): "KEYMAP",
|
||||||
|
_c4bit(4,2): "DOCMAP",
|
||||||
|
_c4bit(4,3): "DOCSEQ",
|
||||||
|
_c4bit(4,0): "DOCVAL",
|
||||||
|
#
|
||||||
|
_c4bit(14): "STYLE_FLOW_SL",
|
||||||
|
_c4bit(15): "STYLE_FLOW_ML",
|
||||||
|
_c4bit(16): "STYLE_BLOCK",
|
||||||
|
#
|
||||||
|
_c4bit(17): "KEY_LITERAL",
|
||||||
|
_c4bit(18): "VAL_LITERAL",
|
||||||
|
_c4bit(19): "KEY_FOLDED",
|
||||||
|
_c4bit(20): "VAL_FOLDED",
|
||||||
|
_c4bit(21): "KEY_SQUO",
|
||||||
|
_c4bit(22): "VAL_SQUO",
|
||||||
|
_c4bit(23): "KEY_DQUO",
|
||||||
|
_c4bit(24): "VAL_DQUO",
|
||||||
|
_c4bit(25): "KEY_PLAIN",
|
||||||
|
_c4bit(26): "VAL_PLAIN",
|
||||||
|
}
|
||||||
|
node_types_rev = {v: k for k, v in node_types.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def _node_type_has_all(node_type_value, type_name):
|
||||||
|
exp = node_types_rev[type_name]
|
||||||
|
return (node_type_value & exp) == exp
|
||||||
|
|
||||||
|
|
||||||
|
def _node_type_has_any(node_type_value, type_name):
|
||||||
|
exp = node_types_rev[type_name]
|
||||||
|
return (node_type_value & exp) != 0
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__NodeType_e(d, value):
|
||||||
|
v = _format_bitmask_value(value.integer(), node_types)
|
||||||
|
d.putValue(v)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__NodeType(d, value):
|
||||||
|
qdump__c4__yml__NodeType_e(d, value["type"])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__NodeData(d, value):
|
||||||
|
d.putValue("wtf")
|
||||||
|
ty = _format_bitmask_value(value.integer(), node_types)
|
||||||
|
t = value["m_type"]["type"].integer()
|
||||||
|
k = value["m_key"]["scalar"]
|
||||||
|
v = value["m_val"]["scalar"]
|
||||||
|
sk, lk = get_str_value(d, k)
|
||||||
|
sv, lv = get_str_value(d, v)
|
||||||
|
if _node_type_has_all(t, "KEYVAL"):
|
||||||
|
d.putValue(f"'{sk}': '{sv}' {ty}")
|
||||||
|
elif _node_type_has_any(t, "KEY"):
|
||||||
|
d.putValue(f"'{sk}': {ty}")
|
||||||
|
elif _node_type_has_any(t, "VAL"):
|
||||||
|
d.putValue(f"'{sv}' {ty}")
|
||||||
|
else:
|
||||||
|
d.putValue(f"{ty}")
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("m_type", value["m_type"])
|
||||||
|
# key
|
||||||
|
if _node_type_has_any(t, "KEY"):
|
||||||
|
d.putSubItem("m_key", value["m_key"])
|
||||||
|
if _node_type_has_any(t, "KEYREF"):
|
||||||
|
with SubItem(d, "m_key.ref"):
|
||||||
|
s_, _ = get_str_value(d, value["m_key"]["anchor"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
if _node_type_has_any(t, "KEYANCH"):
|
||||||
|
with SubItem(d, "m_key.anchor"):
|
||||||
|
s_, _ = get_str_value(d, value["m_key"]["anchor"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
if _node_type_has_any(t, "KEYTAG"):
|
||||||
|
with SubItem(d, "m_key.tag"):
|
||||||
|
s_, _ = get_str_value(d, value["m_key"]["tag"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
# val
|
||||||
|
if _node_type_has_any(t, "VAL"):
|
||||||
|
d.putSubItem("m_val", value["m_val"])
|
||||||
|
if _node_type_has_any(t, "VALREF"):
|
||||||
|
with SubItem(d, "m_val.ref"):
|
||||||
|
s_, _ = get_str_value(d, value["m_val"]["anchor"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
if _node_type_has_any(t, "VALANCH"):
|
||||||
|
with SubItem(d, "m_val.anchor"):
|
||||||
|
s_, _ = get_str_value(d, value["m_val"]["anchor"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
if _node_type_has_any(t, "VALTAG"):
|
||||||
|
with SubItem(d, "m_val.tag"):
|
||||||
|
s_, _ = get_str_value(d, value["m_val"]["tag"])
|
||||||
|
d.putValue(f"'{s_}'")
|
||||||
|
# hierarchy
|
||||||
|
_dump_node_index(d, "m_parent", value)
|
||||||
|
_dump_node_index(d, "m_first_child", value)
|
||||||
|
_dump_node_index(d, "m_last_child", value)
|
||||||
|
_dump_node_index(d, "m_next_sibling", value)
|
||||||
|
_dump_node_index(d, "m_prev_sibling", value)
|
||||||
|
|
||||||
|
|
||||||
|
def _dump_node_index(d, name, value):
|
||||||
|
if int(value[name].integer()) == NPOS:
|
||||||
|
pass
|
||||||
|
#with SubItem(d, name):
|
||||||
|
# d.putValue("-")
|
||||||
|
else:
|
||||||
|
d.putSubItem(name, value[name])
|
||||||
|
|
||||||
|
|
||||||
|
# c4::yml::Tree
|
||||||
|
def qdump__c4__yml__Tree(d, value):
|
||||||
|
m_size = value["m_size"].integer()
|
||||||
|
m_cap = value["m_cap"].integer()
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
#d.putArrayData(value["m_buf"], m_size, value["m_buf"].dereference())
|
||||||
|
with Children(d):
|
||||||
|
with SubItem(d, f"[nodes]"):
|
||||||
|
d.putItemCount(m_size)
|
||||||
|
d.putArrayData(value["m_buf"].pointer(), m_size, value["m_buf"].type.dereference())
|
||||||
|
d.putPtrItem("m_buf", value["m_buf"].pointer())
|
||||||
|
d.putIntItem("m_size", value["m_size"])
|
||||||
|
d.putIntItem("m_cap (capacity)", value["m_cap"])
|
||||||
|
d.putIntItem("[slack]", m_cap - m_size)
|
||||||
|
d.putIntItem("m_free_head", value["m_free_head"])
|
||||||
|
d.putIntItem("m_free_tail", value["m_free_tail"])
|
||||||
|
d.putSubItem("m_arena", value["m_arena"])
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__detail__stack(d, value):
|
||||||
|
T = value.type[0]
|
||||||
|
N = value.type[0]
|
||||||
|
m_size = value["m_size"].integer()
|
||||||
|
m_capacity = value["m_capacity"].integer()
|
||||||
|
d.putItemCount(m_size)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
with SubItem(d, f"[nodes]"):
|
||||||
|
d.putItemCount(m_size)
|
||||||
|
d.putArrayData(value["m_stack"].pointer(), m_size, T)
|
||||||
|
d.putIntItem("m_size", value["m_size"])
|
||||||
|
d.putIntItem("m_capacity", value["m_capacity"])
|
||||||
|
#d.putIntItem("[small capacity]", N)
|
||||||
|
d.putIntItem("[is large]", value["m_buf"].address() == value["m_stack"].pointer())
|
||||||
|
d.putPtrItem("m_stack", value["m_stack"].pointer())
|
||||||
|
d.putPtrItem("m_buf", value["m_buf"].address())
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__c4__yml__detail__ReferenceResolver__refdata(d, value):
|
||||||
|
node = value["node"].integer()
|
||||||
|
ty = _format_bitmask_value(value["type"].integer(), node_types)
|
||||||
|
d.putValue(f'{node} {ty}')
|
||||||
|
d.putExpandable()
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putSubItem("type", value["type"])
|
||||||
|
d.putSubItem("node", value["node"])
|
||||||
|
_dump_node_index(d, "prev_anchor", value)
|
||||||
|
_dump_node_index(d, "target", value)
|
||||||
|
_dump_node_index(d, "parent_ref", value)
|
||||||
|
_dump_node_index(d, "parent_ref_sibling", value)
|
11
dep/rapidyaml/include/ryml.hpp
Normal file
11
dep/rapidyaml/include/ryml.hpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _RYML_HPP_
|
||||||
|
#define _RYML_HPP_
|
||||||
|
|
||||||
|
#include "c4/yml/yml.hpp"
|
||||||
|
|
||||||
|
namespace ryml {
|
||||||
|
using namespace c4::yml;
|
||||||
|
using namespace c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _RYML_HPP_ */
|
194
dep/rapidyaml/include/ryml.natvis
Normal file
194
dep/rapidyaml/include/ryml.natvis
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Very good intro:
|
||||||
|
@see https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2017
|
||||||
|
@see https://code.msdn.microsoft.com/windowsdesktop/Writing-type-visualizers-2eae77a2
|
||||||
|
See also:
|
||||||
|
@see http://blogs.msdn.com/b/vcblog/archive/2013/06/28/using-visual-studio-2013-to-write-maintainable-native-visualizations-natvis.aspx?PageIndex=2
|
||||||
|
@see http://blogs.msdn.com/b/vcblog/archive/2015/09/28/debug-visualizers-in-visual-c-2015.aspx
|
||||||
|
@see http://stackoverflow.com/questions/36883414/limit-display-of-char-in-natvis-file-to-specific-length
|
||||||
|
-->
|
||||||
|
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
|
<Type Name="c4::yml::NodeScalar">
|
||||||
|
<DisplayString Condition="(tag.len == 0) && (anchor.len == 0)">{scalar.str,[scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="(tag.len > 0) && (anchor.len == 0)">{scalar.str,[scalar.len]} [T]</DisplayString>
|
||||||
|
<DisplayString Condition="(tag.len == 0) && (anchor.len > 0)">{scalar.str,[scalar.len]} [A]</DisplayString>
|
||||||
|
<DisplayString Condition="(tag.len > 0) && (anchor.len > 0)">{scalar.str,[scalar.len]} [T][A]</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="scalar">scalar</Item>
|
||||||
|
<Item Name="tag">tag</Item>
|
||||||
|
<Item Name="anchor">anchor</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::NodeType">
|
||||||
|
<DisplayString>{type}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[enabled bits]">
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[0]" Condition="(type & c4::yml::VAL) != 0">c4::yml::VAL</Item>
|
||||||
|
<Item Name="[1]" Condition="(type & c4::yml::KEY) != 0">c4::yml::KEY</Item>
|
||||||
|
<Item Name="[2]" Condition="(type & c4::yml::MAP) != 0">c4::yml::MAP</Item>
|
||||||
|
<Item Name="[3]" Condition="(type & c4::yml::SEQ) != 0">c4::yml::SEQ</Item>
|
||||||
|
<Item Name="[4]" Condition="(type & c4::yml::DOC) != 0">c4::yml::DOC</Item>
|
||||||
|
<Item Name="[5]" Condition="(type & c4::yml::STREAM) != 0">c4::yml::STREAM</Item>
|
||||||
|
<Item Name="[6]" Condition="(type & c4::yml::KEYREF) != 0">c4::yml::KEYREF</Item>
|
||||||
|
<Item Name="[7]" Condition="(type & c4::yml::VALREF) != 0">c4::yml::VALREF</Item>
|
||||||
|
<Item Name="[8]" Condition="(type & c4::yml::KEYANCH) != 0">c4::yml::KEYANCH</Item>
|
||||||
|
<Item Name="[9]" Condition="(type & c4::yml::VALANCH) != 0">c4::yml::VALANCH</Item>
|
||||||
|
<Item Name="[10]" Condition="(type & c4::yml::KEYTAG) != 0">c4::yml::KEYTAG</Item>
|
||||||
|
<Item Name="[11]" Condition="(type & c4::yml::VALTAG) != 0">c4::yml::VALTAG</Item>
|
||||||
|
<Item Name="[12]" Condition="(type & c4::yml::VALQUO) != 0">c4::yml::VALQUO</Item>
|
||||||
|
<Item Name="[13]" Condition="(type & c4::yml::KEYQUO) != 0">c4::yml::KEYQUO</Item>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::NodeData">
|
||||||
|
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::VAL) == c4::yml::VAL)">[KEYVAL] {m_key.scalar.str,[m_key.scalar.len]}: {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::SEQ) == c4::yml::SEQ)">[KEYSEQ] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="((m_type.type & c4::yml::KEY ) == c4::yml::KEY) && ((m_type.type & c4::yml::MAP) == c4::yml::MAP)">[KEYMAP] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="((m_type.type & c4::yml::DOC ) == c4::yml::DOC) && ((m_type.type & c4::yml::SEQ) == c4::yml::SEQ)">[DOCSEQ]</DisplayString>
|
||||||
|
<DisplayString Condition="((m_type.type & c4::yml::DOC ) == c4::yml::DOC) && ((m_type.type & c4::yml::MAP) == c4::yml::MAP)">[DOCMAP]</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::VAL ) == c4::yml::VAL" >[VAL] {m_val.scalar.str,[m_val.scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::KEY ) == c4::yml::KEY" >[KEY] {m_key.scalar.str,[m_key.scalar.len]}</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::SEQ ) == c4::yml::SEQ" >[SEQ]</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::MAP ) == c4::yml::MAP" >[MAP]</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::DOC ) == c4::yml::DOC" >[DOC]</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::STREAM) == c4::yml::STREAM">[STREAM]</DisplayString>
|
||||||
|
<DisplayString Condition="(m_type.type & c4::yml::NOTYPE) == c4::yml::NOTYPE">[NOTYPE]</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="type">m_type</Item>
|
||||||
|
<Item Name="key" Condition="(m_type.type & c4::yml::KEY) != 0">m_key</Item>
|
||||||
|
<Item Name="val" Condition="(m_type.type & c4::yml::VAL) != 0">m_val</Item>
|
||||||
|
<Item Name="key quoted" Condition="((m_type.type & c4::yml::KEY) != 0) && ((m_type.type & c4::yml::KEYQUO) != 0)">c4::yml::KEYQUO</Item>
|
||||||
|
<Item Name="val quoted" Condition="((m_type.type & c4::yml::VAL) != 0) && ((m_type.type & c4::yml::VALQUO) != 0)">c4::yml::VALQUO</Item>
|
||||||
|
<Item Name="key ref" Condition="(m_type.type & c4::yml::KEYREF) != 0">m_key.anchor</Item>
|
||||||
|
<Item Name="val ref" Condition="(m_type.type & c4::yml::VALREF) != 0">m_val.anchor</Item>
|
||||||
|
<Item Name="key anchor" Condition="(m_type.type & c4::yml::KEYANCH) != 0">m_key.anchor</Item>
|
||||||
|
<Item Name="val anchor" Condition="(m_type.type & c4::yml::VALANCH) != 0">m_val.anchor</Item>
|
||||||
|
<Item Name="parent">m_parent</Item>
|
||||||
|
<Item Name="first child" Condition="m_first_child != c4::yml::NONE">m_first_child</Item>
|
||||||
|
<Item Name="last child" Condition="m_last_child != c4::yml::NONE">m_last_child</Item>
|
||||||
|
<Item Name="prev sibling" Condition="m_prev_sibling != c4::yml::NONE">m_prev_sibling</Item>
|
||||||
|
<Item Name="next sibling" Condition="m_next_sibling != c4::yml::NONE">m_next_sibling</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::Tree">
|
||||||
|
<DisplayString>sz={m_size}, cap={m_cap}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<Item Name="[capacity]">m_cap</Item>
|
||||||
|
<Synthetic Name="[buffer]">
|
||||||
|
<Expand>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_cap</Size>
|
||||||
|
<ValuePointer>m_buf</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
<Item Name="free head">m_free_head</Item>
|
||||||
|
<Item Name="arena">m_arena</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::Tree::_lookup_path_token">
|
||||||
|
<DisplayString>{value} ({type})</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="value">value</Item>
|
||||||
|
<Item Name="type">type</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::Tree::lookup_result">
|
||||||
|
<DisplayString>{path} -- target={target} closest={closest}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="target">target</Item>
|
||||||
|
<Item Name="closest">closest</Item>
|
||||||
|
<Item Name="path_pos">path_pos</Item>
|
||||||
|
<Item Name="path">path</Item>
|
||||||
|
<Synthetic Name="[resolved]">
|
||||||
|
<DisplayString>{path.str,[path_pos]}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[unresolved]">
|
||||||
|
<DisplayString>{path.str+path_pos,[path.len-path_pos]}</DisplayString>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::NodeRef">
|
||||||
|
<DisplayString Condition="(m_id == c4::yml::NONE)">(void)</DisplayString>
|
||||||
|
<DisplayString Condition="(m_seed.len != c4::yml::NONE) && (m_seed.str == nullptr)">[INDEX SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
|
||||||
|
<DisplayString Condition="(m_seed.len != c4::yml::NONE) && (m_seed.str != nullptr)">[NAMED SEED for] {*(m_tree->m_buf + m_id)}</DisplayString>
|
||||||
|
<DisplayString>{*(m_tree->m_buf + m_id)}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="id">m_id</Item>
|
||||||
|
<Item Name="elm">*(m_tree->m_buf + m_id)</Item>
|
||||||
|
<Item Name="tree">m_tree</Item>
|
||||||
|
<Synthetic Name="[children]" Condition="(m_id != c4::yml::NONE) && ((m_tree->m_buf + m_id)->m_type.type & (c4::yml::MAP|c4::yml::SEQ) != 0)">
|
||||||
|
<Expand>
|
||||||
|
<CustomListItems>
|
||||||
|
<Variable Name="tree" InitialValue="m_tree"/>
|
||||||
|
<Variable Name="buf" InitialValue="m_tree->m_buf"/>
|
||||||
|
<Variable Name="curr" InitialValue="(m_tree->m_buf + m_id)->m_first_child"/>
|
||||||
|
<Loop>
|
||||||
|
<Item>buf + curr</Item>
|
||||||
|
<Exec>curr = (buf + curr)->m_next_sibling</Exec>
|
||||||
|
<Break Condition="curr == c4::yml::NONE"/>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::detail::ReferenceResolver">
|
||||||
|
<DisplayString>#refs={refs.m_size} #nodes={t->m_size}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Synthetic Name="[ref_nodes]">
|
||||||
|
<Expand>
|
||||||
|
<CustomListItems>
|
||||||
|
<Variable Name="curr" InitialValue="0"/>
|
||||||
|
<Loop>
|
||||||
|
<Item>t->m_buf + (refs.m_stack + curr)->node</Item>
|
||||||
|
<Exec>curr = curr+1</Exec>
|
||||||
|
<Break Condition="curr >= refs.m_size"/>
|
||||||
|
</Loop>
|
||||||
|
</CustomListItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
<Synthetic Name="[refs]">
|
||||||
|
<Expand>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>refs.m_size</Size>
|
||||||
|
<ValuePointer>refs.m_stack</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
<Item Name="[tree]">t</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="c4::yml::detail::stack<*,*>">
|
||||||
|
<DisplayString>sz={m_size} cap={m_capacity}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[size]">m_size</Item>
|
||||||
|
<Item Name="[capacity]">m_capacity</Item>
|
||||||
|
<Item Name="[is small]">m_buf == m_stack</Item>
|
||||||
|
<Synthetic Name="[items]">
|
||||||
|
<Expand>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>m_size</Size>
|
||||||
|
<ValuePointer>m_stack</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Synthetic>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
</AutoVisualizer>
|
6
dep/rapidyaml/include/ryml_std.hpp
Normal file
6
dep/rapidyaml/include/ryml_std.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _RYML_STD_HPP_
|
||||||
|
#define _RYML_STD_HPP_
|
||||||
|
|
||||||
|
#include "./c4/yml/std/std.hpp"
|
||||||
|
|
||||||
|
#endif /* _RYML_STD_HPP_ */
|
85
dep/rapidyaml/rapidyaml.vcxproj
Normal file
85
dep/rapidyaml/rapidyaml.vcxproj
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\msvc\vsprops\Configurations.props" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="include\c4\base64.hpp" />
|
||||||
|
<ClInclude Include="include\c4\blob.hpp" />
|
||||||
|
<ClInclude Include="include\c4\charconv.hpp" />
|
||||||
|
<ClInclude Include="include\c4\compiler.hpp" />
|
||||||
|
<ClInclude Include="include\c4\config.hpp" />
|
||||||
|
<ClInclude Include="include\c4\cpu.hpp" />
|
||||||
|
<ClInclude Include="include\c4\dump.hpp" />
|
||||||
|
<ClInclude Include="include\c4\error.hpp" />
|
||||||
|
<ClInclude Include="include\c4\export.hpp" />
|
||||||
|
<ClInclude Include="include\c4\format.hpp" />
|
||||||
|
<ClInclude Include="include\c4\language.hpp" />
|
||||||
|
<ClInclude Include="include\c4\memory_util.hpp" />
|
||||||
|
<ClInclude Include="include\c4\platform.hpp" />
|
||||||
|
<ClInclude Include="include\c4\preprocessor.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\std.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\std_fwd.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\string.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\string_fwd.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\string_view.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\tuple.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\vector.hpp" />
|
||||||
|
<ClInclude Include="include\c4\std\vector_fwd.hpp" />
|
||||||
|
<ClInclude Include="include\c4\substr.hpp" />
|
||||||
|
<ClInclude Include="include\c4\substr_fwd.hpp" />
|
||||||
|
<ClInclude Include="include\c4\szconv.hpp" />
|
||||||
|
<ClInclude Include="include\c4\types.hpp" />
|
||||||
|
<ClInclude Include="include\c4\utf.hpp" />
|
||||||
|
<ClInclude Include="include\c4\windows.hpp" />
|
||||||
|
<ClInclude Include="include\c4\windows_pop.hpp" />
|
||||||
|
<ClInclude Include="include\c4\windows_push.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\common.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\detail\checks.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\detail\parser_dbg.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\detail\print.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\detail\stack.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\emit.def.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\emit.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\export.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\node.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\parse.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\preprocess.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\std\map.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\std\std.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\std\string.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\std\vector.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\tree.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\writer.hpp" />
|
||||||
|
<ClInclude Include="include\c4\yml\yml.hpp" />
|
||||||
|
<ClInclude Include="include\ryml.hpp" />
|
||||||
|
<ClInclude Include="include\ryml_std.hpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Natvis Include="include\c4\c4core.natvis" />
|
||||||
|
<Natvis Include="include\ryml.natvis" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\c4\base64.cpp" />
|
||||||
|
<ClCompile Include="src\c4\error.cpp" />
|
||||||
|
<ClCompile Include="src\c4\format.cpp" />
|
||||||
|
<ClCompile Include="src\c4\language.cpp" />
|
||||||
|
<ClCompile Include="src\c4\memory_util.cpp" />
|
||||||
|
<ClCompile Include="src\c4\utf.cpp" />
|
||||||
|
<ClCompile Include="src\c4\yml\common.cpp" />
|
||||||
|
<ClCompile Include="src\c4\yml\node.cpp" />
|
||||||
|
<ClCompile Include="src\c4\yml\parse.cpp" />
|
||||||
|
<ClCompile Include="src\c4\yml\preprocess.cpp" />
|
||||||
|
<ClCompile Include="src\c4\yml\tree.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="..\msvc\vsprops\StaticLibrary.props" />
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)src;$(ProjectDir)include;$(ProjectDir)..\fast_float\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>C4_NO_DEBUG_BREAK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="..\msvc\vsprops\Targets.props" />
|
||||||
|
</Project>
|
209
dep/rapidyaml/rapidyaml.vcxproj.filters
Normal file
209
dep/rapidyaml/rapidyaml.vcxproj.filters
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="yml">
|
||||||
|
<UniqueIdentifier>{c002fb0c-6a19-4827-8a7a-19e0a309fb0c}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="yml\detail">
|
||||||
|
<UniqueIdentifier>{a3c32dd2-c04e-4122-8aa7-75c26954f557}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="yml\std">
|
||||||
|
<UniqueIdentifier>{df1d37c9-df20-47f2-9031-60d4fa1f8c69}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="c4">
|
||||||
|
<UniqueIdentifier>{6df19960-803e-4406-a9e6-43eaa256d94d}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="c4\std">
|
||||||
|
<UniqueIdentifier>{c53d424e-00a4-4c3c-89f4-f67c57cdee8f}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="include\c4\yml\detail\parser_dbg.hpp">
|
||||||
|
<Filter>yml\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\detail\print.hpp">
|
||||||
|
<Filter>yml\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\detail\stack.hpp">
|
||||||
|
<Filter>yml\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\detail\checks.hpp">
|
||||||
|
<Filter>yml\detail</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\std\string.hpp">
|
||||||
|
<Filter>yml\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\std\vector.hpp">
|
||||||
|
<Filter>yml\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\std\map.hpp">
|
||||||
|
<Filter>yml\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\std\std.hpp">
|
||||||
|
<Filter>yml\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\yml.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\common.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\emit.def.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\emit.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\export.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\node.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\parse.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\preprocess.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\tree.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\yml\writer.hpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\base64.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\blob.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\charconv.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\compiler.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\config.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\cpu.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\dump.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\error.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\export.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\format.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\language.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\memory_util.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\platform.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\preprocessor.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\substr.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\substr_fwd.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\szconv.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\types.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\utf.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\windows.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\windows_pop.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\windows_push.hpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\string.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\string_fwd.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\string_view.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\tuple.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\vector.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\vector_fwd.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\std.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\c4\std\std_fwd.hpp">
|
||||||
|
<Filter>c4\std</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\ryml.hpp" />
|
||||||
|
<ClInclude Include="include\ryml_std.hpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Natvis Include="include\c4\c4core.natvis">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</Natvis>
|
||||||
|
<Natvis Include="include\ryml.natvis" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\c4\base64.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\error.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\format.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\language.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\memory_util.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\utf.cpp">
|
||||||
|
<Filter>c4</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\yml\parse.cpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\yml\preprocess.cpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\yml\tree.cpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\yml\common.cpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\c4\yml\node.cpp">
|
||||||
|
<Filter>yml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
221
dep/rapidyaml/src/c4/base64.cpp
Normal file
221
dep/rapidyaml/src/c4/base64.cpp
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
#include "c4/base64.hpp"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wchar-subscripts" // array subscript is of type 'char'
|
||||||
|
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wchar-subscripts"
|
||||||
|
# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
|
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
constexpr static const char base64_sextet_to_char_[64] = {
|
||||||
|
/* 0/ 65*/ 'A', /* 1/ 66*/ 'B', /* 2/ 67*/ 'C', /* 3/ 68*/ 'D',
|
||||||
|
/* 4/ 69*/ 'E', /* 5/ 70*/ 'F', /* 6/ 71*/ 'G', /* 7/ 72*/ 'H',
|
||||||
|
/* 8/ 73*/ 'I', /* 9/ 74*/ 'J', /*10/ 75*/ 'K', /*11/ 74*/ 'L',
|
||||||
|
/*12/ 77*/ 'M', /*13/ 78*/ 'N', /*14/ 79*/ 'O', /*15/ 78*/ 'P',
|
||||||
|
/*16/ 81*/ 'Q', /*17/ 82*/ 'R', /*18/ 83*/ 'S', /*19/ 82*/ 'T',
|
||||||
|
/*20/ 85*/ 'U', /*21/ 86*/ 'V', /*22/ 87*/ 'W', /*23/ 88*/ 'X',
|
||||||
|
/*24/ 89*/ 'Y', /*25/ 90*/ 'Z', /*26/ 97*/ 'a', /*27/ 98*/ 'b',
|
||||||
|
/*28/ 99*/ 'c', /*29/100*/ 'd', /*30/101*/ 'e', /*31/102*/ 'f',
|
||||||
|
/*32/103*/ 'g', /*33/104*/ 'h', /*34/105*/ 'i', /*35/106*/ 'j',
|
||||||
|
/*36/107*/ 'k', /*37/108*/ 'l', /*38/109*/ 'm', /*39/110*/ 'n',
|
||||||
|
/*40/111*/ 'o', /*41/112*/ 'p', /*42/113*/ 'q', /*43/114*/ 'r',
|
||||||
|
/*44/115*/ 's', /*45/116*/ 't', /*46/117*/ 'u', /*47/118*/ 'v',
|
||||||
|
/*48/119*/ 'w', /*49/120*/ 'x', /*50/121*/ 'y', /*51/122*/ 'z',
|
||||||
|
/*52/ 48*/ '0', /*53/ 49*/ '1', /*54/ 50*/ '2', /*55/ 51*/ '3',
|
||||||
|
/*56/ 52*/ '4', /*57/ 53*/ '5', /*58/ 54*/ '6', /*59/ 55*/ '7',
|
||||||
|
/*60/ 56*/ '8', /*61/ 57*/ '9', /*62/ 43*/ '+', /*63/ 47*/ '/',
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
|
||||||
|
constexpr static const char base64_char_to_sextet_[128] = {
|
||||||
|
#define __ char(-1) // undefined below
|
||||||
|
/* 0 NUL*/ __, /* 1 SOH*/ __, /* 2 STX*/ __, /* 3 ETX*/ __,
|
||||||
|
/* 4 EOT*/ __, /* 5 ENQ*/ __, /* 6 ACK*/ __, /* 7 BEL*/ __,
|
||||||
|
/* 8 BS */ __, /* 9 TAB*/ __, /* 10 LF */ __, /* 11 VT */ __,
|
||||||
|
/* 12 FF */ __, /* 13 CR */ __, /* 14 SO */ __, /* 15 SI */ __,
|
||||||
|
/* 16 DLE*/ __, /* 17 DC1*/ __, /* 18 DC2*/ __, /* 19 DC3*/ __,
|
||||||
|
/* 20 DC4*/ __, /* 21 NAK*/ __, /* 22 SYN*/ __, /* 23 ETB*/ __,
|
||||||
|
/* 24 CAN*/ __, /* 25 EM */ __, /* 26 SUB*/ __, /* 27 ESC*/ __,
|
||||||
|
/* 28 FS */ __, /* 29 GS */ __, /* 30 RS */ __, /* 31 US */ __,
|
||||||
|
/* 32 SPC*/ __, /* 33 ! */ __, /* 34 " */ __, /* 35 # */ __,
|
||||||
|
/* 36 $ */ __, /* 37 % */ __, /* 38 & */ __, /* 39 ' */ __,
|
||||||
|
/* 40 ( */ __, /* 41 ) */ __, /* 42 * */ __, /* 43 + */ 62,
|
||||||
|
/* 44 , */ __, /* 45 - */ __, /* 46 . */ __, /* 47 / */ 63,
|
||||||
|
/* 48 0 */ 52, /* 49 1 */ 53, /* 50 2 */ 54, /* 51 3 */ 55,
|
||||||
|
/* 52 4 */ 56, /* 53 5 */ 57, /* 54 6 */ 58, /* 55 7 */ 59,
|
||||||
|
/* 56 8 */ 60, /* 57 9 */ 61, /* 58 : */ __, /* 59 ; */ __,
|
||||||
|
/* 60 < */ __, /* 61 = */ __, /* 62 > */ __, /* 63 ? */ __,
|
||||||
|
/* 64 @ */ __, /* 65 A */ 0, /* 66 B */ 1, /* 67 C */ 2,
|
||||||
|
/* 68 D */ 3, /* 69 E */ 4, /* 70 F */ 5, /* 71 G */ 6,
|
||||||
|
/* 72 H */ 7, /* 73 I */ 8, /* 74 J */ 9, /* 75 K */ 10,
|
||||||
|
/* 76 L */ 11, /* 77 M */ 12, /* 78 N */ 13, /* 79 O */ 14,
|
||||||
|
/* 80 P */ 15, /* 81 Q */ 16, /* 82 R */ 17, /* 83 S */ 18,
|
||||||
|
/* 84 T */ 19, /* 85 U */ 20, /* 86 V */ 21, /* 87 W */ 22,
|
||||||
|
/* 88 X */ 23, /* 89 Y */ 24, /* 90 Z */ 25, /* 91 [ */ __,
|
||||||
|
/* 92 \ */ __, /* 93 ] */ __, /* 94 ^ */ __, /* 95 _ */ __,
|
||||||
|
/* 96 ` */ __, /* 97 a */ 26, /* 98 b */ 27, /* 99 c */ 28,
|
||||||
|
/*100 d */ 29, /*101 e */ 30, /*102 f */ 31, /*103 g */ 32,
|
||||||
|
/*104 h */ 33, /*105 i */ 34, /*106 j */ 35, /*107 k */ 36,
|
||||||
|
/*108 l */ 37, /*109 m */ 38, /*110 n */ 39, /*111 o */ 40,
|
||||||
|
/*112 p */ 41, /*113 q */ 42, /*114 r */ 43, /*115 s */ 44,
|
||||||
|
/*116 t */ 45, /*117 u */ 46, /*118 v */ 47, /*119 w */ 48,
|
||||||
|
/*120 x */ 49, /*121 y */ 50, /*122 z */ 51, /*123 { */ __,
|
||||||
|
/*124 | */ __, /*125 } */ __, /*126 ~ */ __, /*127 DEL*/ __,
|
||||||
|
#undef __
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void base64_test_tables()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < C4_COUNTOF(detail::base64_sextet_to_char_); ++i)
|
||||||
|
{
|
||||||
|
char s2c = base64_sextet_to_char_[i];
|
||||||
|
char c2s = base64_char_to_sextet_[(int)s2c];
|
||||||
|
C4_CHECK((size_t)c2s == i);
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < C4_COUNTOF(detail::base64_char_to_sextet_); ++i)
|
||||||
|
{
|
||||||
|
char c2s = base64_char_to_sextet_[i];
|
||||||
|
if(c2s == char(-1))
|
||||||
|
continue;
|
||||||
|
char s2c = base64_sextet_to_char_[(int)c2s];
|
||||||
|
C4_CHECK((size_t)s2c == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
bool base64_valid(csubstr encoded)
|
||||||
|
{
|
||||||
|
if(encoded.len & 3u) // (encoded.len % 4u)
|
||||||
|
return false;
|
||||||
|
for(const char c : encoded)
|
||||||
|
{
|
||||||
|
if(c < 0/* || c >= 128*/)
|
||||||
|
return false;
|
||||||
|
if(c == '=')
|
||||||
|
continue;
|
||||||
|
if(detail::base64_char_to_sextet_[c] == char(-1))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t base64_encode(substr buf, cblob data)
|
||||||
|
{
|
||||||
|
#define c4append_(c) { if(pos < buf.len) { buf.str[pos] = (c); } ++pos; }
|
||||||
|
#define c4append_idx_(char_idx) \
|
||||||
|
{\
|
||||||
|
C4_XASSERT((char_idx) < sizeof(detail::base64_sextet_to_char_));\
|
||||||
|
c4append_(detail::base64_sextet_to_char_[(char_idx)]);\
|
||||||
|
}
|
||||||
|
size_t rem, pos = 0;
|
||||||
|
constexpr const uint32_t sextet_mask = uint32_t(1 << 6) - 1;
|
||||||
|
const unsigned char *C4_RESTRICT d = (const unsigned char *) data.buf; // cast to unsigned to avoid wrapping high-bits
|
||||||
|
for(rem = data.len; rem >= 3; rem -= 3, d += 3)
|
||||||
|
{
|
||||||
|
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8) | (uint32_t(d[2])));
|
||||||
|
c4append_idx_((val >> 18) & sextet_mask);
|
||||||
|
c4append_idx_((val >> 12) & sextet_mask);
|
||||||
|
c4append_idx_((val >> 6) & sextet_mask);
|
||||||
|
c4append_idx_((val ) & sextet_mask);
|
||||||
|
}
|
||||||
|
C4_ASSERT(rem < 3);
|
||||||
|
if(rem == 2)
|
||||||
|
{
|
||||||
|
const uint32_t val = ((uint32_t(d[0]) << 16) | (uint32_t(d[1]) << 8));
|
||||||
|
c4append_idx_((val >> 18) & sextet_mask);
|
||||||
|
c4append_idx_((val >> 12) & sextet_mask);
|
||||||
|
c4append_idx_((val >> 6) & sextet_mask);
|
||||||
|
c4append_('=');
|
||||||
|
}
|
||||||
|
else if(rem == 1)
|
||||||
|
{
|
||||||
|
const uint32_t val = ((uint32_t(d[0]) << 16));
|
||||||
|
c4append_idx_((val >> 18) & sextet_mask);
|
||||||
|
c4append_idx_((val >> 12) & sextet_mask);
|
||||||
|
c4append_('=');
|
||||||
|
c4append_('=');
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
#undef c4append_
|
||||||
|
#undef c4append_idx_
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t base64_decode(csubstr encoded, blob data)
|
||||||
|
{
|
||||||
|
#define c4append_(c) { if(wpos < data.len) { data.buf[wpos] = static_cast<c4::byte>(c); } ++wpos; }
|
||||||
|
#define c4appendval_(c, shift)\
|
||||||
|
{\
|
||||||
|
C4_XASSERT(c >= 0);\
|
||||||
|
C4_XASSERT(size_t(c) < sizeof(detail::base64_char_to_sextet_));\
|
||||||
|
val |= static_cast<uint32_t>(detail::base64_char_to_sextet_[(c)]) << ((shift) * 6);\
|
||||||
|
}
|
||||||
|
C4_ASSERT(base64_valid(encoded));
|
||||||
|
C4_CHECK((encoded.len & 3u) == 0);
|
||||||
|
size_t wpos = 0; // the write position
|
||||||
|
const char *C4_RESTRICT d = encoded.str;
|
||||||
|
constexpr const uint32_t full_byte = 0xff;
|
||||||
|
// process every quartet of input 6 bits --> triplet of output bytes
|
||||||
|
for(size_t rpos = 0; rpos < encoded.len; rpos += 4, d += 4)
|
||||||
|
{
|
||||||
|
if(d[2] == '=' || d[3] == '=') // skip the last quartet if it is padded
|
||||||
|
{
|
||||||
|
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint32_t val = 0;
|
||||||
|
c4appendval_(d[3], 0);
|
||||||
|
c4appendval_(d[2], 1);
|
||||||
|
c4appendval_(d[1], 2);
|
||||||
|
c4appendval_(d[0], 3);
|
||||||
|
c4append_((val >> (2 * 8)) & full_byte);
|
||||||
|
c4append_((val >> (1 * 8)) & full_byte);
|
||||||
|
c4append_((val ) & full_byte);
|
||||||
|
}
|
||||||
|
// deal with the last quartet when it is padded
|
||||||
|
if(d == encoded.str + encoded.len)
|
||||||
|
return wpos;
|
||||||
|
if(d[2] == '=') // 2 padding chars
|
||||||
|
{
|
||||||
|
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||||
|
C4_ASSERT(d[3] == '=');
|
||||||
|
uint32_t val = 0;
|
||||||
|
c4appendval_(d[1], 2);
|
||||||
|
c4appendval_(d[0], 3);
|
||||||
|
c4append_((val >> (2 * 8)) & full_byte);
|
||||||
|
}
|
||||||
|
else if(d[3] == '=') // 1 padding char
|
||||||
|
{
|
||||||
|
C4_ASSERT(d + 4 == encoded.str + encoded.len);
|
||||||
|
uint32_t val = 0;
|
||||||
|
c4appendval_(d[2], 1);
|
||||||
|
c4appendval_(d[1], 2);
|
||||||
|
c4appendval_(d[0], 3);
|
||||||
|
c4append_((val >> (2 * 8)) & full_byte);
|
||||||
|
c4append_((val >> (1 * 8)) & full_byte);
|
||||||
|
}
|
||||||
|
return wpos;
|
||||||
|
#undef c4append_
|
||||||
|
#undef c4appendval_
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
229
dep/rapidyaml/src/c4/error.cpp
Normal file
229
dep/rapidyaml/src/c4/error.cpp
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define C4_LOGF_ERR(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
|
||||||
|
#define C4_LOGF_WARN(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
|
||||||
|
#define C4_LOGP(msg, ...) printf(msg)
|
||||||
|
|
||||||
|
#if defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
|
||||||
|
# include "c4/windows.hpp"
|
||||||
|
#elif defined(C4_PS4)
|
||||||
|
# include <libdbg.h>
|
||||||
|
#elif defined(C4_UNIX) || defined(C4_LINUX)
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# include <cstring>
|
||||||
|
# include <fcntl.h>
|
||||||
|
#elif defined(C4_MACOS) || defined(C4_IOS)
|
||||||
|
# include <assert.h>
|
||||||
|
# include <stdbool.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
// the amalgamation tool is dumb and was omitting this include under MACOS.
|
||||||
|
// So do it only once:
|
||||||
|
#if defined(C4_UNIX) || defined(C4_LINUX) || defined(C4_MACOS) || defined(C4_IOS)
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
|
||||||
|
# include <exception>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||||
|
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||||
|
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
static error_flags s_error_flags = ON_ERROR_DEFAULTS;
|
||||||
|
static error_callback_type s_error_callback = nullptr;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
error_flags get_error_flags()
|
||||||
|
{
|
||||||
|
return s_error_flags;
|
||||||
|
}
|
||||||
|
void set_error_flags(error_flags flags)
|
||||||
|
{
|
||||||
|
s_error_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_callback_type get_error_callback()
|
||||||
|
{
|
||||||
|
return s_error_callback;
|
||||||
|
}
|
||||||
|
/** Set the function which is called when an error occurs. */
|
||||||
|
void set_error_callback(error_callback_type cb)
|
||||||
|
{
|
||||||
|
s_error_callback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void handle_error(srcloc where, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
size_t msglen = 0;
|
||||||
|
if(s_error_flags & (ON_ERROR_LOG|ON_ERROR_CALLBACK))
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int ilen = vsnprintf(buf, sizeof(buf), fmt, args); // ss.vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
msglen = ilen >= 0 && ilen < (int)sizeof(buf) ? static_cast<size_t>(ilen) : sizeof(buf)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_error_flags & ON_ERROR_LOG)
|
||||||
|
{
|
||||||
|
C4_LOGF_ERR("\n");
|
||||||
|
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
|
||||||
|
C4_LOGF_ERR("%s:%d: ERROR here: %s\n", where.file, where.line, where.func);
|
||||||
|
#elif defined(C4_ERROR_SHOWS_FILELINE)
|
||||||
|
C4_LOGF_ERR("%s:%d: ERROR: %s\n", where.file, where.line, buf);
|
||||||
|
#elif ! defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
C4_LOGF_ERR("ERROR: %s\n", buf);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_error_flags & ON_ERROR_CALLBACK)
|
||||||
|
{
|
||||||
|
if(s_error_callback)
|
||||||
|
{
|
||||||
|
s_error_callback(buf, msglen/*ss.c_strp(), ss.tellp()*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_error_flags & ON_ERROR_ABORT)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s_error_flags & ON_ERROR_THROW)
|
||||||
|
{
|
||||||
|
#if defined(C4_EXCEPTIONS_ENABLED) && defined(C4_ERROR_THROWS_EXCEPTION)
|
||||||
|
throw Exception(buf);
|
||||||
|
#else
|
||||||
|
abort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void handle_warning(srcloc where, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buf[1024]; //sstream<c4::string> ss;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
C4_LOGF_WARN("\n");
|
||||||
|
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/);
|
||||||
|
C4_LOGF_WARN("%s:%d: WARNING: here: %s\n", where.file, where.line, where.func);
|
||||||
|
#elif defined(C4_ERROR_SHOWS_FILELINE)
|
||||||
|
C4_LOGF_WARN("%s:%d: WARNING: %s\n", where.file, where.line, buf/*ss.c_strp()*/);
|
||||||
|
#elif ! defined(C4_ERROR_SHOWS_FUNC)
|
||||||
|
C4_LOGF_WARN("WARNING: %s\n", buf/*ss.c_strp()*/);
|
||||||
|
#endif
|
||||||
|
//c4::log.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool is_debugger_attached()
|
||||||
|
{
|
||||||
|
#if defined(C4_UNIX) || defined(C4_LINUX)
|
||||||
|
static bool first_call = true;
|
||||||
|
static bool first_call_result = false;
|
||||||
|
if(first_call)
|
||||||
|
{
|
||||||
|
first_call = false;
|
||||||
|
//! @see http://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb
|
||||||
|
//! (this answer: http://stackoverflow.com/a/24969863/3968589 )
|
||||||
|
char buf[1024] = "";
|
||||||
|
|
||||||
|
int status_fd = open("/proc/self/status", O_RDONLY);
|
||||||
|
if (status_fd == -1)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t num_read = ::read(status_fd, buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (num_read > 0)
|
||||||
|
{
|
||||||
|
static const char TracerPid[] = "TracerPid:";
|
||||||
|
char *tracer_pid;
|
||||||
|
|
||||||
|
if(num_read < 1024)
|
||||||
|
{
|
||||||
|
buf[num_read] = 0;
|
||||||
|
}
|
||||||
|
tracer_pid = strstr(buf, TracerPid);
|
||||||
|
if (tracer_pid)
|
||||||
|
{
|
||||||
|
first_call_result = !!::atoi(tracer_pid + sizeof(TracerPid) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first_call_result;
|
||||||
|
#elif defined(C4_PS4)
|
||||||
|
return (sceDbgIsDebuggerAttached() != 0);
|
||||||
|
#elif defined(C4_XBOX) || (defined(C4_WIN) && defined(C4_MSVC))
|
||||||
|
return IsDebuggerPresent() != 0;
|
||||||
|
#elif defined(C4_MACOS) || defined(C4_IOS)
|
||||||
|
// https://stackoverflow.com/questions/2200277/detecting-debugger-on-mac-os-x
|
||||||
|
// Returns true if the current process is being debugged (either
|
||||||
|
// running under the debugger or has a debugger attached post facto).
|
||||||
|
int junk;
|
||||||
|
int mib[4];
|
||||||
|
struct kinfo_proc info;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
// Initialize the flags so that, if sysctl fails for some bizarre
|
||||||
|
// reason, we get a predictable result.
|
||||||
|
|
||||||
|
info.kp_proc.p_flag = 0;
|
||||||
|
|
||||||
|
// Initialize mib, which tells sysctl the info we want, in this case
|
||||||
|
// we're looking for information about a specific process ID.
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC;
|
||||||
|
mib[2] = KERN_PROC_PID;
|
||||||
|
mib[3] = getpid();
|
||||||
|
|
||||||
|
// Call sysctl.
|
||||||
|
|
||||||
|
size = sizeof(info);
|
||||||
|
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
||||||
|
assert(junk == 0);
|
||||||
|
|
||||||
|
// We're being debugged if the P_TRACED flag is set.
|
||||||
|
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
} // is_debugger_attached()
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
60
dep/rapidyaml/src/c4/format.cpp
Normal file
60
dep/rapidyaml/src/c4/format.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "c4/format.hpp"
|
||||||
|
|
||||||
|
#include <memory> // for std::align
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||||
|
# pragma clang diagnostic ignored "-Wold-style-cast"
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||||
|
# pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
|
||||||
|
size_t to_chars(substr buf, fmt::const_raw_wrapper r)
|
||||||
|
{
|
||||||
|
void * vptr = buf.str;
|
||||||
|
size_t space = buf.len;
|
||||||
|
auto ptr = (decltype(buf.str)) std::align(r.alignment, r.len, vptr, space);
|
||||||
|
if(ptr == nullptr)
|
||||||
|
{
|
||||||
|
// if it was not possible to align, return a conservative estimate
|
||||||
|
// of the required space
|
||||||
|
return r.alignment + r.len;
|
||||||
|
}
|
||||||
|
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
|
||||||
|
size_t sz = static_cast<size_t>(ptr - buf.str) + r.len;
|
||||||
|
if(sz <= buf.len)
|
||||||
|
{
|
||||||
|
memcpy(ptr, r.buf, r.len);
|
||||||
|
}
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool from_chars(csubstr buf, fmt::raw_wrapper *r)
|
||||||
|
{
|
||||||
|
C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wcast-qual")
|
||||||
|
void * vptr = (void*)buf.str;
|
||||||
|
C4_SUPPRESS_WARNING_GCC_POP
|
||||||
|
size_t space = buf.len;
|
||||||
|
auto ptr = (decltype(buf.str)) std::align(r->alignment, r->len, vptr, space);
|
||||||
|
C4_CHECK(ptr != nullptr);
|
||||||
|
C4_CHECK(ptr >= buf.begin() && ptr <= buf.end());
|
||||||
|
//size_t dim = (ptr - buf.str) + r->len;
|
||||||
|
memcpy(r->buf, ptr, r->len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace c4
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
#endif
|
16
dep/rapidyaml/src/c4/language.cpp
Normal file
16
dep/rapidyaml/src/c4/language.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "c4/language.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
void use_char_pointer(char const volatile* v)
|
||||||
|
{
|
||||||
|
C4_UNUSED(v);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void foo() {} // to avoid empty file warning from the linker
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace c4
|
32
dep/rapidyaml/src/c4/memory_util.cpp
Normal file
32
dep/rapidyaml/src/c4/memory_util.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "c4/memory_util.hpp"
|
||||||
|
#include "c4/error.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
|
||||||
|
/** Fills 'dest' with the first 'pattern_size' bytes at 'pattern', 'num_times'. */
|
||||||
|
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times)
|
||||||
|
{
|
||||||
|
if(C4_UNLIKELY(num_times == 0))
|
||||||
|
return;
|
||||||
|
C4_ASSERT( ! mem_overlaps(dest, pattern, num_times*pattern_size, pattern_size));
|
||||||
|
char *begin = static_cast<char*>(dest);
|
||||||
|
char *end = begin + num_times * pattern_size;
|
||||||
|
// copy the pattern once
|
||||||
|
::memcpy(begin, pattern, pattern_size);
|
||||||
|
// now copy from dest to itself, doubling up every time
|
||||||
|
size_t n = pattern_size;
|
||||||
|
while(begin + 2*n < end)
|
||||||
|
{
|
||||||
|
::memcpy(begin + n, begin, n);
|
||||||
|
n <<= 1; // double n
|
||||||
|
}
|
||||||
|
// copy the missing part
|
||||||
|
if(begin + n < end)
|
||||||
|
{
|
||||||
|
::memcpy(begin + n, begin, static_cast<size_t>(end - (begin + n)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace c4
|
60
dep/rapidyaml/src/c4/utf.cpp
Normal file
60
dep/rapidyaml/src/c4/utf.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "c4/utf.hpp"
|
||||||
|
#include "c4/charconv.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
size_t decode_code_point(uint8_t *C4_RESTRICT buf, size_t buflen, const uint32_t code)
|
||||||
|
{
|
||||||
|
C4_UNUSED(buflen);
|
||||||
|
C4_ASSERT(buflen >= 4);
|
||||||
|
if (code <= UINT32_C(0x7f))
|
||||||
|
{
|
||||||
|
buf[0] = (uint8_t)code;
|
||||||
|
return 1u;
|
||||||
|
}
|
||||||
|
else if(code <= UINT32_C(0x7ff))
|
||||||
|
{
|
||||||
|
buf[0] = (uint8_t)(UINT32_C(0xc0) | (code >> 6)); /* 110xxxxx */
|
||||||
|
buf[1] = (uint8_t)(UINT32_C(0x80) | (code & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
return 2u;
|
||||||
|
}
|
||||||
|
else if(code <= UINT32_C(0xffff))
|
||||||
|
{
|
||||||
|
buf[0] = (uint8_t)(UINT32_C(0xe0) | ((code >> 12))); /* 1110xxxx */
|
||||||
|
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 6) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
return 3u;
|
||||||
|
}
|
||||||
|
else if(code <= UINT32_C(0x10ffff))
|
||||||
|
{
|
||||||
|
buf[0] = (uint8_t)(UINT32_C(0xf0) | ((code >> 18))); /* 11110xxx */
|
||||||
|
buf[1] = (uint8_t)(UINT32_C(0x80) | ((code >> 12) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
buf[2] = (uint8_t)(UINT32_C(0x80) | ((code >> 6) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
buf[3] = (uint8_t)(UINT32_C(0x80) | ((code ) & UINT32_C(0x3f))); /* 10xxxxxx */
|
||||||
|
return 4u;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
substr decode_code_point(substr out, csubstr code_point)
|
||||||
|
{
|
||||||
|
C4_ASSERT(out.len >= 4);
|
||||||
|
C4_ASSERT(!code_point.begins_with("U+"));
|
||||||
|
C4_ASSERT(!code_point.begins_with("\\x"));
|
||||||
|
C4_ASSERT(!code_point.begins_with("\\u"));
|
||||||
|
C4_ASSERT(!code_point.begins_with("\\U"));
|
||||||
|
C4_ASSERT(!code_point.begins_with('0'));
|
||||||
|
C4_ASSERT(code_point.len <= 8);
|
||||||
|
C4_ASSERT(code_point.len > 0);
|
||||||
|
uint32_t code_point_val;
|
||||||
|
C4_CHECK(read_hex(code_point, &code_point_val));
|
||||||
|
size_t ret = decode_code_point((uint8_t*)out.str, out.len, code_point_val);
|
||||||
|
C4_ASSERT(ret <= 4);
|
||||||
|
return out.first(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace c4
|
121
dep/rapidyaml/src/c4/yml/common.cpp
Normal file
121
dep/rapidyaml/src/c4/yml/common.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#include "c4/yml/common.hpp"
|
||||||
|
|
||||||
|
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
#endif // RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Callbacks s_default_callbacks;
|
||||||
|
} // anon namespace
|
||||||
|
|
||||||
|
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
void report_error_impl(const char* msg, size_t length, Location loc, FILE *f)
|
||||||
|
{
|
||||||
|
if(!f)
|
||||||
|
f = stderr;
|
||||||
|
if(loc)
|
||||||
|
{
|
||||||
|
if(!loc.name.empty())
|
||||||
|
{
|
||||||
|
fwrite(loc.name.str, 1, loc.name.len, f);
|
||||||
|
fputc(':', f);
|
||||||
|
}
|
||||||
|
fprintf(f, "%zu:", loc.line);
|
||||||
|
if(loc.col)
|
||||||
|
fprintf(f, "%zu:", loc.col);
|
||||||
|
if(loc.offset)
|
||||||
|
fprintf(f, " (%zuB):", loc.offset);
|
||||||
|
}
|
||||||
|
fprintf(f, "%.*s\n", (int)length, msg);
|
||||||
|
fflush(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void error_impl(const char* msg, size_t length, Location loc, void * /*user_data*/)
|
||||||
|
{
|
||||||
|
report_error_impl(msg, length, loc, nullptr);
|
||||||
|
::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
|
||||||
|
{
|
||||||
|
void *mem = ::malloc(length);
|
||||||
|
if(mem == nullptr)
|
||||||
|
{
|
||||||
|
const char msg[] = "could not allocate memory";
|
||||||
|
error_impl(msg, sizeof(msg)-1, {}, nullptr);
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
|
||||||
|
{
|
||||||
|
::free(mem);
|
||||||
|
}
|
||||||
|
#endif // RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Callbacks::Callbacks()
|
||||||
|
:
|
||||||
|
m_user_data(nullptr),
|
||||||
|
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
m_allocate(allocate_impl),
|
||||||
|
m_free(free_impl),
|
||||||
|
m_error(error_impl)
|
||||||
|
#else
|
||||||
|
m_allocate(nullptr),
|
||||||
|
m_free(nullptr),
|
||||||
|
m_error(nullptr)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error error_)
|
||||||
|
:
|
||||||
|
m_user_data(user_data),
|
||||||
|
#ifndef RYML_NO_DEFAULT_CALLBACKS
|
||||||
|
m_allocate(alloc_ ? alloc_ : allocate_impl),
|
||||||
|
m_free(free_ ? free_ : free_impl),
|
||||||
|
m_error(error_ ? error_ : error_impl)
|
||||||
|
#else
|
||||||
|
m_allocate(alloc_),
|
||||||
|
m_free(free_),
|
||||||
|
m_error(error_)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
C4_CHECK(m_allocate);
|
||||||
|
C4_CHECK(m_free);
|
||||||
|
C4_CHECK(m_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_callbacks(Callbacks const& c)
|
||||||
|
{
|
||||||
|
s_default_callbacks = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
Callbacks const& get_callbacks()
|
||||||
|
{
|
||||||
|
return s_default_callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_callbacks()
|
||||||
|
{
|
||||||
|
set_callbacks(Callbacks());
|
||||||
|
}
|
||||||
|
|
||||||
|
void error(const char *msg, size_t msg_len, Location loc)
|
||||||
|
{
|
||||||
|
s_default_callbacks.m_error(msg, msg_len, loc, s_default_callbacks.m_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
30
dep/rapidyaml/src/c4/yml/node.cpp
Normal file
30
dep/rapidyaml/src/c4/yml/node.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include "c4/yml/node.hpp"
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
size_t NodeRef::set_key_serialized(c4::fmt::const_base64_wrapper w)
|
||||||
|
{
|
||||||
|
_apply_seed();
|
||||||
|
csubstr encoded = this->to_arena(w);
|
||||||
|
this->set_key(encoded);
|
||||||
|
return encoded.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NodeRef::set_val_serialized(c4::fmt::const_base64_wrapper w)
|
||||||
|
{
|
||||||
|
_apply_seed();
|
||||||
|
csubstr encoded = this->to_arena(w);
|
||||||
|
this->set_val(encoded);
|
||||||
|
return encoded.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
5750
dep/rapidyaml/src/c4/yml/parse.cpp
Normal file
5750
dep/rapidyaml/src/c4/yml/parse.cpp
Normal file
File diff suppressed because it is too large
Load diff
112
dep/rapidyaml/src/c4/yml/preprocess.cpp
Normal file
112
dep/rapidyaml/src/c4/yml/preprocess.cpp
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#include "c4/yml/preprocess.hpp"
|
||||||
|
#include "c4/yml/detail/parser_dbg.hpp"
|
||||||
|
|
||||||
|
/** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
|
||||||
|
|
||||||
|
namespace c4 {
|
||||||
|
namespace yml {
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
C4_ALWAYS_INLINE bool _is_idchar(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'a' && c <= 'z')
|
||||||
|
|| (c >= 'A' && c <= 'Z')
|
||||||
|
|| (c >= '0' && c <= '9')
|
||||||
|
|| (c == '_' || c == '-' || c == '~' || c == '$');
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum { kReadPending = 0, kKeyPending = 1, kValPending = 2 } _ppstate;
|
||||||
|
C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
|
||||||
|
{
|
||||||
|
int n = (int)s + 1;
|
||||||
|
return (_ppstate)(n <= (int)kValPending ? n : 0);
|
||||||
|
}
|
||||||
|
} // empty namespace
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
size_t preprocess_rxmap(csubstr s, substr buf)
|
||||||
|
{
|
||||||
|
detail::_SubstrWriter writer(buf);
|
||||||
|
_ppstate state = kReadPending;
|
||||||
|
size_t last = 0;
|
||||||
|
|
||||||
|
if(s.begins_with('{'))
|
||||||
|
{
|
||||||
|
RYML_CHECK(s.ends_with('}'));
|
||||||
|
s = s.offs(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.append('{');
|
||||||
|
|
||||||
|
for(size_t i = 0; i < s.len; ++i)
|
||||||
|
{
|
||||||
|
const char curr = s[i];
|
||||||
|
const char next = i+1 < s.len ? s[i+1] : '\0';
|
||||||
|
|
||||||
|
if(curr == '\'' || curr == '"')
|
||||||
|
{
|
||||||
|
csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
|
||||||
|
i += static_cast<size_t>(ss.end() - (s.str + i));
|
||||||
|
state = _next(state);
|
||||||
|
}
|
||||||
|
else if(state == kReadPending && _is_idchar(curr))
|
||||||
|
{
|
||||||
|
state = _next(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case kKeyPending:
|
||||||
|
{
|
||||||
|
if(curr == ':' && next == ' ')
|
||||||
|
{
|
||||||
|
state = _next(state);
|
||||||
|
}
|
||||||
|
else if(curr == ',' && next == ' ')
|
||||||
|
{
|
||||||
|
writer.append(s.range(last, i));
|
||||||
|
writer.append(": 1, ");
|
||||||
|
last = i + 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kValPending:
|
||||||
|
{
|
||||||
|
if(curr == '[' || curr == '{' || curr == '(')
|
||||||
|
{
|
||||||
|
csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
|
||||||
|
i += static_cast<size_t>(ss.end() - (s.str + i));
|
||||||
|
state = _next(state);
|
||||||
|
}
|
||||||
|
else if(curr == ',' && next == ' ')
|
||||||
|
{
|
||||||
|
state = _next(state);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// nothing to do
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.append(s.sub(last));
|
||||||
|
if(state == kKeyPending)
|
||||||
|
writer.append(": 1");
|
||||||
|
writer.append('}');
|
||||||
|
|
||||||
|
return writer.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_SUPPRESS_WARNING_GCC_CLANG_POP
|
||||||
|
|
||||||
|
} // namespace yml
|
||||||
|
} // namespace c4
|
2184
dep/rapidyaml/src/c4/yml/tree.cpp
Normal file
2184
dep/rapidyaml/src/c4/yml/tree.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -73,6 +73,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d12ma", "dep\d3d12ma\d3d1
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reshadefx", "dep\reshadefx\reshadefx.vcxproj", "{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reshadefx", "dep\reshadefx\reshadefx.vcxproj", "{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rapidyaml", "dep\rapidyaml\rapidyaml.vcxproj", "{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|ARM64 = Debug|ARM64
|
Debug|ARM64 = Debug|ARM64
|
||||||
|
@ -1031,6 +1033,38 @@ Global
|
||||||
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
|
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
|
||||||
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
|
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
|
||||||
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
|
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast|x64.ActiveCfg = DebugFast|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast|x64.Build.0 = DebugFast|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.Build.0 = Release|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release-Clang|x64.Build.0 = Release-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -1059,6 +1093,7 @@ Global
|
||||||
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699} = {BA490C0E-497D-4634-A21E-E65012006385}
|
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||||
{F351C4D8-594A-4850-B77B-3C1249812CCE} = {BA490C0E-497D-4634-A21E-E65012006385}
|
{F351C4D8-594A-4850-B77B-3C1249812CCE} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||||
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE} = {BA490C0E-497D-4634-A21E-E65012006385}
|
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||||
|
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E} = {BA490C0E-497D-4634-A21E-E65012006385}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {26E40B32-7C1D-48D0-95F4-1A500E054028}
|
SolutionGuid = {26E40B32-7C1D-48D0-95F4-1A500E054028}
|
||||||
|
|
Loading…
Reference in a new issue