Add config
This commit is contained in:
parent
ca0fae3d83
commit
c0e84d67e7
|
@ -36,10 +36,10 @@ file(GLOB_RECURSE SOURCES "src/*.cpp")
|
|||
file(GLOB IMGUI "include/imgui-1.76/*.cpp")
|
||||
file(GLOB FASTNOISE "include/FastNoiseSIMD/*.cpp")
|
||||
|
||||
add_executable(univerxel ${SOURCES} ${IMGUI} ${FASTNOISE})
|
||||
add_executable(univerxel ${SOURCES} ${IMGUI} ${FASTNOISE} ${TOML})
|
||||
target_compile_features(univerxel PUBLIC cxx_std_17)
|
||||
target_link_libraries(univerxel ${ALL_LIBS})
|
||||
target_include_directories(univerxel PRIVATE "include/imgui-1.76/" "include/FastNoiseSIMD/")
|
||||
target_include_directories(univerxel PRIVATE "include/imgui-1.76/" "include/FastNoiseSIMD/" "include/toml++/")
|
||||
|
||||
|
||||
file(COPY content/shaders DESTINATION ${CMAKE_BINARY_DIR}/content)
|
||||
|
|
|
@ -27,6 +27,7 @@ Experimental project using OpenGL.
|
|||
* OpenGL
|
||||
* ImGui
|
||||
* FasNoiseSIMD
|
||||
* Toml++
|
||||
* Love and insomnia
|
||||
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ void main() {
|
|||
// Light emission properties
|
||||
// You probably want to put them as uniforms
|
||||
vec3 LightColor = vec3(1, 0.9, 0.9);
|
||||
float LightPower = 1.f;
|
||||
float LightPower = 1.2f;
|
||||
|
||||
// Distance to the light
|
||||
float distance = 1.0f;//length( LightPosition_worldspace - Position_worldspace );
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
from os import path
|
||||
from PIL import Image, ImageFile, ImageOps
|
||||
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True # accept extra infos in png
|
||||
|
||||
if not len(sys.argv) in [5, 6]:
|
||||
print("Use: merge.py R G B OUT (invert)")
|
||||
exit(1)
|
||||
|
||||
trues = [1, "true", "True"]
|
||||
[_, r, g, b, out, inv] = sys.argv
|
||||
|
||||
r = Image.open(r).convert('L')
|
||||
g = Image.open(g).convert('L')
|
||||
b = Image.open(b).convert('L')
|
||||
if inv in trues:
|
||||
b = ImageOps.invert(b)
|
||||
Image.merge("RGB", (r, g, b)).save(out)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,106 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//# {{
|
||||
#ifndef INCLUDE_TOMLPLUSPLUS_H
|
||||
#define INCLUDE_TOMLPLUSPLUS_H
|
||||
//# }}
|
||||
|
||||
//# Note: most of these would be included transitively but
|
||||
//# they're listed explicitly here because this file
|
||||
//# is used as the source for generate_single_header.py.
|
||||
|
||||
#include "toml_preprocessor.h"
|
||||
#include "toml_common.h"
|
||||
#include "toml_date_time.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
#include "toml_node.h"
|
||||
#include "toml_value.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_node_view.h"
|
||||
#include "toml_utf8_generated.h"
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_default_formatter.h"
|
||||
#include "toml_json_formatter.h"
|
||||
#if TOML_PARSER
|
||||
#include "toml_parse_error.h"
|
||||
#include "toml_utf8_streams.h"
|
||||
#include "toml_parser.h"
|
||||
#endif // TOML_PARSER
|
||||
|
||||
#if TOML_IMPLEMENTATION
|
||||
#include "toml_node.hpp"
|
||||
#include "toml_array.hpp"
|
||||
#include "toml_table.hpp"
|
||||
#include "toml_default_formatter.hpp"
|
||||
#include "toml_json_formatter.hpp"
|
||||
#if TOML_PARSER
|
||||
#include "toml_parser.hpp"
|
||||
#endif // TOML_PARSER
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
#include "toml_instantiations.hpp"
|
||||
#endif // !TOML_ALL_INLINE
|
||||
|
||||
#endif // TOML_IMPLEMENTATION
|
||||
|
||||
// macro hygiene
|
||||
#if TOML_UNDEF_MACROS
|
||||
#undef TOML_INT_CHARCONV
|
||||
#undef TOML_FLOAT_CHARCONV
|
||||
#undef TOML_ATTR
|
||||
#undef TOML_PUSH_WARNINGS
|
||||
#undef TOML_DISABLE_SWITCH_WARNINGS
|
||||
#undef TOML_DISABLE_INIT_WARNINGS
|
||||
#undef TOML_DISABLE_VTABLE_WARNINGS
|
||||
#undef TOML_DISABLE_PADDING_WARNINGS
|
||||
#undef TOML_DISABLE_FLOAT_WARNINGS
|
||||
#undef TOML_DISABLE_SHADOW_WARNINGS
|
||||
#undef TOML_DISABLE_SUGGEST_WARNINGS
|
||||
#undef TOML_DISABLE_ALL_WARNINGS
|
||||
#undef TOML_POP_WARNINGS
|
||||
#undef TOML_ALWAYS_INLINE
|
||||
#undef TOML_NEVER_INLINE
|
||||
#undef TOML_ASSUME
|
||||
#undef TOML_UNREACHABLE
|
||||
#undef TOML_INTERFACE
|
||||
#undef TOML_EMPTY_BASES
|
||||
#undef TOML_CPP_VERSION
|
||||
#undef TOML_CPP
|
||||
#undef TOML_MAY_THROW
|
||||
#undef TOML_NO_DEFAULT_CASE
|
||||
#undef TOML_CONSTEVAL
|
||||
#undef TOML_LIKELY
|
||||
#undef TOML_UNLIKELY
|
||||
#undef TOML_NODISCARD_CTOR
|
||||
#undef TOML_MAKE_VERSION
|
||||
#undef TOML_LANG_EFFECTIVE_VERSION
|
||||
#undef TOML_LANG_HIGHER_THAN
|
||||
#undef TOML_LANG_AT_LEAST
|
||||
#undef TOML_LANG_UNRELEASED
|
||||
#undef TOML_STRING_PREFIX_1
|
||||
#undef TOML_STRING_PREFIX
|
||||
#undef TOML_UNDEF_MACROS
|
||||
#undef TOML_RELOPS_REORDERING
|
||||
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
|
||||
#undef TOML_ALL_INLINE
|
||||
#undef TOML_IMPLEMENTATION
|
||||
#undef TOML_EXTERNAL_LINKAGE
|
||||
#undef TOML_INTERNAL_LINKAGE
|
||||
#undef TOML_INTERNAL_NAMESPACE
|
||||
#undef TOML_COMPILER_EXCEPTIONS
|
||||
#undef TOML_TRIVIAL_ABI
|
||||
#undef TOML_ABI_NAMESPACES
|
||||
#undef TOML_ABI_NAMESPACE_START
|
||||
#undef TOML_ABI_NAMESPACE_END
|
||||
#undef TOML_PARSER_TYPENAME
|
||||
#undef TOML_LAUNDER
|
||||
#endif
|
||||
|
||||
//# {{
|
||||
#endif // INCLUDE_TOMLPLUSPLUS_H
|
||||
//# }}
|
|
@ -0,0 +1,951 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_value.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <bool IsConst>
|
||||
class TOML_TRIVIAL_ABI array_iterator final
|
||||
{
|
||||
private:
|
||||
friend class ::toml::array;
|
||||
|
||||
using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
|
||||
using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
|
||||
using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
|
||||
|
||||
mutable raw_iterator raw_;
|
||||
|
||||
array_iterator(raw_mutable_iterator raw) noexcept
|
||||
: raw_{ raw }
|
||||
{}
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<C>>
|
||||
TOML_NODISCARD_CTOR
|
||||
array_iterator(raw_const_iterator raw) noexcept
|
||||
: raw_{ raw }
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
using value_type = std::conditional_t<IsConst, const node, node>;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
array_iterator() noexcept = default;
|
||||
array_iterator(const array_iterator&) noexcept = default;
|
||||
array_iterator& operator = (const array_iterator&) noexcept = default;
|
||||
|
||||
array_iterator& operator++() noexcept // ++pre
|
||||
{
|
||||
++raw_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator operator++(int) noexcept // post++
|
||||
{
|
||||
array_iterator out{ raw_ };
|
||||
++raw_;
|
||||
return out;
|
||||
}
|
||||
|
||||
array_iterator& operator--() noexcept // --pre
|
||||
{
|
||||
--raw_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator operator--(int) noexcept // post--
|
||||
{
|
||||
array_iterator out{ raw_ };
|
||||
--raw_;
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reference operator * () const noexcept
|
||||
{
|
||||
return *raw_->get();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
pointer operator -> () const noexcept
|
||||
{
|
||||
return raw_->get();
|
||||
}
|
||||
|
||||
array_iterator& operator += (ptrdiff_t rhs) noexcept
|
||||
{
|
||||
raw_ += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator& operator -= (ptrdiff_t rhs) noexcept
|
||||
{
|
||||
raw_ -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr array_iterator operator + (const array_iterator& lhs, ptrdiff_t rhs) noexcept
|
||||
{
|
||||
return { lhs.raw_ + rhs };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr array_iterator operator + (ptrdiff_t lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return { rhs.raw_ + lhs };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr array_iterator operator - (const array_iterator& lhs, ptrdiff_t rhs) noexcept
|
||||
{
|
||||
return { lhs.raw_ - rhs };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr ptrdiff_t operator - (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ - rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ == rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ != rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ < rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ <= rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator > (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ > rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator >= (const array_iterator& lhs, const array_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ >= rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reference operator[] (ptrdiff_t idx) const noexcept
|
||||
{
|
||||
return *(raw_ + idx)->get();
|
||||
}
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<!C>>
|
||||
[[nodiscard]]
|
||||
operator array_iterator<true>() const noexcept
|
||||
{
|
||||
return array_iterator<true>{ raw_ };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(returns_nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
auto* make_node(T&& val) noexcept
|
||||
{
|
||||
using type = unwrapped<remove_cvref_t<T>>;
|
||||
if constexpr (is_one_of<type, array, table>)
|
||||
{
|
||||
static_assert(
|
||||
std::is_rvalue_reference_v<decltype(val)>,
|
||||
"Tables and arrays may only be moved (not copied)."
|
||||
);
|
||||
return new type{ std::forward<T>(val) };
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(
|
||||
is_value_or_promotable<type>,
|
||||
"Value initializers must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
return new value{ std::forward<T>(val) };
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(returns_nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
auto* make_node(inserter<T>&& val) noexcept
|
||||
{
|
||||
return make_node(std::move(val.value));
|
||||
}
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
[[nodiscard]] TOML_API bool operator == (const array& lhs, const array& rhs) noexcept;
|
||||
[[nodiscard]] TOML_API bool operator != (const array& lhs, const array& rhs) noexcept;
|
||||
template <typename Char>
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
|
||||
|
||||
/// \brief A RandomAccessIterator for iterating over nodes in a toml::array.
|
||||
using array_iterator = impl::array_iterator<false>;
|
||||
|
||||
/// \brief A RandomAccessIterator for iterating over const nodes in a toml::array.
|
||||
using const_array_iterator = impl::array_iterator<true>;
|
||||
|
||||
/// \brief A TOML array.
|
||||
///
|
||||
/// \detail The interface of this type is modeled after std::vector, with some
|
||||
/// additional considerations made for the heterogeneous nature of a
|
||||
/// TOML array. \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse("arr = [1, 2, 3, 4, 'five']"sv);
|
||||
/// auto& arr = *tbl.get_as<toml::array>("arr");
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// for (size_t i = 0; i < arr.size(); i++)
|
||||
/// {
|
||||
/// arr[i].visit([](auto&& el) noexcept
|
||||
/// {
|
||||
/// if constexpr (toml::is_number<decltype(el)>)
|
||||
/// (*el)++;
|
||||
/// else if constexpr (toml::is_string<decltype(el)>)
|
||||
/// el = "six"sv;
|
||||
/// });
|
||||
/// }
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.push_back(7);
|
||||
/// arr.push_back(8.0f);
|
||||
/// arr.push_back("nine"sv);
|
||||
/// arr.erase(arr.cbegin());
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.emplace_back<toml::array>(10, 11.0);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, 3, 4, "five"]
|
||||
/// [2, 3, 4, 5, "six"]
|
||||
/// [3, 4, 5, "six", 7, 8.0, "nine"]
|
||||
/// [3, 4, 5, "six", 7, 8.0, "nine", [10, 11.0]]
|
||||
/// \eout
|
||||
class TOML_API array final
|
||||
: public node
|
||||
{
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
std::vector<std::unique_ptr<node>> values;
|
||||
|
||||
void preinsertion_resize(size_t idx, size_t count) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
using value_type = node;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = node&;
|
||||
using const_reference = const node&;
|
||||
|
||||
/// \brief A RandomAccessIterator for iterating over nodes in a toml::array.
|
||||
using iterator = array_iterator;
|
||||
/// \brief A RandomAccessIterator for iterating over const nodes in a toml::array.
|
||||
using const_iterator = const_array_iterator;
|
||||
|
||||
/// \brief Default constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
array() noexcept;
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
array(array&& other) noexcept;
|
||||
|
||||
/// \brief Constructs an array with one or more initial values.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2.0, "three", [4, 5]]
|
||||
/// \eout
|
||||
///
|
||||
/// \remark \parblock If you need to construct an array with one child array element, the array's move constructor
|
||||
/// will take precedence and perform a move-construction instead. You can use toml::inserter to
|
||||
/// suppress this behaviour: \cpp
|
||||
/// // desired result: [ [ 42 ] ]
|
||||
/// auto bad = toml::array{ toml::array{ 42 } }
|
||||
/// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
|
||||
/// std::cout << "bad: " << bad << std::endl;
|
||||
/// std::cout << "good:" << good << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// bad: [ 42 ]
|
||||
/// good: [ [ 42 ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \endparblock
|
||||
///
|
||||
/// \tparam U One of the TOML node or value types (or a type promotable to one).
|
||||
/// \tparam V One of the TOML node or value types (or a type promotable to one).
|
||||
/// \param val The value used to initialize node 0.
|
||||
/// \param vals The values used to initialize nodes 1...N.
|
||||
template <typename U, typename... V>
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit array(U&& val, V&&... vals)
|
||||
{
|
||||
values.reserve(sizeof...(V) + 1_sz);
|
||||
values.emplace_back(impl::make_node(std::forward<U>(val)));
|
||||
if constexpr (sizeof...(V) > 0)
|
||||
{
|
||||
(
|
||||
values.emplace_back(impl::make_node(std::forward<V>(vals))),
|
||||
...
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
array& operator= (array&& rhs) noexcept;
|
||||
|
||||
array(const array&) = delete;
|
||||
array& operator= (const array&) = delete;
|
||||
|
||||
/// \brief Always returns node_type::array for array nodes.
|
||||
[[nodiscard]] node_type type() const noexcept override;
|
||||
/// \brief Always returns `false` for array nodes.
|
||||
[[nodiscard]] bool is_table() const noexcept override;
|
||||
/// \brief Always returns `true` for array nodes.
|
||||
[[nodiscard]] bool is_array() const noexcept override;
|
||||
/// \brief Always returns `false` for array nodes.
|
||||
[[nodiscard]] bool is_value() const noexcept override;
|
||||
[[nodiscard]] array* as_array() noexcept override;
|
||||
[[nodiscard]] const array* as_array() const noexcept override;
|
||||
|
||||
/// \brief Checks if the array contains nodes of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << std::endl;
|
||||
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << std::endl;
|
||||
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << std::endl;
|
||||
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// homogeneous: true
|
||||
/// all doubles: false
|
||||
/// all arrays: false
|
||||
/// all integers: true
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam T A TOML node type. <br>
|
||||
/// <strong><em>Explicitly specified:</em></strong> "is every node a T?" <br>
|
||||
/// <strong><em>Left as `void`:</em></strong> "is every node the same type?"
|
||||
///
|
||||
/// \returns True if the array was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` for empty arrays.
|
||||
template <typename T = void>
|
||||
[[nodiscard]] bool is_homogeneous() const noexcept
|
||||
{
|
||||
if (values.empty())
|
||||
return false;
|
||||
|
||||
if constexpr (std::is_same_v<T, void>)
|
||||
{
|
||||
const auto type = values[0]->type();
|
||||
for (size_t i = 1; i < values.size(); i++)
|
||||
if (values[i]->type() != type)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& v : values)
|
||||
if (!v->is<T>())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Returns true if this array contains only tables.
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool is_array_of_tables() const noexcept override
|
||||
{
|
||||
return is_homogeneous<toml::table>();
|
||||
}
|
||||
|
||||
/// \brief Gets a reference to the node at a specific index.
|
||||
[[nodiscard]] node& operator[] (size_t index) noexcept;
|
||||
/// \brief Gets a reference to the node at a specific index.
|
||||
[[nodiscard]] const node& operator[] (size_t index) const noexcept;
|
||||
|
||||
/// \brief Returns a reference to the first node in the array.
|
||||
[[nodiscard]] node& front() noexcept;
|
||||
/// \brief Returns a reference to the first node in the array.
|
||||
[[nodiscard]] const node& front() const noexcept;
|
||||
/// \brief Returns a reference to the last node in the array.
|
||||
[[nodiscard]] node& back() noexcept;
|
||||
/// \brief Returns a reference to the last node in the array.
|
||||
[[nodiscard]] const node& back() const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to the first node.
|
||||
[[nodiscard]] iterator begin() noexcept;
|
||||
/// \brief Returns an iterator to the first node.
|
||||
[[nodiscard]] const_iterator begin() const noexcept;
|
||||
/// \brief Returns an iterator to the first node.
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last node.
|
||||
[[nodiscard]] iterator end() noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last node.
|
||||
[[nodiscard]] const_iterator end() const noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last node.
|
||||
[[nodiscard]] const_iterator cend() const noexcept;
|
||||
|
||||
/// \brief Returns true if the array is empty.
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
/// \brief Returns the number of nodes in the array.
|
||||
[[nodiscard]] size_t size() const noexcept;
|
||||
/// \brief Reserves internal storage capacity up to a pre-determined number of nodes.
|
||||
void reserve(size_t new_capacity);
|
||||
/// \brief Removes all nodes from the array.
|
||||
void clear() noexcept;
|
||||
|
||||
/// \brief Returns the maximum number of nodes that can be stored in an array on the current platform.
|
||||
[[nodiscard]] size_t max_size() const noexcept;
|
||||
/// \brief Returns the current max number of nodes that may be held in the array's internal storage.
|
||||
[[nodiscard]] size_t capacity() const noexcept;
|
||||
/// \brief Requests the removal of any unused internal storage capacity.
|
||||
void shrink_to_fit();
|
||||
|
||||
/// \brief Inserts a new node at a specific position in the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 3 };
|
||||
/// arr.insert(arr.cbegin() + 1, "two");
|
||||
/// arr.insert(arr.cend(), toml::array{ 4, 5 });
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, "two", 3, [4, 5]]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML node or value types (or a type promotable to one).
|
||||
/// \param pos The insertion position.
|
||||
/// \param val The value being inserted.
|
||||
///
|
||||
/// \returns An iterator to the inserted value.
|
||||
template <typename U>
|
||||
iterator insert(const_iterator pos, U&& val) noexcept
|
||||
{
|
||||
return { values.emplace(pos.raw_, impl::make_node(std::forward<U>(val))) };
|
||||
}
|
||||
|
||||
/// \brief Repeatedly inserts a value starting at a specific position in the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{
|
||||
/// "with an evil twinkle in its eye the goose said",
|
||||
/// "and immediately we knew peace was never an option."
|
||||
/// };
|
||||
/// arr.insert(arr.cbegin() + 1, 3, "honk");
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [
|
||||
/// "with an evil twinkle in its eye the goose said",
|
||||
/// "honk",
|
||||
/// "honk",
|
||||
/// "honk",
|
||||
/// "and immediately we knew peace was never an option."
|
||||
/// ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML value types (or a type promotable to one).
|
||||
/// \param pos The insertion position.
|
||||
/// \param count The number of times the value should be inserted.
|
||||
/// \param val The value being inserted.
|
||||
///
|
||||
/// \returns An iterator to the first inserted value (or a copy of `pos` if count was 0).
|
||||
template <typename U>
|
||||
iterator insert(const_iterator pos, size_t count, U&& val) noexcept
|
||||
{
|
||||
switch (count)
|
||||
{
|
||||
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
|
||||
case 1: return insert(pos, std::forward<U>(val));
|
||||
default:
|
||||
{
|
||||
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
|
||||
preinsertion_resize(start_idx, count);
|
||||
size_t i = start_idx;
|
||||
for (size_t e = start_idx + count - 1_sz; i < e; i++)
|
||||
values[i].reset(impl::make_node(val));
|
||||
|
||||
//# potentially move the initial value into the last element
|
||||
values[i].reset(impl::make_node(std::forward<U>(val)));
|
||||
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Inserts a range of values into the array at a specific position.
|
||||
///
|
||||
/// \tparam Iter An iterator type. Must satisfy ForwardIterator.
|
||||
/// \param pos The insertion position.
|
||||
/// \param first Iterator to the first value being inserted.
|
||||
/// \param last Iterator to the one-past-the-last value being inserted.
|
||||
///
|
||||
/// \returns An iterator to the first inserted value (or a copy of `pos` if `first` == `last`).
|
||||
template <typename Iter>
|
||||
iterator insert(const_iterator pos, Iter first, Iter last) noexcept
|
||||
{
|
||||
const auto count = std::distance(first, last);
|
||||
switch (count)
|
||||
{
|
||||
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
|
||||
case 1: return insert(pos, *first);
|
||||
default:
|
||||
{
|
||||
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
|
||||
preinsertion_resize(start_idx, count);
|
||||
size_t i = start_idx;
|
||||
for (auto it = first; it != last; it++)
|
||||
values[i].reset(impl::make_node(*it));
|
||||
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Inserts a range of values into the array at a specific position.
|
||||
///
|
||||
/// \tparam U One of the TOML value types (or a type promotable to one).
|
||||
/// \param pos The insertion position.
|
||||
/// \param ilist An initializer list containing the values to be inserted.
|
||||
///
|
||||
/// \returns An iterator to the first inserted value (or a copy of `pos` if `ilist` was empty).
|
||||
template <typename U>
|
||||
iterator insert(const_iterator pos, std::initializer_list<U> ilist) noexcept
|
||||
{
|
||||
switch (ilist.size())
|
||||
{
|
||||
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
|
||||
case 1: return insert(pos, *ilist.begin());
|
||||
default:
|
||||
{
|
||||
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
|
||||
preinsertion_resize(start_idx, ilist.size());
|
||||
size_t i = start_idx;
|
||||
for (auto& val : ilist)
|
||||
values[i].reset(impl::make_node(val));
|
||||
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new value at a specific position in the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
///
|
||||
/// //add a string using std::string's substring constructor
|
||||
/// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, "drill", 2]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML node or value types.
|
||||
/// \tparam V Value constructor argument types.
|
||||
/// \param pos The insertion position.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns An iterator to the inserted value.
|
||||
///
|
||||
/// \remarks There is no difference between insert() and emplace()
|
||||
/// for trivial value types (floats, ints, bools).
|
||||
template <typename U, typename... V>
|
||||
iterator emplace(const_iterator pos, V&&... args) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return { values.emplace(pos.raw_, new impl::node_of<type>{ std::forward<V>(args)...} ) };
|
||||
}
|
||||
|
||||
/// \brief Removes the specified node from the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.erase(arr.cbegin() + 1);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, 3]
|
||||
/// [1, 3]
|
||||
/// \eout
|
||||
///
|
||||
/// \param pos Iterator to the node being erased.
|
||||
///
|
||||
/// \returns Iterator to the first node immediately following the removed node.
|
||||
iterator erase(const_iterator pos) noexcept;
|
||||
|
||||
/// \brief Removes the nodes in the range [first, last) from the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, "bad", "karma" 2 };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, "bad", "karma", 3]
|
||||
/// [1, 3]
|
||||
/// \eout
|
||||
///
|
||||
/// \param first Iterator to the first node being erased.
|
||||
/// \param last Iterator to the one-past-the-last node being erased.
|
||||
///
|
||||
/// \returns Iterator to the first node immediately following the last removed node.
|
||||
iterator erase(const_iterator first, const_iterator last) noexcept;
|
||||
|
||||
|
||||
/// \brief Resizes the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.resize(6, 42);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.resize(2, 0);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, 3]
|
||||
/// [1, 2, 3, 42, 42, 42]
|
||||
/// [1, 2]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML value types (or a type promotable to one).
|
||||
///
|
||||
/// \param new_size New number of elements the array will have.
|
||||
/// \param default_init_val The value used to initialize new elements if the array needs to grow.
|
||||
template <typename U>
|
||||
void resize(size_t new_size, U&& default_init_val) noexcept
|
||||
{
|
||||
if (!new_size)
|
||||
values.clear();
|
||||
else if (new_size < values.size())
|
||||
values.resize(new_size);
|
||||
else if (new_size > values.size())
|
||||
insert(cend(), new_size - values.size(), std::forward<U>(default_init_val));
|
||||
}
|
||||
|
||||
/// \brief Shrinks the array to the given size.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.truncate(5); // no-op
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.truncate(1);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, 3]
|
||||
/// [1, 2, 3]
|
||||
/// [1]
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks Does nothing if the requested size is larger than or equal to the current size.
|
||||
void truncate(size_t new_size);
|
||||
|
||||
/// \brief Appends a new value to the end of the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
/// arr.push_back(3);
|
||||
/// arr.push_back(4.0);
|
||||
/// arr.push_back(toml::array{ 5, "six"sv });
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, 3, 4.0, [5, "six"]]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML value types (or a type promotable to one).
|
||||
/// \param val The value being added.
|
||||
///
|
||||
/// \returns A reference to the newly-constructed value node.
|
||||
template <typename U>
|
||||
decltype(auto) push_back(U&& val) noexcept
|
||||
{
|
||||
auto nde = impl::make_node(std::forward<U>(val));
|
||||
values.emplace_back(nde);
|
||||
return *nde;
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new value at the end of the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
/// arr.emplace_back<toml::array>(3, "four"sv);
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, [3, "four"]]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML value types.
|
||||
/// \tparam V Value constructor argument types.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns A reference to the newly-constructed value node.
|
||||
///
|
||||
/// \remarks There is no difference between push_back and emplace_back
|
||||
/// For trivial value types (floats, ints, bools).
|
||||
template <typename U, typename... V>
|
||||
decltype(auto) emplace_back(V&&... args) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
auto nde = new impl::node_of<type>{ std::forward<V>(args)... };
|
||||
values.emplace_back(nde);
|
||||
return *nde;
|
||||
}
|
||||
|
||||
/// \brief Removes the last node from the array.
|
||||
void pop_back() noexcept;
|
||||
|
||||
/// \brief Gets the node at a specific index.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 99, "bottles of beer on the wall" };
|
||||
/// std::cout << "node [0] exists: "sv << !!arr.get(0) << std::endl;
|
||||
/// std::cout << "node [1] exists: "sv << !!arr.get(1) << std::endl;
|
||||
/// std::cout << "node [2] exists: "sv << !!arr.get(2) << std::endl;
|
||||
/// if (auto val = arr.get(0))
|
||||
/// std::cout << "node [0] was an "sv << val->type() << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// node [0] exists: true
|
||||
/// node [1] exists: true
|
||||
/// node [2] exists: false
|
||||
/// node [0] was an integer
|
||||
/// \eout
|
||||
///
|
||||
/// \param index The node's index.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified index if one existed, or nullptr.
|
||||
[[nodiscard]] node* get(size_t index) noexcept;
|
||||
|
||||
/// \brief Gets the node at a specific index (const overload).
|
||||
///
|
||||
/// \param index The node's index.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified index if one existed, or nullptr.
|
||||
[[nodiscard]] const node* get(size_t index) const noexcept;
|
||||
|
||||
/// \brief Gets the node at a specific index if it is a particular type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
|
||||
/// if (auto val = arr.get_as<int64_t>(0))
|
||||
/// std::cout << "node [0] was an integer with value "sv << **val << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// node [0] was an integer with value 42
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam T The node's type.
|
||||
/// \param index The node's index.
|
||||
///
|
||||
/// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::node_of<T>* get_as(size_t index) noexcept
|
||||
{
|
||||
if (auto val = get(index))
|
||||
return val->as<T>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Gets the node at a specific index if it is a particular type (const overload).
|
||||
///
|
||||
/// \tparam T The node's type.
|
||||
/// \param index The node's index.
|
||||
///
|
||||
/// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::node_of<T>* get_as(size_t index) const noexcept
|
||||
{
|
||||
if (auto val = get(index))
|
||||
return val->as<T>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS array.
|
||||
/// \param rhs The RHS array.
|
||||
///
|
||||
/// \returns True if the arrays contained the same values.
|
||||
friend bool operator == (const array& lhs, const array& rhs) noexcept;
|
||||
|
||||
/// \brief Inequality operator.
|
||||
///
|
||||
/// \param lhs The LHS array.
|
||||
/// \param rhs The RHS array.
|
||||
///
|
||||
/// \returns True if the arrays did not contain the same values.
|
||||
friend bool operator != (const array& lhs, const array& rhs) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static bool container_equality(const array& lhs, const T& rhs) noexcept
|
||||
{
|
||||
using elem_t = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<elem_t>,
|
||||
"Container element type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto& list_elem : rhs)
|
||||
{
|
||||
const auto elem = lhs.get_as<impl::promoted<elem_t>>(i++);
|
||||
if (!elem || *elem != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t total_leaf_count() const noexcept;
|
||||
|
||||
void flatten_child(array&& child, size_t& dest_index) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Initializer list equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::initializer_list<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>)
|
||||
|
||||
/// \brief Vector equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator == (const array& lhs, const std::vector<T>& rhs) noexcept
|
||||
{
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>)
|
||||
|
||||
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
|
||||
///
|
||||
/// \detail \cpp
|
||||
///
|
||||
/// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// arr.flatten();
|
||||
/// std::cout << arr << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [1, 2, [3, 4, [5]], 6, []]
|
||||
/// [1, 2, 3, 4, 5, 6]
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks Arrays inside child tables are not flattened.
|
||||
///
|
||||
/// A reference to the array.
|
||||
array& flatten() &;
|
||||
|
||||
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
|
||||
array&& flatten()&&
|
||||
{
|
||||
return static_cast<toml::array&&>(static_cast<toml::array&>(*this).flatten());
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
|
||||
};
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS //TOML_DISABLE_VTABLE_WARNINGS
|
|
@ -0,0 +1,237 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_array.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SUGGEST_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::preinsertion_resize(size_t idx, size_t count) noexcept
|
||||
{
|
||||
const auto new_size = values.size() + count;
|
||||
const auto inserting_at_end = idx == values.size();
|
||||
values.resize(new_size);
|
||||
if (!inserting_at_end)
|
||||
{
|
||||
for (size_t r = new_size, e = idx + count, l = e; r-- > e; l--)
|
||||
values[r] = std::move(values[l]);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::array() noexcept = default;
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::array(array&& other) noexcept
|
||||
: node{ std::move(other) },
|
||||
values{ std::move(other.values) }
|
||||
{}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array& array::operator= (array&& rhs) noexcept
|
||||
{
|
||||
node::operator=(std::move(rhs));
|
||||
values = std::move(rhs.values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) node_type array::type() const noexcept { return node_type::array; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_table() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_array() const noexcept { return true; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_value() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) const array* array::as_array() const noexcept { return this; }
|
||||
TOML_MEMBER_ATTR(const) array* array::as_array() noexcept { return this; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *values[index]; }
|
||||
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *values[index]; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *values.front(); }
|
||||
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *values.back(); }
|
||||
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *values.front(); }
|
||||
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *values.back(); }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { values.begin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { values.end() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { values.cbegin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { values.cend() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { values.begin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { values.end() }; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return values.size(); }
|
||||
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return values.capacity(); }
|
||||
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return values.empty(); }
|
||||
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return values.max_size(); }
|
||||
|
||||
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { values.reserve(new_capacity); }
|
||||
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { values.clear(); }
|
||||
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { values.shrink_to_fit(); }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::truncate(size_t new_size)
|
||||
{
|
||||
if (new_size < values.size())
|
||||
values.resize(new_size);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::iterator array::erase(const_iterator pos) noexcept
|
||||
{
|
||||
return { values.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
|
||||
{
|
||||
return { values.erase(first.raw_, last.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::pop_back() noexcept
|
||||
{
|
||||
values.pop_back();
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
TOML_ATTR(pure)
|
||||
node* array::get(size_t index) noexcept
|
||||
{
|
||||
return index < values.size() ? values[index].get() : nullptr;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
TOML_ATTR(pure)
|
||||
const node* array::get(size_t index) const noexcept
|
||||
{
|
||||
return index < values.size() ? values[index].get() : nullptr;
|
||||
}
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator == (const array& lhs, const array& rhs) noexcept
|
||||
{
|
||||
if (&lhs == &rhs)
|
||||
return true;
|
||||
if (lhs.values.size() != rhs.values.size())
|
||||
return false;
|
||||
for (size_t i = 0, e = lhs.values.size(); i < e; i++)
|
||||
{
|
||||
const auto lhs_type = lhs.values[i]->type();
|
||||
const node& rhs_ = *rhs.values[i];
|
||||
const auto rhs_type = rhs_.type();
|
||||
if (lhs_type != rhs_type)
|
||||
return false;
|
||||
|
||||
const bool equal = lhs.values[i]->visit([&](const auto& lhs_) noexcept
|
||||
{
|
||||
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
|
||||
});
|
||||
if (!equal)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator != (const array& lhs, const array& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
size_t array::total_leaf_count() const noexcept
|
||||
{
|
||||
size_t leaves{};
|
||||
for (size_t i = 0, e = values.size(); i < e; i++)
|
||||
{
|
||||
auto arr = values[i]->as_array();
|
||||
leaves += arr ? arr->total_leaf_count() : 1_sz;
|
||||
}
|
||||
return leaves;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::flatten_child(array&& child, size_t& dest_index) noexcept
|
||||
{
|
||||
for (size_t i = 0, e = child.size(); i < e; i++)
|
||||
{
|
||||
auto type = child.values[i]->type();
|
||||
if (type == node_type::array)
|
||||
{
|
||||
array& arr = *reinterpret_cast<array*>(child.values[i].get());
|
||||
if (!arr.empty())
|
||||
flatten_child(std::move(arr), dest_index);
|
||||
}
|
||||
else
|
||||
values[dest_index++] = std::move(child.values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array& array::flatten() &
|
||||
{
|
||||
if (values.empty())
|
||||
return *this;
|
||||
|
||||
bool requires_flattening = false;
|
||||
size_t size_after_flattening = values.size();
|
||||
for (size_t i = values.size(); i --> 0_sz;)
|
||||
{
|
||||
auto arr = values[i]->as_array();
|
||||
if (!arr)
|
||||
continue;
|
||||
size_after_flattening--; //discount the array itself
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
if (leaf_count > 0_sz)
|
||||
{
|
||||
requires_flattening = true;
|
||||
size_after_flattening += leaf_count;
|
||||
}
|
||||
else
|
||||
values.erase(values.cbegin() + static_cast<ptrdiff_t>(i));
|
||||
}
|
||||
|
||||
if (!requires_flattening)
|
||||
return *this;
|
||||
|
||||
values.reserve(size_after_flattening);
|
||||
|
||||
size_t i = 0;
|
||||
while (i < values.size())
|
||||
{
|
||||
auto arr = values[i]->as_array();
|
||||
if (!arr)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<node> arr_storage = std::move(values[i]);
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
if (leaf_count > 1_sz)
|
||||
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
|
||||
flatten_child(std::move(*arr), i); //increments i
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SUGGEST_WARNINGS
|
|
@ -0,0 +1,594 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_preprocessor.h"
|
||||
|
||||
////////// INCLUDES
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
#include <cstring> //memcpy, memset
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iosfwd>
|
||||
#ifndef TOML_OPTIONAL_TYPE
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
#if TOML_CHAR_8_STRINGS && !defined(__cpp_lib_char8_t)
|
||||
#error toml++ requires implementation support to use char8_t strings, but yours does not provide it.
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_launder
|
||||
#define TOML_LAUNDER(x) std::launder(x)
|
||||
#else
|
||||
#define TOML_LAUNDER(x) x
|
||||
#endif
|
||||
|
||||
////////// FORWARD DECLARATIONS & TYPEDEFS
|
||||
|
||||
/// \brief The root namespace for all toml++ functions and types.
|
||||
namespace toml
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
using size_t = std::size_t;
|
||||
using ptrdiff_t = std::ptrdiff_t;
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
TOML_CONSTEVAL size_t operator"" _sz(unsigned long long n) noexcept
|
||||
{
|
||||
return static_cast<size_t>(n);
|
||||
}
|
||||
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
|
||||
using string_char = char8_t;
|
||||
using string = std::u8string;
|
||||
using string_view = std::u8string_view;
|
||||
|
||||
#else
|
||||
|
||||
/// \brief The base character type for keys and string values.
|
||||
/// \remarks This will be an alias for char8_t if #TOML_CHAR_8_STRINGS is enabled.
|
||||
using string_char = char;
|
||||
|
||||
/// \brief The string type for keys and string values.
|
||||
/// \remarks This will be an alias for std::u8string if #TOML_CHAR_8_STRINGS is enabled.
|
||||
using string = std::string;
|
||||
|
||||
/// \brief The string type for keys and string values.
|
||||
/// \remarks This will be an alias for std::u8string_view if #TOML_CHAR_8_STRINGS is enabled.
|
||||
using string_view = std::string_view;
|
||||
|
||||
#endif
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
TOML_DISABLE_SHADOW_WARNINGS // false positive on gcc
|
||||
|
||||
#if !TOML_DOXYGEN
|
||||
|
||||
// foward declarations are hidden from doxygen
|
||||
// because they fuck it up =/
|
||||
struct date;
|
||||
struct time;
|
||||
struct time_offset;
|
||||
class node;
|
||||
class array;
|
||||
class table;
|
||||
template <typename> class node_view;
|
||||
template <typename> class value;
|
||||
template <typename> class default_formatter;
|
||||
template <typename> class json_formatter;
|
||||
|
||||
#ifdef TOML_OPTIONAL_TYPE
|
||||
TOML_ABI_NAMESPACE_START(custopt)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(stdopt)
|
||||
#endif
|
||||
|
||||
struct date_time;
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_OPTIONAL_TYPE
|
||||
|
||||
#endif // !TOML_DOXYGEN
|
||||
|
||||
/// \brief TOML node type identifiers.
|
||||
enum class node_type : uint8_t
|
||||
{
|
||||
none, ///< Not-a-node.
|
||||
table, ///< The node is a toml::table.
|
||||
array, ///< The node is a toml::array.
|
||||
string, ///< The node is a toml::value<toml::string>.
|
||||
integer, ///< The node is a toml::value<int64_t>.
|
||||
floating_point, ///< The node is a toml::value<double>.
|
||||
boolean, ///< The node is a toml::value<bool>.
|
||||
date, ///< The node is a toml::value<date>.
|
||||
time, ///< The node is a toml::value<time>.
|
||||
date_time ///< The node is a toml::value<date_time>.
|
||||
};
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS, TOML_DISABLE_SHADOW_WARNINGS
|
||||
|
||||
#ifdef TOML_OPTIONAL_TYPE
|
||||
|
||||
template <typename T>
|
||||
using optional = TOML_OPTIONAL_TYPE<T>;
|
||||
|
||||
#else
|
||||
|
||||
/// \brief The 'optional' type used throughout the library.
|
||||
///
|
||||
/// \remarks By default this will be a simple alias for std::optional, but you can change the optional type
|
||||
/// used by the library by defining #TOML_OPTIONAL_TYPE.
|
||||
template <typename T>
|
||||
using optional = std::optional<T>;
|
||||
|
||||
#endif
|
||||
|
||||
#if TOML_LARGE_FILES
|
||||
|
||||
using source_index = uint32_t;
|
||||
|
||||
#else
|
||||
|
||||
/// \brief The integer type used to tally line numbers and columns.
|
||||
/// \remarks This will be an alias for uint32_t if #TOML_LARGE_FILES is enabled.
|
||||
using source_index = uint16_t;
|
||||
|
||||
#endif
|
||||
|
||||
/// \brief A pointer to a shared string resource containing a source path.
|
||||
using source_path_ptr = std::shared_ptr<const std::string>;
|
||||
|
||||
#if TOML_LARGE_FILES
|
||||
TOML_ABI_NAMESPACE_START(lf)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(sf)
|
||||
#endif
|
||||
|
||||
/// \brief A source document line-and-column pair.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto table = toml::parse_file("config.toml"sv);
|
||||
/// std::cout << "The node 'description' was defined at "sv
|
||||
/// << table.get("description")->source().begin()
|
||||
/// << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// The value 'description' was defined at line 7, column 15
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
|
||||
/// various non-conventional whitespace and newline characters, but it doesn't give
|
||||
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
|
||||
/// If a TOML document contains lots of codepoints outside of the ASCII range
|
||||
/// you may find that your source_positions don't match those given by a text editor
|
||||
/// (typically the line numbers will be accurate but column numbers will be too high).
|
||||
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
|
||||
/// between parser complexity and correctness.
|
||||
struct TOML_TRIVIAL_ABI source_position
|
||||
{
|
||||
/// \brief The line number.
|
||||
/// \remarks Valid line numbers start at 1.
|
||||
source_index line;
|
||||
|
||||
/// \brief The column number.
|
||||
/// \remarks Valid column numbers start at 1.
|
||||
source_index column;
|
||||
|
||||
/// \brief Returns true if both line and column numbers are non-zero.
|
||||
[[nodiscard]]
|
||||
explicit constexpr operator bool () const noexcept
|
||||
{
|
||||
return line > source_index{} && column > source_index{};
|
||||
}
|
||||
|
||||
/// \brief Returns true if two source_positions represent the same line and column.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const source_position& lhs, const source_position& rhs) noexcept
|
||||
{
|
||||
return lhs.line == rhs.line
|
||||
&& lhs.column == rhs.column;
|
||||
}
|
||||
|
||||
/// \brief Returns true if two source_positions do not represent the same line and column.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const source_position& lhs, const source_position& rhs) noexcept
|
||||
{
|
||||
return lhs.line != rhs.line
|
||||
|| lhs.column != rhs.column;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the LHS position is before the RHS position.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (const source_position& lhs, const source_position& rhs) noexcept
|
||||
{
|
||||
return lhs.line < rhs.line
|
||||
|| (lhs.line == rhs.line && lhs.column < rhs.column);
|
||||
}
|
||||
|
||||
/// \brief Returns true if the LHS position is before the RHS position or equal to it.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (const source_position& lhs, const source_position& rhs) noexcept
|
||||
{
|
||||
return lhs.line < rhs.line
|
||||
|| (lhs.line == rhs.line && lhs.column <= rhs.column);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A source document region.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// #include <fstream>
|
||||
///
|
||||
/// auto tbl = toml::parse_file("config.toml"sv);
|
||||
/// if (auto server = tbl.get("server"))
|
||||
/// {
|
||||
/// std::cout << "begin: "sv << server->source().begin << std::endl;
|
||||
/// std::cout << "end: "sv << server->source().end << std::endl;
|
||||
/// std::cout << "path: "sv << *server->source().path << std::endl;
|
||||
/// }
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// begin: line 3, column 1
|
||||
/// end: line 3, column 22
|
||||
/// path: config.toml
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
|
||||
/// various non-conventional whitespace and newline characters, but it doesn't give
|
||||
/// much thought to combining marks, grapheme clusters vs. characters, et cetera.
|
||||
/// If a TOML document contains lots of codepoints outside of the ASCII range
|
||||
/// you may find that your source_positions don't match those given by a text editor
|
||||
/// (typically the line numbers will be accurate but column numbers will be too high).
|
||||
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
|
||||
/// between parser complexity and correctness.
|
||||
struct source_region
|
||||
{
|
||||
/// \brief The beginning of the region (inclusive).
|
||||
source_position begin;
|
||||
|
||||
/// \brief The end of the region (exclusive).
|
||||
source_position end;
|
||||
|
||||
/// \brief The path to the corresponding source document.
|
||||
///
|
||||
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
|
||||
source_path_ptr path;
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
|
||||
}
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename T>
|
||||
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
template <typename T, typename... U>
|
||||
struct is_one_of_ : std::integral_constant<bool,
|
||||
(false || ... || std::is_same_v<T, U>)
|
||||
> {};
|
||||
|
||||
template <typename T, typename... U>
|
||||
inline constexpr bool is_one_of = is_one_of_<T, U...>::value;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr std::underlying_type_t<T> unbox_enum(T val) noexcept
|
||||
{
|
||||
return static_cast<std::underlying_type_t<T>>(val);
|
||||
}
|
||||
|
||||
// Q: "why not use std::find??"
|
||||
// A: Because <algorithm> is _huge_ and std::find would be the only thing I used from it.
|
||||
// I don't want to impose such a heavy compile-time burden on users.
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
inline const T* find(const std::vector<T>& haystack, const T& needle) noexcept
|
||||
{
|
||||
for (size_t i = 0, e = haystack.size(); i < e; i++)
|
||||
if (haystack[i] == needle)
|
||||
return haystack.data() + i;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if TOML_ABI_NAMESPACES
|
||||
#if TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_START(impl_ex)
|
||||
#define TOML_PARSER_TYPENAME ::toml::impl::abi_impl_ex::parser
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(impl_noex)
|
||||
#define TOML_PARSER_TYPENAME ::toml::impl::abi_impl_noex::parser
|
||||
#endif
|
||||
#else
|
||||
#define TOML_PARSER_TYPENAME ::toml::impl::parser
|
||||
#endif
|
||||
|
||||
class parser;
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value =
|
||||
std::is_same_v<T, string>
|
||||
|| std::is_same_v<T, int64_t>
|
||||
|| std::is_same_v<T, double>
|
||||
|| std::is_same_v<T, bool>
|
||||
|| std::is_same_v<T, date>
|
||||
|| std::is_same_v<T, time>
|
||||
|| std::is_same_v<T, date_time>;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value_or_promotable =
|
||||
is_value<T>
|
||||
|| std::is_same_v<std::decay_t<T>, string_char*>
|
||||
|| std::is_same_v<T, string_view>
|
||||
|| std::is_same_v<T, int32_t>
|
||||
|| std::is_same_v<T, int16_t>
|
||||
|| std::is_same_v<T, int8_t>
|
||||
|| std::is_same_v<T, uint32_t>
|
||||
|| std::is_same_v<T, uint16_t>
|
||||
|| std::is_same_v<T, uint8_t>
|
||||
|| std::is_same_v<T, float>
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
|| std::is_same_v<T, TOML_SMALL_FLOAT_TYPE>
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
|| std::is_same_v<T, TOML_SMALL_INT_TYPE>
|
||||
#endif
|
||||
;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_value_or_node =
|
||||
is_value<T>
|
||||
|| std::is_same_v<T, array>
|
||||
|| std::is_same_v<T, table>;
|
||||
|
||||
template <typename T> struct node_wrapper { using type = T; };
|
||||
template <> struct node_wrapper<string> { using type = value<string>; };
|
||||
template <> struct node_wrapper<int64_t> { using type = value<int64_t>; };
|
||||
template <> struct node_wrapper<double> { using type = value<double>; };
|
||||
template <> struct node_wrapper<bool> { using type = value<bool>; };
|
||||
template <> struct node_wrapper<date> { using type = value<date>; };
|
||||
template <> struct node_wrapper<time> { using type = value<time>; };
|
||||
template <> struct node_wrapper<date_time> { using type = value<date_time>; };
|
||||
|
||||
template <typename T>
|
||||
using node_of = typename impl::node_wrapper<T>::type;
|
||||
|
||||
template <typename T> struct node_unwrapper { using type = T; };
|
||||
template <typename T> struct node_unwrapper<value<T>> { using type = T; };
|
||||
|
||||
template <typename T> using unwrapped = typename impl::node_unwrapper<T>::type;
|
||||
|
||||
template <typename T> struct value_promoter { using type = T; };
|
||||
template <size_t N> struct value_promoter<const string_char[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const string_char(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<const string_char(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<const string_char*> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char(&)[N]> { using type = string; };
|
||||
template <size_t N> struct value_promoter<string_char(&&)[N]> { using type = string; };
|
||||
template <> struct value_promoter<string_char*> { using type = string; };
|
||||
template <> struct value_promoter<string_view> { using type = string; };
|
||||
template <> struct value_promoter<int32_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<int16_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<int8_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint32_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint16_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<uint8_t> { using type = int64_t; };
|
||||
template <> struct value_promoter<float> { using type = double; };
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
template <> struct value_promoter<TOML_SMALL_FLOAT_TYPE> { using type = double; };
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
template <> struct value_promoter<TOML_SMALL_INT_TYPE> { using type = int64_t; };
|
||||
#endif
|
||||
template <typename T> using promoted = typename impl::value_promoter<T>::type;
|
||||
|
||||
template <typename T> struct node_type_of_;
|
||||
template <> struct node_type_of_<table> { static constexpr auto value = node_type::table; };
|
||||
template <> struct node_type_of_<array> { static constexpr auto value = node_type::array; };
|
||||
template <> struct node_type_of_<string> { static constexpr auto value = node_type::string; };
|
||||
template <> struct node_type_of_<int64_t> { static constexpr auto value = node_type::integer; };
|
||||
template <> struct node_type_of_<double> { static constexpr auto value = node_type::floating_point; };
|
||||
template <> struct node_type_of_<bool> { static constexpr auto value = node_type::boolean; };
|
||||
template <> struct node_type_of_<date> { static constexpr auto value = node_type::date; };
|
||||
template <> struct node_type_of_<time> { static constexpr auto value = node_type::time; };
|
||||
template <> struct node_type_of_<date_time> { static constexpr auto value = node_type::date_time; };
|
||||
|
||||
template <typename T>
|
||||
inline constexpr auto node_type_of = node_type_of_<promoted<typename node_unwrapper<remove_cvref_t<T>>::type>>::value;
|
||||
|
||||
inline constexpr std::string_view low_character_escape_table[] =
|
||||
{
|
||||
"\\u0000"sv,
|
||||
"\\u0001"sv,
|
||||
"\\u0002"sv,
|
||||
"\\u0003"sv,
|
||||
"\\u0004"sv,
|
||||
"\\u0005"sv,
|
||||
"\\u0006"sv,
|
||||
"\\u0007"sv,
|
||||
"\\b"sv,
|
||||
"\\t"sv,
|
||||
"\\n"sv,
|
||||
"\\u000B"sv,
|
||||
"\\f"sv,
|
||||
"\\r"sv,
|
||||
"\\u000E"sv,
|
||||
"\\u000F"sv,
|
||||
"\\u0010"sv,
|
||||
"\\u0011"sv,
|
||||
"\\u0012"sv,
|
||||
"\\u0013"sv,
|
||||
"\\u0014"sv,
|
||||
"\\u0015"sv,
|
||||
"\\u0016"sv,
|
||||
"\\u0017"sv,
|
||||
"\\u0018"sv,
|
||||
"\\u0019"sv,
|
||||
"\\u001A"sv,
|
||||
"\\u001B"sv,
|
||||
"\\u001C"sv,
|
||||
"\\u001D"sv,
|
||||
"\\u001E"sv,
|
||||
"\\u001F"sv,
|
||||
};
|
||||
|
||||
inline constexpr std::string_view node_type_friendly_names[] =
|
||||
{
|
||||
"none"sv,
|
||||
"table"sv,
|
||||
"array"sv,
|
||||
"string"sv,
|
||||
"integer"sv,
|
||||
"floating-point"sv,
|
||||
"boolean"sv,
|
||||
"date"sv,
|
||||
"time"sv,
|
||||
"date-time"sv
|
||||
};
|
||||
|
||||
#define TOML_P2S_DECL(Linkage, Type) \
|
||||
template <typename Char> \
|
||||
Linkage void print_to_stream(Type, std::basic_ostream<Char>&)
|
||||
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, int64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint8_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint16_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint32_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, uint64_t);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, float);
|
||||
TOML_P2S_DECL(TOML_ALWAYS_INLINE, double);
|
||||
TOML_P2S_DECL(inline, const date&);
|
||||
TOML_P2S_DECL(inline, const time&);
|
||||
TOML_P2S_DECL(inline, time_offset);
|
||||
TOML_P2S_DECL(inline, const date_time&);
|
||||
|
||||
#undef TOML_P2S_DECL
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief Metafunction for determining if a type is a toml::table.
|
||||
template <typename T>
|
||||
inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>;
|
||||
/// \brief Metafunction for determining if a type is a toml::array.
|
||||
template <typename T>
|
||||
inline constexpr bool is_array = std::is_same_v<impl::remove_cvref_t<T>, array>;
|
||||
/// \brief Metafunction for determining if a type is a toml::string or toml::value<toml::string>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_string = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<string>>;
|
||||
/// \brief Metafunction for determining if a type is an int64_t or toml::value<int64_t>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_integer = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<int64_t>>;
|
||||
/// \brief Metafunction for determining if a type is a double or toml::value<double>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_floating_point = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<double>>;
|
||||
/// \brief Metafunction for determining if a type satisfies `toml::is_integer || toml::is_floating_point`.
|
||||
template <typename T>
|
||||
inline constexpr bool is_number = is_integer<T> || is_floating_point<T>;
|
||||
/// \brief Metafunction for determining if a type is a bool toml::value<bool>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_boolean = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<bool>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::date or toml::value<date>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_date = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<date>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::time or toml::value<time>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_time = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<time>>;
|
||||
/// \brief Metafunction for determining if a type is a toml::date_time or toml::value<date_time>.
|
||||
template <typename T>
|
||||
inline constexpr bool is_date_time = std::is_same_v<impl::node_of<impl::remove_cvref_t<T>>, value<date_time>>;
|
||||
|
||||
/// \brief Pretty-prints the value of a node_type to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2.0, "3", false };
|
||||
/// for (size_t i = 0; i < arr.size() i++)
|
||||
/// std::cout << "Element ["sv << i << "] is: "sv << arr[i].type() << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// Element [0] is: integer
|
||||
/// Element [1] is: floating-point
|
||||
/// Element [2] is: string
|
||||
/// Element [3] is: boolean
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, node_type rhs)
|
||||
{
|
||||
using underlying_t = std::underlying_type_t<node_type>;
|
||||
const auto str = impl::node_type_friendly_names[static_cast<underlying_t>(rhs)];
|
||||
if constexpr (std::is_same_v<Char, char>)
|
||||
return lhs << str;
|
||||
else
|
||||
{
|
||||
if constexpr (sizeof(Char) == 1)
|
||||
return lhs << std::basic_string_view<Char>{ reinterpret_cast<const Char*>(str.data()), str.length() };
|
||||
else
|
||||
return lhs << str.data();
|
||||
}
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, node_type);
|
||||
#endif
|
||||
|
||||
/// \brief Helper class for suppressing move-construction in single-argument array constructors.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// // desired result: [ [ 42 ] ]
|
||||
/// auto bad = toml::array{ toml::array{ 42 } }
|
||||
/// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
|
||||
/// std::cout << "bad: " << bad << std::endl;
|
||||
/// std::cout << "good:" << good << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// bad: [ 42 ]
|
||||
/// good: [ [ 42 ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \see toml::array
|
||||
template <typename T>
|
||||
struct TOML_TRIVIAL_ABI inserter
|
||||
{
|
||||
T&& value;
|
||||
};
|
||||
template <typename T> inserter(T&&) -> inserter<T>;
|
||||
}
|
|
@ -0,0 +1,437 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief A local date.
|
||||
struct TOML_TRIVIAL_ABI date
|
||||
{
|
||||
/// \brief The year component.
|
||||
uint16_t year;
|
||||
/// \brief The month component, from 1 - 12.
|
||||
uint8_t month;
|
||||
/// \brief The day component, from 1 - 31.
|
||||
uint8_t day;
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year == rhs.year
|
||||
&& lhs.month == rhs.month
|
||||
&& lhs.day == rhs.day;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (date lhs, date rhs) noexcept
|
||||
{
|
||||
return lhs.year != rhs.year
|
||||
|| lhs.month != rhs.month
|
||||
|| lhs.day != rhs.day;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
static constexpr uint32_t pack(date d) noexcept
|
||||
{
|
||||
return static_cast<uint32_t>(d.year) << 16
|
||||
| static_cast<uint32_t>(d.month) << 8
|
||||
| static_cast<uint32_t>(d.day);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (date lhs, date rhs) noexcept
|
||||
{
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (date lhs, date rhs) noexcept
|
||||
{
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator > (date lhs, date rhs) noexcept
|
||||
{
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator >= (date lhs, date rhs) noexcept
|
||||
{
|
||||
return pack(lhs) >= pack(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date{ 1987, 3, 16 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date& rhs)
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const date&);
|
||||
#endif
|
||||
|
||||
/// \brief A local time-of-day.
|
||||
struct TOML_TRIVIAL_ABI time
|
||||
{
|
||||
/// \brief The hour component, from 0 - 23.
|
||||
uint8_t hour;
|
||||
/// \brief The minute component, from 0 - 59.
|
||||
uint8_t minute;
|
||||
/// \brief The second component, from 0 - 59.
|
||||
uint8_t second;
|
||||
/// \brief The fractional nanoseconds component, from 0 - 999999999.
|
||||
uint32_t nanosecond;
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return lhs.hour == rhs.hour
|
||||
&& lhs.minute == rhs.minute
|
||||
&& lhs.second == rhs.second
|
||||
&& lhs.nanosecond == rhs.nanosecond;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const time& lhs, const time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
static constexpr uint64_t pack(time t) noexcept
|
||||
{
|
||||
return static_cast<uint64_t>(t.hour) << 48
|
||||
| static_cast<uint64_t>(t.minute) << 40
|
||||
| static_cast<uint64_t>(t.second) << 32
|
||||
| static_cast<uint64_t>(t.nanosecond);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (time lhs, time rhs) noexcept
|
||||
{
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (time lhs, time rhs) noexcept
|
||||
{
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator > (time lhs, time rhs) noexcept
|
||||
{
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator >= (time lhs, time rhs) noexcept
|
||||
{
|
||||
return pack(lhs) >= pack(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time{ 10, 20, 34 } << std::endl;
|
||||
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 10:20:34
|
||||
/// 10:20:34.5
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time& rhs)
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const time&);
|
||||
#endif
|
||||
|
||||
/// \brief A timezone offset.
|
||||
struct TOML_TRIVIAL_ABI time_offset
|
||||
{
|
||||
/// \brief Offset from UTC+0, in minutes.
|
||||
int16_t minutes;
|
||||
|
||||
/// \brief Default-constructs a zero time-offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset() noexcept
|
||||
: minutes{}
|
||||
{}
|
||||
|
||||
/// \brief Constructs a timezone offset from separate hour and minute totals.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ 0, 0 } << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// +02:30
|
||||
/// -01:30
|
||||
/// -02:30
|
||||
/// Z
|
||||
/// \eout
|
||||
///
|
||||
/// \param h The total hours.
|
||||
/// \param m The total minutes.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset(int8_t h, int8_t m) noexcept
|
||||
: minutes{ static_cast<int16_t>(h * 60 + m) }
|
||||
{}
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes == rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes != rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes < rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes <= rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator > (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes > rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator >= (time_offset lhs, time_offset rhs) noexcept
|
||||
{
|
||||
return lhs.minutes >= rhs.minutes;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ 2, -30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{} << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// +02:30
|
||||
/// +01:30
|
||||
/// Z
|
||||
/// -01:30
|
||||
/// -02:30
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const time_offset& rhs)
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
|
||||
#endif
|
||||
|
||||
#ifdef TOML_OPTIONAL_TYPE
|
||||
TOML_ABI_NAMESPACE_START(custopt)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(stdopt)
|
||||
#endif
|
||||
|
||||
/// \brief A date-time.
|
||||
struct date_time
|
||||
{
|
||||
/// \brief The date component.
|
||||
toml::date date;
|
||||
/// \brief The time component.
|
||||
toml::time time;
|
||||
/// \brief The timezone offset component.
|
||||
///
|
||||
/// \remarks The date_time is said to be 'local' if the time_offset is empty.
|
||||
optional<toml::time_offset> time_offset;
|
||||
|
||||
/// \brief Default-constructs a zero date-time.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time() noexcept
|
||||
: date{},
|
||||
time{}
|
||||
{}
|
||||
|
||||
/// \brief Constructs a local date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t) noexcept
|
||||
: date{ d },
|
||||
time{ t }
|
||||
{}
|
||||
|
||||
/// \brief Constructs an offset date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
/// \param offset The timezone offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t, toml::time_offset offset) noexcept
|
||||
: date{ d },
|
||||
time{ t },
|
||||
time_offset{ offset }
|
||||
{}
|
||||
|
||||
/// \brief Returns true if this date_time does not contain timezone offset information.
|
||||
[[nodiscard]]
|
||||
constexpr bool is_local() const noexcept
|
||||
{
|
||||
return !time_offset.has_value();
|
||||
}
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return lhs.date == rhs.date
|
||||
&& lhs.time == rhs.time
|
||||
&& lhs.time_offset == rhs.time_offset;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator < (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
if (lhs.date != rhs.date)
|
||||
return lhs.date < rhs.date;
|
||||
if (lhs.time != rhs.time)
|
||||
return lhs.time < rhs.time;
|
||||
return lhs.time_offset < rhs.time_offset;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator <= (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
if (lhs.date != rhs.date)
|
||||
return lhs.date < rhs.date;
|
||||
if (lhs.time != rhs.time)
|
||||
return lhs.time < rhs.time;
|
||||
return lhs.time_offset <= rhs.time_offset;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator > (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator >= (const date_time& lhs, const date_time& rhs) noexcept
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_OPTIONAL_TYPE
|
||||
|
||||
/// \brief Prints a date_time out to a stream in RFC 3339 format.
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << std::endl;
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << std::endl;
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16T10:20:34
|
||||
/// 1987-03-16T10:20:34-02:30
|
||||
/// 1987-03-16T10:20:34Z
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const date_time& rhs)
|
||||
{
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,388 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_utf8.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
[[nodiscard]] TOML_API
|
||||
toml::string default_formatter_make_key_segment(const toml::string& str) noexcept;
|
||||
|
||||
[[nodiscard]] TOML_API
|
||||
size_t default_formatter_inline_columns(const node& node) noexcept;
|
||||
|
||||
[[nodiscard]] TOML_API
|
||||
bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias = 0) noexcept;
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename T, typename U>
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&);
|
||||
template <typename T, typename U>
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&);
|
||||
|
||||
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
|
||||
///
|
||||
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
|
||||
/// operators of the TOML node types already print themselves out using this formatter.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "description", "This is some TOML, yo." },
|
||||
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
|
||||
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
|
||||
/// { "table", toml::table{{ { "foo", "bar" } }} }
|
||||
/// }};
|
||||
///
|
||||
/// // these two lines are equivalent:
|
||||
/// std::cout << toml::default_formatter{ tbl } << std::endl;
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// description = "This is some TOML, yo."
|
||||
/// fruit = ["apple", "orange", "pear"]
|
||||
/// numbers = [1, 2, 3, 4, 5]
|
||||
///
|
||||
/// [table]
|
||||
/// foo = "bar"
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The underlying character type of the output stream. Must be 1 byte in size.
|
||||
template <typename Char = char>
|
||||
class TOML_API default_formatter final : impl::formatter<Char>
|
||||
{
|
||||
private:
|
||||
using base = impl::formatter<Char>;
|
||||
std::vector<toml::string> key_path;
|
||||
|
||||
void print_key_segment(const toml::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
impl::print_to_stream("''"sv, base::stream());
|
||||
else
|
||||
{
|
||||
bool requiresQuotes = false;
|
||||
{
|
||||
impl::utf8_decoder decoder;
|
||||
for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
|
||||
{
|
||||
decoder(static_cast<uint8_t>(str[i]));
|
||||
if (decoder.error())
|
||||
requiresQuotes = true;
|
||||
else if (decoder.has_code_point())
|
||||
requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresQuotes)
|
||||
base::print_quoted_string(str);
|
||||
else
|
||||
impl::print_to_stream(str, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print_key_path()
|
||||
{
|
||||
for (const auto& segment : key_path)
|
||||
{
|
||||
if (std::addressof(segment) > key_path.data())
|
||||
impl::print_to_stream('.', base::stream());
|
||||
impl::print_to_stream(segment, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print_inline(const table& /*tbl*/);
|
||||
|
||||
void print(const array& arr)
|
||||
{
|
||||
if (arr.empty())
|
||||
impl::print_to_stream("[]"sv, base::stream());
|
||||
else
|
||||
{
|
||||
const auto original_indent = base::indent();
|
||||
const auto multiline = impl::default_formatter_forces_multiline(
|
||||
arr,
|
||||
base::indent_columns * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)
|
||||
);
|
||||
impl::print_to_stream("["sv, base::stream());
|
||||
if (multiline)
|
||||
{
|
||||
if (original_indent < 0)
|
||||
base::indent(0);
|
||||
base::increase_indent();
|
||||
}
|
||||
else
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++)
|
||||
{
|
||||
if (i > 0_sz)
|
||||
{
|
||||
impl::print_to_stream(',', base::stream());
|
||||
if (!multiline)
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
}
|
||||
|
||||
if (multiline)
|
||||
{
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
}
|
||||
|
||||
auto& v = arr[i];
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
|
||||
}
|
||||
if (multiline)
|
||||
{
|
||||
base::indent(original_indent);
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
}
|
||||
else
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
impl::print_to_stream("]"sv, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print(const table& tbl)
|
||||
{
|
||||
static constexpr auto is_non_inline_array_of_tables = [](auto&& nde) noexcept
|
||||
{
|
||||
auto arr = nde.as_array();
|
||||
return arr
|
||||
&& arr->is_array_of_tables()
|
||||
&& !arr->template get_as<table>(0_sz)->is_inline();
|
||||
};
|
||||
|
||||
//values, arrays, and inline tables/table arrays
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
const auto type = v.type();
|
||||
if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
|
||||
|| (type == node_type::array && is_non_inline_array_of_tables(v)))
|
||||
continue;
|
||||
|
||||
base::print_newline();
|
||||
base::print_indent();
|
||||
print_key_segment(k);
|
||||
impl::print_to_stream(" = "sv, base::stream());
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
|
||||
//non-inline tables
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
const auto type = v.type();
|
||||
if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
|
||||
continue;
|
||||
auto& child_tbl = *reinterpret_cast<const table*>(&v);
|
||||
|
||||
//we can skip indenting and emitting the headers for tables that only contain other tables
|
||||
//(so we don't over-nest)
|
||||
size_t child_value_count{}; //includes inline tables and non-table arrays
|
||||
size_t child_table_count{};
|
||||
size_t child_table_array_count{};
|
||||
for (auto&& [child_k, child_v] : child_tbl)
|
||||
{
|
||||
(void)child_k;
|
||||
const auto child_type = child_v.type();
|
||||
TOML_ASSUME(child_type != node_type::none);
|
||||
switch (child_type)
|
||||
{
|
||||
case node_type::table:
|
||||
if (reinterpret_cast<const table*>(&child_v)->is_inline())
|
||||
child_value_count++;
|
||||
else
|
||||
child_table_count++;
|
||||
break;
|
||||
|
||||
case node_type::array:
|
||||
if (is_non_inline_array_of_tables(child_v))
|
||||
child_table_array_count++;
|
||||
else
|
||||
child_value_count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
child_value_count++;
|
||||
}
|
||||
}
|
||||
bool skip_self = false;
|
||||
if (child_value_count == 0_sz && (child_table_count > 0_sz || child_table_array_count > 0_sz))
|
||||
skip_self = true;
|
||||
|
||||
if (!skip_self)
|
||||
base::increase_indent();
|
||||
key_path.push_back(impl::default_formatter_make_key_segment(k));
|
||||
|
||||
if (!skip_self)
|
||||
{
|
||||
base::print_newline();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream("["sv, base::stream());
|
||||
print_key_path();
|
||||
impl::print_to_stream("]"sv, base::stream());
|
||||
base::print_newline(true);
|
||||
}
|
||||
|
||||
print(child_tbl);
|
||||
|
||||
key_path.pop_back();
|
||||
if (!skip_self)
|
||||
base::decrease_indent();
|
||||
}
|
||||
|
||||
//table arrays
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
if (!is_non_inline_array_of_tables(v))
|
||||
continue;
|
||||
auto& arr = *reinterpret_cast<const array*>(&v);
|
||||
|
||||
base::increase_indent();
|
||||
key_path.push_back(impl::default_formatter_make_key_segment(k));
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++)
|
||||
{
|
||||
base::print_newline();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream("[["sv, base::stream());
|
||||
print_key_path();
|
||||
impl::print_to_stream("]]"sv, base::stream());
|
||||
base::print_newline(true);
|
||||
print(*reinterpret_cast<const table*>(&arr[i]));
|
||||
}
|
||||
|
||||
key_path.pop_back();
|
||||
base::decrease_indent();
|
||||
}
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
switch (auto source_type = base::source().type())
|
||||
{
|
||||
case node_type::table:
|
||||
{
|
||||
auto& tbl = *reinterpret_cast<const table*>(&base::source());
|
||||
if (tbl.is_inline())
|
||||
print_inline(tbl);
|
||||
else
|
||||
{
|
||||
base::decrease_indent(); // so root kvps and tables have the same indent
|
||||
print(tbl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array*>(&base::source()));
|
||||
break;
|
||||
|
||||
default:
|
||||
base::print_value(base::source(), source_type);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructs a default formatter and binds it to a TOML object.
|
||||
///
|
||||
/// \param source The source TOML object.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit default_formatter(const toml::node& source, format_flags flags = {}) noexcept
|
||||
: base{ source, flags }
|
||||
{}
|
||||
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&);
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&);
|
||||
};
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template class TOML_API default_formatter<char>;
|
||||
#endif
|
||||
|
||||
default_formatter(const table&) -> default_formatter<char>;
|
||||
default_formatter(const array&) -> default_formatter<char>;
|
||||
template <typename T> default_formatter(const value<T>&) -> default_formatter<char>;
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
|
||||
template <typename T, typename U>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>& rhs)
|
||||
{
|
||||
rhs.attach(lhs);
|
||||
rhs.key_path.clear();
|
||||
rhs.print();
|
||||
rhs.detach();
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
|
||||
template <typename T, typename U>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>&& rhs)
|
||||
{
|
||||
return lhs << rhs; //as lvalue
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const table& rhs)
|
||||
{
|
||||
return lhs << default_formatter<Char>{ rhs };
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const array& rhs)
|
||||
{
|
||||
return lhs << default_formatter<Char>{ rhs };
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const table&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const array&);
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,208 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_default_formatter.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
TOML_DISABLE_FLOAT_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
inline constexpr size_t default_formatter_line_wrap = 120_sz;
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
string default_formatter_make_key_segment(const string& str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return TOML_STRING_PREFIX("''"s);
|
||||
else
|
||||
{
|
||||
bool requiresQuotes = false;
|
||||
{
|
||||
utf8_decoder decoder;
|
||||
for (size_t i = 0; i < str.length() && !requiresQuotes; i++)
|
||||
{
|
||||
decoder(static_cast<uint8_t>(str[i]));
|
||||
if (decoder.error())
|
||||
requiresQuotes = true;
|
||||
else if (decoder.has_code_point())
|
||||
requiresQuotes = !is_bare_key_character(decoder.codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresQuotes)
|
||||
{
|
||||
string s;
|
||||
s.reserve(str.length() + 2_sz);
|
||||
s += TOML_STRING_PREFIX('"');
|
||||
for (auto c : str)
|
||||
{
|
||||
if TOML_UNLIKELY(c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F'))
|
||||
{
|
||||
const auto& sv = low_character_escape_table[c];
|
||||
s.append(reinterpret_cast<const string_char*>(sv.data()), sv.length());
|
||||
}
|
||||
else if TOML_UNLIKELY(c == TOML_STRING_PREFIX('\x7F'))
|
||||
s.append(TOML_STRING_PREFIX("\\u007F"sv));
|
||||
else if TOML_UNLIKELY(c == TOML_STRING_PREFIX('"'))
|
||||
s.append(TOML_STRING_PREFIX("\\\""sv));
|
||||
else
|
||||
s += c;
|
||||
}
|
||||
s += TOML_STRING_PREFIX('"');
|
||||
return s;
|
||||
}
|
||||
else
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
size_t default_formatter_inline_columns(const node& node) noexcept
|
||||
{
|
||||
switch (node.type())
|
||||
{
|
||||
case node_type::table:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const table*>(&node);
|
||||
if (n.empty())
|
||||
return 2_sz; // "{}"
|
||||
size_t weight = 3_sz; // "{ }"
|
||||
for (auto&& [k, v] : n)
|
||||
{
|
||||
weight += k.length() + default_formatter_inline_columns(v) + 2_sz; // + ", "
|
||||
if (weight >= default_formatter_line_wrap)
|
||||
break;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
case node_type::array:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const array*>(&node);
|
||||
if (n.empty())
|
||||
return 2_sz; // "[]"
|
||||
size_t weight = 3_sz; // "[ ]"
|
||||
for (auto& elem : n)
|
||||
{
|
||||
weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
|
||||
if (weight >= default_formatter_line_wrap)
|
||||
break;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
case node_type::string:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<string>*>(&node);
|
||||
return n.get().length() + 2_sz; // + ""
|
||||
}
|
||||
|
||||
case node_type::integer:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<int64_t>*>(&node);
|
||||
auto v = n.get();
|
||||
if (!v)
|
||||
return 1_sz;
|
||||
size_t weight = {};
|
||||
if (v < 0)
|
||||
{
|
||||
weight += 1;
|
||||
v *= -1;
|
||||
}
|
||||
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
|
||||
}
|
||||
|
||||
case node_type::floating_point:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<double>*>(&node);
|
||||
auto v = n.get();
|
||||
if (v == 0.0)
|
||||
return 3_sz; // "0.0"
|
||||
size_t weight = 2_sz; // ".0"
|
||||
if (v < 0.0)
|
||||
{
|
||||
weight += 1;
|
||||
v *= -1.0;
|
||||
}
|
||||
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
|
||||
break;
|
||||
}
|
||||
|
||||
case node_type::boolean: return 5_sz;
|
||||
case node_type::date: [[fallthrough]];
|
||||
case node_type::time: return 10_sz;
|
||||
case node_type::date_time: return 30_sz;
|
||||
case node_type::none: TOML_UNREACHABLE;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias) noexcept
|
||||
{
|
||||
return (default_formatter_inline_columns(node) + starting_column_bias) > default_formatter_line_wrap;
|
||||
}
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void default_formatter<Char>::print_inline(const toml::table& tbl)
|
||||
{
|
||||
if (tbl.empty())
|
||||
impl::print_to_stream("{}"sv, base::stream());
|
||||
else
|
||||
{
|
||||
impl::print_to_stream("{ "sv, base::stream());
|
||||
|
||||
bool first = false;
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
if (first)
|
||||
impl::print_to_stream(", "sv, base::stream());
|
||||
first = true;
|
||||
|
||||
print_key_segment(k);
|
||||
impl::print_to_stream(" = "sv, base::stream());
|
||||
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
|
||||
impl::print_to_stream(" }"sv, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_FLOAT_WARNINGS
|
|
@ -0,0 +1,169 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_print_to_stream.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief Format flags for modifying how TOML data is printed to streams.
|
||||
enum class format_flags : uint8_t
|
||||
{
|
||||
none,
|
||||
quote_dates_and_times = 1
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
|
||||
{
|
||||
return static_cast<format_flags>(impl::unbox_enum(lhs) & impl::unbox_enum(rhs));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
|
||||
{
|
||||
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
|
||||
}
|
||||
}
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename Char = char>
|
||||
class TOML_API formatter
|
||||
{
|
||||
private:
|
||||
const toml::node* source_;
|
||||
std::basic_ostream<Char>* stream_ = nullptr;
|
||||
format_flags flags_;
|
||||
int8_t indent_;
|
||||
bool naked_newline_;
|
||||
|
||||
protected:
|
||||
|
||||
[[nodiscard]] const toml::node& source() const noexcept { return *source_; }
|
||||
[[nodiscard]] format_flags flags() const noexcept { return flags_; }
|
||||
[[nodiscard]] std::basic_ostream<Char>& stream() const noexcept { return *stream_; }
|
||||
|
||||
static constexpr size_t indent_columns = 4;
|
||||
static constexpr toml::string_view indent_string = TOML_STRING_PREFIX(" "sv);
|
||||
[[nodiscard]] int8_t indent() const noexcept { return indent_; }
|
||||
void indent(int8_t level) noexcept { indent_ = level; }
|
||||
void increase_indent() noexcept { indent_++; }
|
||||
void decrease_indent() noexcept { indent_--; }
|
||||
|
||||
TOML_ALWAYS_INLINE
|
||||
void clear_naked_newline() noexcept { naked_newline_ = false; }
|
||||
|
||||
void attach(std::basic_ostream<Char>& stream) noexcept
|
||||
{
|
||||
indent_ = {};
|
||||
naked_newline_ = true;
|
||||
stream_ = &stream;
|
||||
}
|
||||
|
||||
void detach() noexcept
|
||||
{
|
||||
stream_ = nullptr;
|
||||
}
|
||||
|
||||
void print_newline(bool force = false)
|
||||
{
|
||||
if (!naked_newline_ || force)
|
||||
{
|
||||
print_to_stream('\n', *stream_);
|
||||
naked_newline_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void print_indent()
|
||||
{
|
||||
for (int8_t i = 0; i < indent_; i++)
|
||||
{
|
||||
print_to_stream(indent_string, *stream_);
|
||||
naked_newline_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void print_quoted_string(toml::string_view str)
|
||||
{
|
||||
if (str.empty())
|
||||
print_to_stream("\"\""sv, *stream_);
|
||||
else
|
||||
{
|
||||
print_to_stream('"', *stream_);
|
||||
print_to_stream_with_escapes(str, *stream_);
|
||||
print_to_stream('"', *stream_);
|
||||
}
|
||||
naked_newline_ = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void print(const value<T>& val)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, string>)
|
||||
{
|
||||
print_quoted_string(val.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr auto is_dt =
|
||||
std::is_same_v<T, date>
|
||||
|| std::is_same_v<T, time>
|
||||
|| std::is_same_v<T, date_time>;
|
||||
|
||||
if constexpr (is_dt)
|
||||
{
|
||||
if ((flags_ & format_flags::quote_dates_and_times) != format_flags::none)
|
||||
print_to_stream('"', *stream_);
|
||||
}
|
||||
|
||||
*stream_ << val;
|
||||
|
||||
if constexpr (is_dt)
|
||||
{
|
||||
if ((flags_ & format_flags::quote_dates_and_times) != format_flags::none)
|
||||
print_to_stream('"', *stream_);
|
||||
}
|
||||
|
||||
naked_newline_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void print_value(const node& val_node, node_type type)
|
||||
{
|
||||
TOML_ASSUME(type > node_type::array);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::string: print(*reinterpret_cast<const value<string>*>(&val_node)); break;
|
||||
case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
|
||||
case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
|
||||
case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
|
||||
case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
|
||||
case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
|
||||
case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
formatter(const toml::node& source, format_flags flags) noexcept
|
||||
: source_{ &source },
|
||||
flags_{ flags }
|
||||
{}
|
||||
};
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template class TOML_API formatter<char>;
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,102 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
#if TOML_ALL_INLINE
|
||||
#error This header cannot not be included when TOML_ALL_INLINE is enabled.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
TOML_POP_WARNINGS
|
||||
#include "toml_node_view.h"
|
||||
#include "toml_default_formatter.h"
|
||||
#include "toml_json_formatter.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
// value<>
|
||||
template class TOML_API value<string>;
|
||||
template class TOML_API value<int64_t>;
|
||||
template class TOML_API value<double>;
|
||||
template class TOML_API value<bool>;
|
||||
template class TOML_API value<date>;
|
||||
template class TOML_API value<time>;
|
||||
template class TOML_API value<date_time>;
|
||||
|
||||
// node_view
|
||||
template class TOML_API node_view<node>;
|
||||
template class TOML_API node_view<const node>;
|
||||
|
||||
// formatters
|
||||
namespace impl
|
||||
{
|
||||
template class TOML_API formatter<char>;
|
||||
}
|
||||
template class TOML_API default_formatter<char>;
|
||||
template class TOML_API json_formatter<char>;
|
||||
|
||||
// various ostream operators
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const date&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const time&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const date_time&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::string>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const table&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const array&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const node_view<node>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const node_view<const node>&);
|
||||
template TOML_API std::ostream& operator << (std::ostream&, node_type);
|
||||
|
||||
// print_to_stream() machinery
|
||||
namespace impl
|
||||
{
|
||||
template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
|
||||
template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
|
||||
}
|
||||
|
||||
// parser machinery
|
||||
#if TOML_PARSER
|
||||
|
||||
// parse error ostream
|
||||
template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
|
||||
|
||||
// parse() and parse_file()
|
||||
#if TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_START(parse_ex)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(parse_noex)
|
||||
#endif
|
||||
template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
|
||||
template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
|
||||
template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
|
||||
#ifdef __cpp_lib_char8_t
|
||||
template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
|
||||
#endif
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
|
||||
#endif // TOML_PARSER
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_formatter.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename T, typename U>
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&);
|
||||
template <typename T, typename U>
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&);
|
||||
|
||||
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto some_toml = toml::parse(R"(
|
||||
/// [fruit]
|
||||
/// apple.color = "red"
|
||||
/// apple.taste.sweet = true
|
||||
///
|
||||
/// [fruit.apple.texture]
|
||||
/// smooth = true
|
||||
/// )"sv);
|
||||
/// std::cout << toml::json_formatter{ some_toml } << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// {
|
||||
/// "fruit" : {
|
||||
/// "apple" : {
|
||||
/// "color" : "red",
|
||||
/// "taste" : {
|
||||
/// "sweet" : true
|
||||
/// },
|
||||
/// "texture" : {
|
||||
/// "smooth" : true
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The underlying character type of the output stream. Must be 1 byte in size.
|
||||
template <typename Char = char>
|
||||
class TOML_API json_formatter final : impl::formatter<Char>
|
||||
{
|
||||
private:
|
||||
using base = impl::formatter<Char>;
|
||||
|
||||
void print(const toml::table& tbl);
|
||||
|
||||
void print(const array& arr)
|
||||
{
|
||||
if (arr.empty())
|
||||
impl::print_to_stream("[]"sv, base::stream());
|
||||
else
|
||||
{
|
||||
impl::print_to_stream('[', base::stream());
|
||||
base::increase_indent();
|
||||
for (size_t i = 0; i < arr.size(); i++)
|
||||
{
|
||||
if (i > 0_sz)
|
||||
impl::print_to_stream(',', base::stream());
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
|
||||
auto& v = arr[i];
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
|
||||
}
|
||||
base::decrease_indent();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream(']', base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
switch (auto source_type = base::source().type())
|
||||
{
|
||||
case node_type::table: print(*reinterpret_cast<const table*>(&base::source())); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&base::source())); break;
|
||||
default: base::print_value(base::source(), source_type);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructs a JSON formatter and binds it to a TOML object.
|
||||
///
|
||||
/// \param source The source TOML object.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit json_formatter(const toml::node& source, format_flags flags = {}) noexcept
|
||||
: base{ source, flags | format_flags::quote_dates_and_times }
|
||||
{}
|
||||
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&);
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&);
|
||||
};
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template class TOML_API json_formatter<char>;
|
||||
#endif
|
||||
|
||||
json_formatter(const table&) -> json_formatter<char>;
|
||||
json_formatter(const array&) -> json_formatter<char>;
|
||||
template <typename T> json_formatter(const value<T>&) -> json_formatter<char>;
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as JSON.
|
||||
template <typename T, typename U>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>& rhs)
|
||||
{
|
||||
rhs.attach(lhs);
|
||||
rhs.print();
|
||||
rhs.detach();
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
|
||||
template <typename T, typename U>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>&& rhs)
|
||||
{
|
||||
return lhs << rhs; //as lvalue
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, json_formatter<char>&&);
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,63 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_json_formatter.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SWITCH_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void json_formatter<Char>::print(const toml::table& tbl)
|
||||
{
|
||||
if (tbl.empty())
|
||||
impl::print_to_stream("{}"sv, base::stream());
|
||||
else
|
||||
{
|
||||
impl::print_to_stream('{', base::stream());
|
||||
base::increase_indent();
|
||||
bool first = false;
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
if (first)
|
||||
impl::print_to_stream(", "sv, base::stream());
|
||||
first = true;
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
|
||||
base::print_quoted_string(k);
|
||||
impl::print_to_stream(" : "sv, base::stream());
|
||||
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
|
||||
}
|
||||
base::decrease_indent();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream('}', base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
|
|
@ -0,0 +1,535 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief A TOML node.
|
||||
///
|
||||
/// \detail A parsed TOML document forms a tree made up of tables, arrays and values.
|
||||
/// This type is the base of each of those, providing a lot of the polymorphic plumbing.
|
||||
class TOML_INTERFACE TOML_API node
|
||||
{
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
source_region source_{};
|
||||
|
||||
protected:
|
||||
|
||||
node(node&& other) noexcept;
|
||||
node& operator= (node&& rhs) noexcept;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>& ref_cast() & noexcept
|
||||
{
|
||||
return *reinterpret_cast<impl::node_of<T>*>(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>&& ref_cast() && noexcept
|
||||
{
|
||||
return std::move(*reinterpret_cast<impl::node_of<T>*>(this));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
const impl::node_of<T>& ref_cast() const & noexcept
|
||||
{
|
||||
return *reinterpret_cast<const impl::node_of<T>*>(this);
|
||||
}
|
||||
|
||||
template <typename N, typename T>
|
||||
using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
|
||||
|
||||
node() noexcept = default;
|
||||
node(const node&) = delete;
|
||||
node& operator= (const node&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~node() noexcept = default;
|
||||
|
||||
/// \brief Returns the node's type identifier.
|
||||
[[nodiscard]] virtual node_type type() const noexcept = 0;
|
||||
|
||||
/// \brief Returns true if this node is a table.
|
||||
[[nodiscard]] virtual bool is_table() const noexcept = 0;
|
||||
/// \brief Returns true if this node is an array.
|
||||
[[nodiscard]] virtual bool is_array() const noexcept = 0;
|
||||
/// \brief Returns true if this node is a value.
|
||||
[[nodiscard]] virtual bool is_value() const noexcept = 0;
|
||||
|
||||
/// \brief Returns true if this node is a string value.
|
||||
[[nodiscard]] virtual bool is_string() const noexcept;
|
||||
/// \brief Returns true if this node is an integer value.
|
||||
[[nodiscard]] virtual bool is_integer() const noexcept;
|
||||
/// \brief Returns true if this node is an floating-point value.
|
||||
[[nodiscard]] virtual bool is_floating_point() const noexcept;
|
||||
/// \brief Returns true if this node is an integer or floating-point value.
|
||||
[[nodiscard]] virtual bool is_number() const noexcept;
|
||||
/// \brief Returns true if this node is a boolean value.
|
||||
[[nodiscard]] virtual bool is_boolean() const noexcept;
|
||||
/// \brief Returns true if this node is a local date value.
|
||||
[[nodiscard]] virtual bool is_date() const noexcept;
|
||||
/// \brief Returns true if this node is a local time value.
|
||||
[[nodiscard]] virtual bool is_time() const noexcept;
|
||||
/// \brief Returns true if this node is a date-time value.
|
||||
[[nodiscard]] virtual bool is_date_time() const noexcept;
|
||||
/// \brief Returns true if this node is an array containing only tables.
|
||||
[[nodiscard]] virtual bool is_array_of_tables() const noexcept;
|
||||
|
||||
/// \brief Checks if a node is a specific type.
|
||||
///
|
||||
/// \tparam T A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if this node is an instance of the specified type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool is() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<impl::remove_cvref_t<T>>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return is_table();
|
||||
else if constexpr (std::is_same_v<type, array>) return is_array();
|
||||
else if constexpr (std::is_same_v<type, string>) return is_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>) return is_integer();
|
||||
else if constexpr (std::is_same_v<type, double>) return is_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>) return is_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>) return is_date();
|
||||
else if constexpr (std::is_same_v<type, time>) return is_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>) return is_date_time();
|
||||
}
|
||||
|
||||
/// \brief Returns a pointer to the node as a toml::table, if it is one.
|
||||
[[nodiscard]] virtual table* as_table() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::array, if it is one.
|
||||
[[nodiscard]] virtual array* as_array() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<string>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<string>* as_string() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<int64_t>* as_integer() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<double>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<double>* as_floating_point() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<bool>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<bool>* as_boolean() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<date>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<date>* as_date() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<time>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<time>* as_time() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<date_time>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<date_time>* as_date_time() noexcept;
|
||||
|
||||
[[nodiscard]] virtual const table* as_table() const noexcept;
|
||||
[[nodiscard]] virtual const array* as_array() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<string>* as_string() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<int64_t>* as_integer() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<double>* as_floating_point() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<bool>* as_boolean() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<date>* as_date() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<time>* as_time() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<date_time>* as_date_time() const noexcept;
|
||||
|
||||
/// \brief Gets the raw value contained by this node.
|
||||
///
|
||||
/// \detail The optional returned by this function will only contain a value if the node was an instance of
|
||||
/// toml::value with the same value type as the template argument. Additionally, some type are allowed to
|
||||
/// convert to each other, for instance asking for an integer when the value exists as a double,
|
||||
/// or requesting a string value as a string_view: \cpp
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// int_val = 10
|
||||
/// float_val = 25.6
|
||||
/// string_val = "kek"
|
||||
/// )"sv);
|
||||
///
|
||||
/// if (auto val = tbl.get("int_val"sv)->value<int64_t>())
|
||||
/// std::cout << "'int_val' as int64_t: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("int_val"sv)->value<double>())
|
||||
/// std::cout << "'int_val' as double: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("float_val"sv)->value<int64_t>())
|
||||
/// std::cout << "'float_val' as int64_t: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("float_val"sv)->value<double>())
|
||||
/// std::cout << "'float_val' as double: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("string_val"sv)->value<std::string>())
|
||||
/// std::cout << "'string_val' as std::string: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("string_val"sv)->value<std::string_view>())
|
||||
/// std::cout << "'string_val' as std::string_view: "sv << *val << std::endl;
|
||||
///
|
||||
/// if (auto val = tbl.get("string_val"sv)->value<int64_t>())
|
||||
/// std::cout << "this line won't be printed because string_val wasn't an int."sv << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 'int_val' as int64_t: 10
|
||||
/// 'int_val' as double: 10
|
||||
/// 'float_val' as int64_t: 25
|
||||
/// 'float_val' as double: 25.6
|
||||
/// 'string_val' as std::string: kek
|
||||
/// 'string_val' as std::string_view: kek
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam T One of the TOML value types. Can also be a string_view.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching type (or convertible to it), or an empty optional.
|
||||
template <typename T>
|
||||
[[nodiscard]] optional<T> value() const noexcept;
|
||||
|
||||
/// \brief Gets the raw value contained by this node, or a default.
|
||||
///
|
||||
/// \tparam T Default value type. Must be (or be promotable to) one of the TOML value types.
|
||||
/// \param default_value The default value to return if the node wasn't a value, wasn't the
|
||||
/// correct type, or no conversion was possible.
|
||||
///
|
||||
/// \returns The node's underlying value, or the default if the node wasn't a value, wasn't the
|
||||
/// correct type, or no conversion was possible.
|
||||
///
|
||||
/// \see node::value()
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(T&& default_value) const noexcept;
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type.
|
||||
///
|
||||
/// \details \cpp
|
||||
///
|
||||
/// toml::value<int64_t>* int_value = node->as<int64_t>();
|
||||
/// toml::table* tbl = node->as<toml::table>();
|
||||
/// if (int_value)
|
||||
/// std::cout << "Node is a value<int64_t>" << std::endl;
|
||||
/// else if (tbl)
|
||||
/// std::cout << "Node is a table" << std::endl;
|
||||
///
|
||||
/// // fully-qualified value node types also work (useful for template code):
|
||||
/// toml::value<int64_t>* int_value2 = node->as<toml::value<int64_t>>();
|
||||
/// if (int_value2)
|
||||
/// std::cout << "Node is a value<int64_t>" << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam T The node type or TOML value type to cast to.
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
impl::node_of<T>* as() noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return as_table();
|
||||
else if constexpr (std::is_same_v<type, array>) return as_array();
|
||||
else if constexpr (std::is_same_v<type, string>) return as_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
|
||||
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>) return as_date();
|
||||
else if constexpr (std::is_same_v<type, time>) return as_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
|
||||
}
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type (const overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
const impl::node_of<T>* as() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>) return as_table();
|
||||
else if constexpr (std::is_same_v<type, array>) return as_array();
|
||||
else if constexpr (std::is_same_v<type, string>) return as_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
|
||||
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>) return as_date();
|
||||
else if constexpr (std::is_same_v<type, time>) return as_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
|
||||
}
|
||||
|
||||
/// \brief Returns the source region responsible for generating this node during parsing.
|
||||
[[nodiscard]] const source_region& source() const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
template <typename Func, typename N, typename T>
|
||||
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool can_visit_any =
|
||||
can_visit<Func, N, table>
|
||||
|| can_visit<Func, N, array>
|
||||
|| can_visit<Func, N, string>
|
||||
|| can_visit<Func, N, int64_t>
|
||||
|| can_visit<Func, N, double>
|
||||
|| can_visit<Func, N, bool>
|
||||
|| can_visit<Func, N, date>
|
||||
|| can_visit<Func, N, time>
|
||||
|| can_visit<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool can_visit_all =
|
||||
can_visit<Func, N, table>
|
||||
&& can_visit<Func, N, array>
|
||||
&& can_visit<Func, N, string>
|
||||
&& can_visit<Func, N, int64_t>
|
||||
&& can_visit<Func, N, double>
|
||||
&& can_visit<Func, N, bool>
|
||||
&& can_visit<Func, N, date>
|
||||
&& can_visit<Func, N, time>
|
||||
&& can_visit<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N, typename T>
|
||||
static constexpr bool visit_is_nothrow_one =
|
||||
!can_visit<Func, N, T>
|
||||
|| std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool visit_is_nothrow =
|
||||
visit_is_nothrow_one<Func, N, table>
|
||||
&& visit_is_nothrow_one<Func, N, array>
|
||||
&& visit_is_nothrow_one<Func, N, string>
|
||||
&& visit_is_nothrow_one<Func, N, int64_t>
|
||||
&& visit_is_nothrow_one<Func, N, double>
|
||||
&& visit_is_nothrow_one<Func, N, bool>
|
||||
&& visit_is_nothrow_one<Func, N, date>
|
||||
&& visit_is_nothrow_one<Func, N, time>
|
||||
&& visit_is_nothrow_one<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
|
||||
struct visit_return_type final
|
||||
{
|
||||
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
|
||||
};
|
||||
template <typename Func, typename N, typename T>
|
||||
struct visit_return_type<Func, N, T, false> final
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
|
||||
|
||||
//# these functions are static helpers to preserve const and ref categories
|
||||
//# (otherwise I'd have to implement them thrice)
|
||||
//# ((propagation in C++: a modern horror story))
|
||||
|
||||
template <typename N, typename Func>
|
||||
static decltype(auto) do_visit(N&& n, Func&& visitor)
|
||||
noexcept(visit_is_nothrow<Func&&, N&&>)
|
||||
{
|
||||
static_assert(
|
||||
can_visit_any<Func&&, N&&>,
|
||||
"Visitors must be invocable for at least one of the toml::node specializations"
|
||||
);
|
||||
|
||||
switch (n.type())
|
||||
{
|
||||
case node_type::table:
|
||||
if constexpr (can_visit<Func&&, N&&, table>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<table>());
|
||||
break;
|
||||
|
||||
case node_type::array:
|
||||
if constexpr (can_visit<Func&&, N&&, array>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<array>());
|
||||
break;
|
||||
|
||||
case node_type::string:
|
||||
if constexpr (can_visit<Func&&, N&&, string>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<string>());
|
||||
break;
|
||||
|
||||
case node_type::integer:
|
||||
if constexpr (can_visit<Func&&, N&&, int64_t>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<int64_t>());
|
||||
break;
|
||||
|
||||
case node_type::floating_point:
|
||||
if constexpr (can_visit<Func&&, N&&, double>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<double>());
|
||||
break;
|
||||
|
||||
case node_type::boolean:
|
||||
if constexpr (can_visit<Func&&, N&&, bool>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<bool>());
|
||||
break;
|
||||
|
||||
case node_type::date:
|
||||
if constexpr (can_visit<Func&&, N&&, date>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date>());
|
||||
break;
|
||||
|
||||
case node_type::time:
|
||||
if constexpr (can_visit<Func&&, N&&, time>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<time>());
|
||||
break;
|
||||
|
||||
case node_type::date_time:
|
||||
if constexpr (can_visit<Func&&, N&&, date_time>)
|
||||
return std::forward<Func>(visitor)(std::forward<N>(n).template ref_cast<date_time>());
|
||||
break;
|
||||
|
||||
case node_type::none: TOML_UNREACHABLE;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
if constexpr (can_visit_all<Func&&, N&&>)
|
||||
TOML_UNREACHABLE;
|
||||
else
|
||||
{
|
||||
using return_type =
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, table>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, array>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, string>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, int64_t>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, double>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, bool>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, date>::type,
|
||||
nonvoid<typename visit_return_type<Func&&, N&&, time>::type,
|
||||
typename visit_return_type<Func&&, N&&, date_time>::type
|
||||
>>>>>>>>;
|
||||
|
||||
if constexpr (!std::is_void_v<return_type>)
|
||||
{
|
||||
static_assert(
|
||||
std::is_default_constructible_v<return_type>,
|
||||
"Non-exhaustive visitors must return a default-constructible type, or void"
|
||||
);
|
||||
return return_type{};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename N>
|
||||
[[nodiscard]] static decltype(auto) do_ref(N&& n) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<T>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
);
|
||||
TOML_ASSERT(
|
||||
n.template is<T>()
|
||||
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type"
|
||||
);
|
||||
if constexpr (impl::is_value<type>)
|
||||
return std::forward<N>(n).template ref_cast<type>().get();
|
||||
else
|
||||
return std::forward<N>(n).template ref_cast<type>();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type.
|
||||
///
|
||||
/// \details Visitation is useful when you expect
|
||||
/// a node to be one of a set number of types and need
|
||||
/// to handle these types differently. Using `visit()` allows
|
||||
/// you to eliminate some of the casting/conversion boilerplate: \cpp
|
||||
///
|
||||
/// node.visit([](auto&& n)
|
||||
/// {
|
||||
/// if constexpr (toml::is_string<decltype(n)>)
|
||||
/// do_something_with_a_string(*n)); //n is a toml::value<toml::string>
|
||||
/// else if constexpr (toml::is_integer<decltype(n)>)
|
||||
/// do_something_with_an_int(*n); //n is a toml::value<int64_t>
|
||||
/// else
|
||||
/// throw std::exception{ "Expected string or integer" };
|
||||
/// });
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam Func A callable type invocable with one or more of the
|
||||
/// toml++ node types.
|
||||
///
|
||||
/// \param visitor The visitor object.
|
||||
///
|
||||
/// \returns The return value of the visitor.
|
||||
/// Can be void. Non-exhaustive visitors must return a default-constructible type.
|
||||
///
|
||||
/// \see https://en.wikipedia.org/wiki/Visitor_pattern
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>)
|
||||
{
|
||||
return do_visit(*this, std::forward<Func>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload).
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>)
|
||||
{
|
||||
return do_visit(std::move(*this), std::forward<Func>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type (const lvalue overload).
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>)
|
||||
{
|
||||
return do_visit(*this, std::forward<Func>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data.
|
||||
///
|
||||
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
|
||||
/// chosen value type doesn't match the node's actual type. In debug builds an assertion
|
||||
/// will fire when invalid accesses are attempted: \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// min = 32
|
||||
/// max = 45
|
||||
/// )"sv);
|
||||
///
|
||||
/// int64_t& min_ref = tbl.get("min")->ref<int64_t>(); // matching type
|
||||
/// double& max_ref = tbl.get("max")->ref<double>(); // mismatched type, hits assert()
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam T One of the TOML value types.
|
||||
///
|
||||
/// \returns A reference to the underlying data.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::unwrapped<T>& ref() & noexcept
|
||||
{
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (rvalue overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::unwrapped<T>&& ref() && noexcept
|
||||
{
|
||||
return do_ref<T>(std::move(*this));
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (const lvalue overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::unwrapped<T>& ref() const& noexcept
|
||||
{
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS //TOML_DISABLE_VTABLE_WARNINGS
|
|
@ -0,0 +1,75 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_node.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SUGGEST_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node::node(node && other) noexcept
|
||||
: source_{ std::move(other.source_) }
|
||||
{
|
||||
other.source_.begin = {};
|
||||
other.source_.end = {};
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node & node::operator= (node && rhs) noexcept
|
||||
{
|
||||
source_ = std::move(rhs.source_);
|
||||
rhs.source_.begin = {};
|
||||
rhs.source_.end = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) bool node::is_string() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_integer() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_floating_point() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_number() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_boolean() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_date() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_time() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_date_time() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_array_of_tables() const noexcept { return false; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) table* node::as_table() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) array* node::as_array() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<string>* node::as_string() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<int64_t>* node::as_integer() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<double>* node::as_floating_point() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<bool>* node::as_boolean() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<date>* node::as_date() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<time>* node::as_time() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<date_time>* node::as_date_time() noexcept { return nullptr; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) const table* node::as_table() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const array* node::as_array() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<string>* node::as_string() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<int64_t>* node::as_integer() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<double>* node::as_floating_point() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<bool>* node::as_boolean() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<date>* node::as_date() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<time>* node::as_time() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<date_time>* node::as_date_time() const noexcept { return nullptr; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) const source_region& node::source() const noexcept { return source_; }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SUGGEST_WARNINGS
|
|
@ -0,0 +1,380 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_table.h"
|
||||
#include "toml_array.h"
|
||||
#include "toml_value.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_FLOAT_WARNINGS
|
||||
|
||||
template <typename Char, typename T>
|
||||
inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<T>&);
|
||||
|
||||
/// \brief A view of a node.
|
||||
///
|
||||
/// \detail A node_view is like a std::optional<toml::node> with lots of toml-specific stuff built-in.
|
||||
/// It _may_ represent a node, and allows you to do many of the same operations that you'd do
|
||||
/// on nodes directly, as well as easily traversing the node tree by creating
|
||||
/// subviews (via node_view::operator[]). \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
///
|
||||
/// title = "my hardware store"
|
||||
///
|
||||
/// [[products]]
|
||||
/// name = "Hammer"
|
||||
/// sku = 738594937
|
||||
/// keywords = [ "hammer", "construction", "build" ]
|
||||
///
|
||||
/// [[products]]
|
||||
/// name = "Nail"
|
||||
/// sku = 284758393
|
||||
/// color = "gray"
|
||||
///
|
||||
/// )"sv);
|
||||
///
|
||||
/// std::cout << tbl["title"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["name"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["keywords"] << std::endl;
|
||||
/// std::cout << tbl["products"][0]["keywords"][2] << std::endl;
|
||||
///
|
||||
/// tbl["products"][0]["keywords"].as_array()->push_back("heavy");
|
||||
/// std::cout << tbl["products"][0]["keywords"] << std::endl;
|
||||
/// std::cout << "has product[2]: "sv << !!tbl["products"][2] << std::endl;
|
||||
/// std::cout << "product[2]: "sv << tbl["products"][2] << std::endl;
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// "my hardware store"
|
||||
/// "Hammer"
|
||||
/// [ "hammer", "construction", "build" ]
|
||||
/// "build"
|
||||
/// [ "hammer", "construction", "build", "heavy" ]
|
||||
/// has product[2]: false
|
||||
/// product[2]:
|
||||
/// \eout
|
||||
template <typename T>
|
||||
class TOML_API TOML_TRIVIAL_ABI node_view
|
||||
{
|
||||
public:
|
||||
using viewed_type = T;
|
||||
|
||||
private:
|
||||
friend class toml::table;
|
||||
template <typename U> friend class toml::node_view;
|
||||
|
||||
mutable viewed_type* node_ = nullptr;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(viewed_type* node) noexcept
|
||||
: node_{ node }
|
||||
{}
|
||||
|
||||
template <typename Func>
|
||||
static constexpr bool visit_is_nothrow
|
||||
= noexcept(std::declval<viewed_type*>()->visit(std::declval<Func&&>()));
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructs an empty node view.
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view() noexcept = default;
|
||||
|
||||
/// \brief Returns true if the view references a node.
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
|
||||
/// \brief Returns the node that's being referenced by the view.
|
||||
[[nodiscard]] viewed_type* get() const noexcept { return node_; }
|
||||
|
||||
/// \brief Returns the type identifier for the viewed node.
|
||||
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
|
||||
|
||||
/// \brief Returns true if the viewed node is a toml::table.
|
||||
[[nodiscard]] bool is_table() const noexcept { return node_ && node_->is_table(); }
|
||||
/// \brief Returns true if the viewed node is a toml::array.
|
||||
[[nodiscard]] bool is_array() const noexcept { return node_ && node_->is_array(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<>.
|
||||
[[nodiscard]] bool is_value() const noexcept { return node_ && node_->is_value(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<string>.
|
||||
[[nodiscard]] bool is_string() const noexcept { return node_ && node_->is_string(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
|
||||
[[nodiscard]] bool is_integer() const noexcept { return node_ && node_->is_integer(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<double>.
|
||||
[[nodiscard]] bool is_floating_point() const noexcept { return node_ && node_->is_floating_point(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<int64_t> or toml::value<double>.
|
||||
[[nodiscard]] bool is_number() const noexcept { return node_ && node_->is_number(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<bool>.
|
||||
[[nodiscard]] bool is_boolean() const noexcept { return node_ && node_->is_boolean(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<date>.
|
||||
[[nodiscard]] bool is_date() const noexcept { return node_ && node_->is_date(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<time>.
|
||||
[[nodiscard]] bool is_time() const noexcept { return node_ && node_->is_time(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<date_time>.
|
||||
[[nodiscard]] bool is_date_time() const noexcept { return node_ && node_->is_date_time(); }
|
||||
/// \brief Returns true if the viewed node is a toml::array that contains only tables.
|
||||
[[nodiscard]] bool is_array_of_tables() const noexcept { return node_ && node_->is_array_of_tables(); }
|
||||
|
||||
/// \brief Checks if this view references a node of a specific type.
|
||||
///
|
||||
/// \tparam U A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if the viewed node is an instance of the specified type.
|
||||
///
|
||||
/// \see toml::node::is()
|
||||
template <typename U>
|
||||
[[nodiscard]]
|
||||
bool is() const noexcept
|
||||
{
|
||||
return node_ ? node_->template is<U>() : false;
|
||||
}
|
||||
|
||||
/// \brief Gets a pointer to the viewed node as a more specific node type.
|
||||
///
|
||||
/// \tparam U The node type or TOML value type to cast to.
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
|
||||
///
|
||||
/// \see toml::node::as()
|
||||
template <typename U>
|
||||
[[nodiscard]]
|
||||
auto as() const noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_node<impl::unwrapped<U>>,
|
||||
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
return node_ ? node_->template as<U>() : nullptr;
|
||||
}
|
||||
|
||||
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
|
||||
[[nodiscard]] auto as_table() const noexcept { return as<table>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
|
||||
[[nodiscard]] auto as_array() const noexcept { return as<array>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
|
||||
[[nodiscard]] auto as_string() const noexcept { return as<string>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
|
||||
[[nodiscard]] auto as_integer() const noexcept { return as<int64_t>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
|
||||
[[nodiscard]] auto as_floating_point() const noexcept { return as<double>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
|
||||
[[nodiscard]] auto as_boolean() const noexcept { return as<bool>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
|
||||
[[nodiscard]] auto as_date() const noexcept { return as<date>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
|
||||
[[nodiscard]] auto as_time() const noexcept { return as<time>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
|
||||
[[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_INIT_WARNINGS
|
||||
|
||||
/// \brief Gets the raw value contained by the referenced node.
|
||||
///
|
||||
/// \tparam U One of the TOML value types. Can also be a string_view.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching type (or convertible to it), or an empty optional.
|
||||
///
|
||||
/// \see node::value()
|
||||
template <typename U>
|
||||
[[nodiscard]] optional<U> value() const noexcept
|
||||
{
|
||||
if (node_)
|
||||
return node_->template value<U>();
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
/// \brief Gets the raw value contained by the referenced node, or a default.
|
||||
///
|
||||
/// \tparam U Default value type. Must be (or be promotable to) one of the TOML value types.
|
||||
/// \param default_value The default value to return if the view did not reference a node,
|
||||
/// or if the node wasn't a value, wasn't the correct type, or no conversion was possible.
|
||||
///
|
||||
/// \returns The node's underlying value, or the default if the node wasn't a value, wasn't the
|
||||
/// correct type, or no conversion was possible.
|
||||
///
|
||||
/// \see node::value_or()
|
||||
template <typename U>
|
||||
[[nodiscard]] auto value_or(U&& default_value) const noexcept
|
||||
{
|
||||
using return_type = decltype(node_->value_or(std::forward<U>(default_value)));
|
||||
if (node_)
|
||||
return node_->value_or(std::forward<U>(default_value));
|
||||
return return_type{ std::forward<U>(default_value) };
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the viewed node based on its concrete type.
|
||||
///
|
||||
/// \remarks Has no effect if the view does not reference a node.
|
||||
///
|
||||
/// \see node::visit()
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func&& visitor) const
|
||||
noexcept(visit_is_nothrow<Func&&>)
|
||||
{
|
||||
using return_type = decltype(node_->visit(std::forward<Func>(visitor)));
|
||||
if (node_)
|
||||
return node_->visit(std::forward<Func>(visitor));
|
||||
if constexpr (!std::is_void_v<return_type>)
|
||||
return return_type{};
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to the viewed node's underlying data.
|
||||
///
|
||||
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
|
||||
/// node_view didn't reference a node, or the chosen value type doesn't match the node's
|
||||
/// actual type. In debug builds an assertion will fire when invalid accesses are attempted: \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// min = 32
|
||||
/// max = 45
|
||||
/// )"sv);
|
||||
///
|
||||
/// int64_t& min_ref = tbl["min"].ref<int64_t>(); // matching type
|
||||
/// double& max_ref = tbl["max"].ref<double>(); // mismatched type, hits assert()
|
||||
/// int64_t& foo_ref = tbl["foo"].ref<int64_t>(); // nonexistent key, hits assert()
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam U One of the TOML value types.
|
||||
///
|
||||
/// \returns A reference to the underlying data.
|
||||
template <typename U>
|
||||
[[nodiscard]] decltype(auto) ref() const noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Template type parameter must be one of the TOML value types, a toml::table, or a toml::array"
|
||||
);
|
||||
TOML_ASSERT(
|
||||
node_
|
||||
&& "toml::node_view::ref() called on a node_view that did not reference a node"
|
||||
);
|
||||
return node_->template ref<type>();
|
||||
}
|
||||
|
||||
/// \brief Returns true if the viewed node is a table with the same contents as RHS.
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const table& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto tbl = lhs.as<table>();
|
||||
return tbl && *tbl == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, )
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as RHS.
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const array& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, )
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const toml::value<U>& rhs) noexcept
|
||||
{
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto val = lhs.as<U>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const U& rhs) noexcept
|
||||
{
|
||||
const auto val = lhs.as<impl::promoted<U>>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view&,
|
||||
const U&,
|
||||
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
|
||||
)
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::initializer_list<U>& rhs) noexcept
|
||||
{
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as the RHS vector.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const node_view& lhs, const std::vector<U>& rhs) noexcept
|
||||
{
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<U>&, template <typename U>)
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param key The key of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented a table and it contained a
|
||||
/// value at the given key, or an empty view.
|
||||
[[nodiscard]] node_view operator[] (string_view key) const noexcept
|
||||
{
|
||||
if (auto tbl = this->as_table())
|
||||
return { tbl->get(key) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param index The index of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented an array and it contained a
|
||||
/// value at the given index, or an empty view.
|
||||
[[nodiscard]] node_view operator[] (size_t index) const noexcept
|
||||
{
|
||||
if (auto arr = this->as_array())
|
||||
return { arr->get(index) };
|
||||
return { nullptr };
|
||||
}
|
||||
|
||||
template <typename Char, typename U>
|
||||
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const node_view<U>&);
|
||||
};
|
||||
|
||||
/// \brief Prints the viewed node out to a stream.
|
||||
template <typename Char, typename T>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& os, const node_view<T>& nv)
|
||||
{
|
||||
if (nv.node_)
|
||||
{
|
||||
nv.node_->visit([&os](const auto& n)
|
||||
{
|
||||
os << n;
|
||||
});
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template class TOML_API node_view<node>;
|
||||
extern template class TOML_API node_view<const node>;
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const node_view<node>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const node_view<const node>&);
|
||||
#endif
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_FLOAT_WARNINGS
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
#if TOML_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_INIT_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
#if TOML_LARGE_FILES
|
||||
TOML_ABI_NAMESPACE_START(lf)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(sf)
|
||||
#endif
|
||||
|
||||
#if TOML_DOXYGEN || !TOML_EXCEPTIONS
|
||||
|
||||
TOML_ABI_NAMESPACE_START(noex)
|
||||
|
||||
/// \brief An error generated when parsing fails.
|
||||
///
|
||||
/// \remarks This class inherits from std::runtime_error when exceptions are enabled.
|
||||
/// The public interface is the same regardless of exception mode.
|
||||
class parse_error final
|
||||
{
|
||||
private:
|
||||
std::string description_;
|
||||
source_region source_;
|
||||
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& desc, source_region&& src) noexcept
|
||||
: description_{ std::move(desc) },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& desc, const source_region& src) noexcept
|
||||
: parse_error{ std::move(desc), source_region{ src } }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ std::move(desc), source_region{ position, position, path } }
|
||||
{}
|
||||
|
||||
|
||||
/// \brief Returns a textual description of the error.
|
||||
/// \remark The backing string is guaranteed to be null-terminated.
|
||||
[[nodiscard]]
|
||||
std::string_view description() const noexcept
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
|
||||
/// \brief Returns the region of the source document responsible for the error.
|
||||
[[nodiscard]]
|
||||
const source_region& source() const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
TOML_ABI_NAMESPACE_START(ex)
|
||||
|
||||
class parse_error final
|
||||
: public std::runtime_error
|
||||
{
|
||||
private:
|
||||
source_region source_;
|
||||
|
||||
public:
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char* desc, source_region&& src) noexcept
|
||||
: std::runtime_error{ desc },
|
||||
source_{ std::move(src) }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char* desc, const source_region& src) noexcept
|
||||
: parse_error{ desc, source_region{ src } }
|
||||
{}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
|
||||
: parse_error{ desc, source_region{ position, position, path } }
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string_view description() const noexcept
|
||||
{
|
||||
return std::string_view{ what() };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const source_region& source() const noexcept
|
||||
{
|
||||
return source_;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
|
||||
|
||||
/// \brief Prints a parse_error to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// try
|
||||
/// {
|
||||
/// auto tbl = toml::parse("enabled = trUe"sv);
|
||||
/// }
|
||||
/// catch (const toml::parse_error & err)
|
||||
/// {
|
||||
/// std::cerr << "Parsing failed:\n"sv << err << std::endl;
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// Parsing failed:
|
||||
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
|
||||
/// (error occurred at line 1, column 13)
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
|
||||
/// \param lhs The stream.
|
||||
/// \param rhs The parse_error.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const parse_error& rhs)
|
||||
{
|
||||
lhs << rhs.description();
|
||||
lhs << "\n\t(error occurred at "sv;
|
||||
lhs << rhs.source();
|
||||
lhs << ")"sv;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
|
@ -0,0 +1,649 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
#include "toml_table.h"
|
||||
#include "toml_utf8_streams.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
#if TOML_DOXYGEN || !TOML_EXCEPTIONS
|
||||
|
||||
TOML_ABI_NAMESPACE_START(parse_noex)
|
||||
|
||||
/// \brief The result of a parsing operation.
|
||||
///
|
||||
/// \detail A parse_result is effectively a discriminated union containing either a toml::table
|
||||
/// or a toml::parse_error. Most member functions assume a particular one of these two states,
|
||||
/// and calling them when in the wrong state will cause errors (e.g. attempting to access the
|
||||
/// error object when parsing was successful). \cpp
|
||||
/// parse_result result = toml::parse_file("config.toml");
|
||||
/// if (result)
|
||||
/// do_stuff_with_a_table(result); //implicitly converts to table&
|
||||
/// else
|
||||
/// std::cerr << "Parse failed:\n"sv << result.error() << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// example output:
|
||||
///
|
||||
/// Parse failed:
|
||||
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
|
||||
/// (error occurred at line 1, column 13 of 'config.toml')
|
||||
/// \eout
|
||||
///
|
||||
/// Getting node_views (`operator[]`) and using the iterator accessor functions (`begin(), end()` etc.) are
|
||||
/// unconditionally safe; when parsing fails these just return 'empty' values. A ranged-for loop on a failed
|
||||
/// parse_result is also safe since `begin()` and `end()` return the same iterator and will not lead to any
|
||||
/// dereferences and iterations.
|
||||
///
|
||||
/// \attention <strong>This type only exists when exceptions are not enabled.</strong>
|
||||
/// Otherwise parse_result is just an alias for toml::table: \cpp
|
||||
/// #if TOML_EXCEPTIONS
|
||||
/// using parse_result = table;
|
||||
/// #else
|
||||
/// class parse_result final { // ...
|
||||
/// #endif
|
||||
/// \ecpp
|
||||
class parse_result final
|
||||
{
|
||||
private:
|
||||
std::aligned_storage_t<
|
||||
(sizeof(table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(table)),
|
||||
(alignof(table) < alignof(parse_error) ? alignof(parse_error) : alignof(table))
|
||||
> storage;
|
||||
bool is_err;
|
||||
|
||||
void destroy() noexcept
|
||||
{
|
||||
if (is_err)
|
||||
TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage))->~parse_error();
|
||||
else
|
||||
TOML_LAUNDER(reinterpret_cast<table*>(&storage))->~table();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
|
||||
using iterator = table_iterator;
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
|
||||
using const_iterator = const_table_iterator;
|
||||
|
||||
/// \brief Returns true if parsing succeeeded.
|
||||
[[nodiscard]] bool succeeded() const noexcept { return !is_err; }
|
||||
/// \brief Returns true if parsing failed.
|
||||
[[nodiscard]] bool failed() const noexcept { return is_err; }
|
||||
/// \brief Returns true if parsing succeeeded.
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return !is_err; }
|
||||
|
||||
/// \brief Returns the internal toml::table.
|
||||
[[nodiscard]] table& get() & noexcept
|
||||
{
|
||||
TOML_ASSERT(!is_err);
|
||||
return *TOML_LAUNDER(reinterpret_cast<table*>(&storage));
|
||||
}
|
||||
/// \brief Returns the internal toml::table (rvalue overload).
|
||||
[[nodiscard]] table&& get() && noexcept
|
||||
{
|
||||
TOML_ASSERT(!is_err);
|
||||
return std::move(*TOML_LAUNDER(reinterpret_cast<table*>(&storage)));
|
||||
}
|
||||
/// \brief Returns the internal toml::table (const lvalue overload).
|
||||
[[nodiscard]] const table& get() const& noexcept
|
||||
{
|
||||
TOML_ASSERT(!is_err);
|
||||
return *TOML_LAUNDER(reinterpret_cast<const table*>(&storage));
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::parse_error.
|
||||
[[nodiscard]] parse_error& error() & noexcept
|
||||
{
|
||||
TOML_ASSERT(is_err);
|
||||
return *TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage));
|
||||
}
|
||||
/// \brief Returns the internal toml::parse_error (rvalue overload).
|
||||
[[nodiscard]] parse_error&& error() && noexcept
|
||||
{
|
||||
TOML_ASSERT(is_err);
|
||||
return std::move(*TOML_LAUNDER(reinterpret_cast<parse_error*>(&storage)));
|
||||
}
|
||||
/// \brief Returns the internal toml::parse_error (const lvalue overload).
|
||||
[[nodiscard]] const parse_error& error() const& noexcept
|
||||
{
|
||||
TOML_ASSERT(is_err);
|
||||
return *TOML_LAUNDER(reinterpret_cast<const parse_error*>(&storage));
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::table.
|
||||
[[nodiscard]] operator table& () noexcept { return get(); }
|
||||
/// \brief Returns the internal toml::table (rvalue overload).
|
||||
[[nodiscard]] operator table&& () noexcept { return std::move(get()); }
|
||||
/// \brief Returns the internal toml::table (const lvalue overload).
|
||||
[[nodiscard]] operator const table& () const noexcept { return get(); }
|
||||
|
||||
/// \brief Returns the internal toml::parse_error.
|
||||
[[nodiscard]] explicit operator parse_error& () noexcept { return error(); }
|
||||
/// \brief Returns the internal toml::parse_error (rvalue overload).
|
||||
[[nodiscard]] explicit operator parse_error && () noexcept { return std::move(error()); }
|
||||
/// \brief Returns the internal toml::parse_error (const lvalue overload).
|
||||
[[nodiscard]] explicit operator const parse_error& () const noexcept { return error(); }
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit parse_result(table&& tbl) noexcept
|
||||
: is_err{ false }
|
||||
{
|
||||
::new (&storage) table{ std::move(tbl) };
|
||||
}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit parse_result(parse_error&& err) noexcept
|
||||
: is_err{ true }
|
||||
{
|
||||
::new (&storage) parse_error{ std::move(err) };
|
||||
}
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_result(parse_result&& res) noexcept
|
||||
: is_err{ res.is_err }
|
||||
{
|
||||
if (is_err)
|
||||
::new (&storage) parse_error{ std::move(res).error() };
|
||||
else
|
||||
::new (&storage) table{ std::move(res).get() };
|
||||
}
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
parse_result& operator=(parse_result&& rhs) noexcept
|
||||
{
|
||||
if (is_err != rhs.is_err)
|
||||
{
|
||||
destroy();
|
||||
is_err = rhs.is_err;
|
||||
if (is_err)
|
||||
::new (&storage) parse_error{ std::move(rhs).error() };
|
||||
else
|
||||
::new (&storage) table{ std::move(rhs).get() };
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_err)
|
||||
error() = std::move(rhs).error();
|
||||
else
|
||||
get() = std::move(rhs).get();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Destructor.
|
||||
~parse_result() noexcept
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
|
||||
/// or an empty node view.
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<node> operator[] (string_view key) noexcept
|
||||
{
|
||||
return is_err ? node_view<node>{} : get()[key];
|
||||
}
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
|
||||
[[nodiscard]] node_view<const node> operator[] (string_view key) const noexcept
|
||||
{
|
||||
return is_err ? node_view<const node>{} : get()[key];
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] table_iterator begin() noexcept
|
||||
{
|
||||
return is_err ? table_iterator{} : get().begin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator begin() const noexcept
|
||||
{
|
||||
return is_err ? const_table_iterator{} : get().begin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator cbegin() const noexcept
|
||||
{
|
||||
return is_err ? const_table_iterator{} : get().cbegin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] table_iterator end() noexcept
|
||||
{
|
||||
return is_err ? table_iterator{} : get().end();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator end() const noexcept
|
||||
{
|
||||
return is_err ? const_table_iterator{} : get().end();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator cend() const noexcept
|
||||
{
|
||||
return is_err ? const_table_iterator{} : get().cend();
|
||||
}
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END
|
||||
|
||||
#else
|
||||
|
||||
using parse_result = table;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
#if TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_START(impl_ex)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(impl_noex)
|
||||
#endif
|
||||
|
||||
[[nodiscard]] TOML_API
|
||||
parse_result do_parse(utf8_reader_interface&&) TOML_MAY_THROW;
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
}
|
||||
|
||||
|
||||
namespace toml
|
||||
{
|
||||
#if TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_START(parse_ex)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(parse_noex)
|
||||
#endif
|
||||
|
||||
/// \brief Parses a TOML document from a string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("a = 3"sv);
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
/// If you don't have a path (or you have no intention of using paths in diagnostics)
|
||||
/// then this parameter can safely be left blank.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result parse(std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
|
||||
|
||||
/// \brief Parses a TOML document from a string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("a = 3"sv, "foo.toml");
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result parse(std::string_view doc, std::string&& source_path) TOML_MAY_THROW;
|
||||
|
||||
#ifdef __cpp_lib_char8_t
|
||||
|
||||
/// \brief Parses a TOML document from a char8_t string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse(u8"a = 3"sv);
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
/// If you don't have a path (or you have no intention of using paths in diagnostics)
|
||||
/// then this parameter can safely be left blank.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
///
|
||||
/// \attention This overload is not available if your compiler does not support char8_t-based strings.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result parse(std::u8string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
|
||||
|
||||
/// \brief Parses a TOML document from a char8_t string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
///
|
||||
/// \attention This overload is not available if your compiler does not support char8_t-based strings.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result parse(std::u8string_view doc, std::string&& source_path) TOML_MAY_THROW;
|
||||
|
||||
#endif // __cpp_lib_char8_t
|
||||
|
||||
/// \brief Parses a TOML document from a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::stringstream ss;
|
||||
/// ss << "a = 3"sv;
|
||||
///
|
||||
/// auto tbl = toml::parse(ss);
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
/// If you don't have a path (or you have no intention of using paths in diagnostics)
|
||||
/// then this parameter can safely be left blank.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
template <typename Char>
|
||||
[[nodiscard]]
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
parse_result parse(std::basic_istream<Char>& doc, std::string_view source_path = {}) TOML_MAY_THROW
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
return impl::do_parse(impl::utf8_reader{ doc, source_path });
|
||||
}
|
||||
|
||||
/// \brief Parses a TOML document from a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::stringstream ss;
|
||||
/// ss << "a = 3"sv;
|
||||
///
|
||||
/// auto tbl = toml::parse(ss, "foo.toml");
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
|
||||
/// \param doc The TOML document to parse. Must be valid UTF-8.
|
||||
/// \param source_path The path used to initialize each node's `source().path`.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
template <typename Char>
|
||||
[[nodiscard]]
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
parse_result parse(std::basic_istream<Char>& doc, std::string&& source_path) TOML_MAY_THROW
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
|
||||
}
|
||||
|
||||
|
||||
// Q: "why are the parse_file functions templated??"
|
||||
// A: I don't want to force users to drag in <fstream> if they're not going to do
|
||||
// any parsing directly from files. Keeping them templated delays their instantiation
|
||||
// until they're actually required, so only those users wanting to use parse_file()
|
||||
// are burdened by the <fstream> overhead.
|
||||
|
||||
|
||||
/// \brief Parses a TOML document from a file.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// #include <fstream>
|
||||
///
|
||||
/// toml::parse_result get_foo_toml()
|
||||
/// {
|
||||
/// return toml::parse_file("foo.toml");
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam Char The path's character type. Must be 1 byte in size.
|
||||
/// \param file_path The TOML document to parse. Must be valid UTF-8.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
///
|
||||
/// \attention You must `#include <fstream>` to use this function (toml++ does not transitively include it for you).
|
||||
template <typename Char, typename StreamChar = char>
|
||||
[[nodiscard]]
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
parse_result parse_file(std::basic_string_view<Char> file_path) TOML_MAY_THROW
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The path's character type must be 1 byte in size."
|
||||
);
|
||||
static_assert(
|
||||
sizeof(StreamChar) == 1,
|
||||
"The stream's character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
#if TOML_EXCEPTIONS
|
||||
#define TOML_PARSE_FILE_ERROR(msg, pos) \
|
||||
throw parse_error{ msg, pos, std::make_shared<const std::string>(std::move(file_path_str)) }
|
||||
#else
|
||||
#define TOML_PARSE_FILE_ERROR(msg, pos) \
|
||||
return parse_result{ \
|
||||
parse_error{ msg, pos, std::make_shared<const std::string>(std::move(file_path_str)) } \
|
||||
}
|
||||
#endif
|
||||
|
||||
auto file_path_str = std::string(reinterpret_cast<const char*>(file_path.data()), file_path.length());
|
||||
|
||||
// open file with a custom-sized stack buffer
|
||||
using ifstream = std::basic_ifstream<StreamChar>;
|
||||
ifstream file;
|
||||
StreamChar file_buffer[sizeof(void*) * 4096_sz];
|
||||
file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
|
||||
file.open(file_path_str, ifstream::in | ifstream::binary | ifstream::ate);
|
||||
if (!file.is_open())
|
||||
TOML_PARSE_FILE_ERROR("File could not be opened for reading", source_position{});
|
||||
|
||||
// get size
|
||||
const auto file_size = file.tellg();
|
||||
if (file_size == -1)
|
||||
TOML_PARSE_FILE_ERROR("Could not determine file size", source_position{});
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// read the whole file into memory first if the file isn't too large
|
||||
constexpr auto large_file_threshold = 1024 * 1024 * static_cast<int>(sizeof(void*)) * 4; // 32 megabytes on 64-bit
|
||||
if (file_size <= large_file_threshold)
|
||||
{
|
||||
std::vector<StreamChar> file_data;
|
||||
file_data.resize(static_cast<size_t>(file_size));
|
||||
file.read(file_data.data(), static_cast<std::streamsize>(file_size));
|
||||
return parse(std::basic_string_view<StreamChar>{ file_data.data(), file_data.size() }, std::move(file_path_str));
|
||||
}
|
||||
|
||||
// otherwise parse it using the streams
|
||||
else
|
||||
return parse(file, std::move(file_path_str));
|
||||
|
||||
#undef TOML_PARSE_FILE_ERROR
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
|
||||
extern template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
|
||||
extern template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
|
||||
#ifdef __cpp_lib_char8_t
|
||||
extern template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename Char>
|
||||
[[nodiscard]]
|
||||
inline parse_result parse_file(const std::basic_string<Char>& file_path) TOML_MAY_THROW
|
||||
{
|
||||
return parse_file(std::basic_string_view<Char>{ file_path });
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
[[nodiscard]]
|
||||
inline parse_result parse_file(const Char* file_path) TOML_MAY_THROW
|
||||
{
|
||||
return parse_file(std::basic_string_view<Char>{ file_path });
|
||||
}
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
|
||||
/// \brief Convenience literal operators for working with toml++.
|
||||
///
|
||||
/// \detail This namespace exists so you can safely hoist the UDL operators into another scope
|
||||
/// without dragging in everything in the toml namespace: \cpp
|
||||
///
|
||||
/// #include <toml++/toml.h>
|
||||
/// using namespace toml::literals;
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
/// auto tbl = "vals = [1, 2, 3]"_toml;
|
||||
///
|
||||
/// // ... do stuff with the table generated by the "_toml" UDL ...
|
||||
///
|
||||
/// return 0;
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
inline namespace literals
|
||||
{
|
||||
#if TOML_EXCEPTIONS
|
||||
TOML_ABI_NAMESPACE_START(lit_ex)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(lit_noex)
|
||||
#endif
|
||||
|
||||
/// \brief Parses TOML data from a string.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// using namespace toml::literals;
|
||||
///
|
||||
/// auto tbl = "a = 3"_toml;
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param str The string data.
|
||||
/// \param len The string length.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result operator"" _toml(const char* str, size_t len) TOML_MAY_THROW;
|
||||
|
||||
#ifdef __cpp_lib_char8_t
|
||||
|
||||
/// \brief Parses TOML data from a string.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// using namespace toml::literals;
|
||||
///
|
||||
/// auto tbl = u8"a = 3"_toml;
|
||||
/// std::cout << tbl["a"] << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param str The string data.
|
||||
/// \param len The string length.
|
||||
///
|
||||
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
|
||||
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
|
||||
///
|
||||
/// \attention This overload is not available if your compiler does not support char8_t-based strings.
|
||||
[[nodiscard]]
|
||||
TOML_API
|
||||
parse_result operator"" _toml(const char8_t* str, size_t len) TOML_MAY_THROW;
|
||||
|
||||
#endif // __cpp_lib_char8_t
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,519 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
////////// CONFIGURATION
|
||||
|
||||
#ifdef TOML_CONFIG_HEADER
|
||||
#include TOML_CONFIG_HEADER
|
||||
#endif
|
||||
|
||||
#if !defined(TOML_ALL_INLINE) || (defined(TOML_ALL_INLINE) && TOML_ALL_INLINE) || defined(__INTELLISENSE__)
|
||||
#undef TOML_ALL_INLINE
|
||||
#define TOML_ALL_INLINE 1
|
||||
#endif
|
||||
|
||||
#if defined(TOML_IMPLEMENTATION) || TOML_ALL_INLINE
|
||||
#undef TOML_IMPLEMENTATION
|
||||
#define TOML_IMPLEMENTATION 1
|
||||
#else
|
||||
#define TOML_IMPLEMENTATION 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_API
|
||||
#define TOML_API
|
||||
#endif
|
||||
|
||||
#ifndef TOML_CHAR_8_STRINGS
|
||||
#define TOML_CHAR_8_STRINGS 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNRELEASED_FEATURES
|
||||
#define TOML_UNRELEASED_FEATURES 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_LARGE_FILES
|
||||
#define TOML_LARGE_FILES 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNDEF_MACROS
|
||||
#define TOML_UNDEF_MACROS 1
|
||||
#endif
|
||||
|
||||
#ifndef TOML_PARSER
|
||||
#define TOML_PARSER 1
|
||||
#endif
|
||||
|
||||
////////// COMPILER & ENVIRONMENT
|
||||
|
||||
#ifndef __cplusplus
|
||||
#error toml++ is a C++ library.
|
||||
#endif
|
||||
#ifndef TOML_DOXYGEN
|
||||
#define TOML_DOXYGEN 0
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
|
||||
#define TOML_PUSH_WARNINGS _Pragma("clang diagnostic push")
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS _Pragma("clang diagnostic ignored \"-Wswitch\"")
|
||||
#define TOML_DISABLE_INIT_WARNINGS _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"")
|
||||
#define TOML_DISABLE_VTABLE_WARNINGS _Pragma("clang diagnostic ignored \"-Weverything\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
|
||||
#define TOML_DISABLE_PADDING_WARNINGS _Pragma("clang diagnostic ignored \"-Wpadded\"")
|
||||
#define TOML_DISABLE_FLOAT_WARNINGS _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wdouble-promotion\"")
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS _Pragma("clang diagnostic ignored \"-Wshadow\"")
|
||||
#define TOML_DISABLE_ALL_WARNINGS _Pragma("clang diagnostic ignored \"-Weverything\"")
|
||||
#define TOML_POP_WARNINGS _Pragma("clang diagnostic pop")
|
||||
|
||||
#define TOML_ASSUME(cond) __builtin_assume(cond)
|
||||
#define TOML_UNREACHABLE __builtin_unreachable()
|
||||
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
|
||||
#if defined(_MSC_VER) // msvc compat mode
|
||||
#ifdef __has_declspec_attribute
|
||||
#if __has_declspec_attribute(novtable)
|
||||
#define TOML_INTERFACE __declspec(novtable)
|
||||
#endif
|
||||
#if __has_declspec_attribute(empty_bases)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
#endif
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __forceinline
|
||||
#endif
|
||||
#if __has_declspec_attribute(noinline)
|
||||
#define TOML_NEVER_INLINE __declspec(noinline)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __has_attribute
|
||||
#if !defined(TOML_ALWAYS_INLINE) && __has_attribute(always_inline)
|
||||
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
|
||||
#endif
|
||||
#if !defined(TOML_NEVER_INLINE) && __has_attribute(noinline)
|
||||
#define TOML_NEVER_INLINE __attribute__((__noinline__))
|
||||
#endif
|
||||
#if !defined(TOML_TRIVIAL_ABI) && __has_attribute(trivial_abi)
|
||||
#define TOML_TRIVIAL_ABI __attribute__((__trivial_abi__))
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __EXCEPTIONS
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#else
|
||||
#define TOML_COMPILER_EXCEPTIONS 0
|
||||
#endif
|
||||
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
|
||||
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
|
||||
|
||||
//floating-point from_chars and to_chars are not implemented in any version of clang as of 1/1/2020
|
||||
#ifndef TOML_FLOAT_CHARCONV
|
||||
#define TOML_FLOAT_CHARCONV 0
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(__ICL))
|
||||
|
||||
#define TOML_PUSH_WARNINGS __pragma(warning(push))
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS __pragma(warning(disable: 4063))
|
||||
#define TOML_DISABLE_ALL_WARNINGS __pragma(warning(pop)) \
|
||||
__pragma(warning(push, 0))
|
||||
#define TOML_POP_WARNINGS __pragma(warning(pop))
|
||||
|
||||
#define TOML_CPP_VERSION _MSVC_LANG
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __forceinline
|
||||
#endif
|
||||
#define TOML_NEVER_INLINE __declspec(noinline)
|
||||
#define TOML_ASSUME(cond) __assume(cond)
|
||||
#define TOML_UNREACHABLE __assume(0)
|
||||
#define TOML_INTERFACE __declspec(novtable)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
#ifdef _CPPUNWIND
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#else
|
||||
#define TOML_COMPILER_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define TOML_PUSH_WARNINGS _Pragma("GCC diagnostic push")
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS _Pragma("GCC diagnostic ignored \"-Wswitch\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wswitch-enum\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"")
|
||||
#define TOML_DISABLE_INIT_WARNINGS _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wuninitialized\"")
|
||||
#define TOML_DISABLE_PADDING_WARNINGS _Pragma("GCC diagnostic ignored \"-Wpadded\"")
|
||||
#define TOML_DISABLE_FLOAT_WARNINGS _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS _Pragma("GCC diagnostic ignored \"-Wshadow\"")
|
||||
#define TOML_DISABLE_SUGGEST_WARNINGS _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=pure\"")
|
||||
#define TOML_DISABLE_ALL_WARNINGS _Pragma("GCC diagnostic ignored \"-Wall\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wextra\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
|
||||
TOML_DISABLE_SUGGEST_WARNINGS \
|
||||
TOML_DISABLE_SWITCH_WARNINGS \
|
||||
TOML_DISABLE_INIT_WARNINGS \
|
||||
TOML_DISABLE_PADDING_WARNINGS \
|
||||
TOML_DISABLE_FLOAT_WARNINGS \
|
||||
TOML_DISABLE_SHADOW_WARNINGS
|
||||
#define TOML_POP_WARNINGS _Pragma("GCC diagnostic pop")
|
||||
|
||||
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
|
||||
#endif
|
||||
#define TOML_NEVER_INLINE __attribute__((__noinline__))
|
||||
#define TOML_UNREACHABLE __builtin_unreachable()
|
||||
#if !defined(TOML_RELOPS_REORDERING) && defined(__cpp_impl_three_way_comparison)
|
||||
#define TOML_RELOPS_REORDERING 1
|
||||
#endif
|
||||
#ifdef __cpp_exceptions
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#else
|
||||
#define TOML_COMPILER_EXCEPTIONS 0
|
||||
#endif
|
||||
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
|
||||
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
|
||||
|
||||
// floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020
|
||||
#ifndef TOML_FLOAT_CHARCONV
|
||||
#define TOML_FLOAT_CHARCONV 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TOML_CPP_VERSION
|
||||
#define TOML_CPP_VERSION __cplusplus
|
||||
#endif
|
||||
|
||||
#if TOML_CPP_VERSION < 201103L
|
||||
#error toml++ requires C++17 or higher. For a TOML library supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml
|
||||
#elif TOML_CPP_VERSION < 201703L
|
||||
#error toml++ requires C++17 or higher. For a TOML library supporting C++11 see https://github.com/ToruNiina/toml11
|
||||
#elif TOML_CPP_VERSION >= 202600L
|
||||
#define TOML_CPP 26
|
||||
#elif TOML_CPP_VERSION >= 202300L
|
||||
#define TOML_CPP 23
|
||||
#elif TOML_CPP_VERSION >= 202002L
|
||||
#define TOML_CPP 20
|
||||
#elif TOML_CPP_VERSION >= 201703L
|
||||
#define TOML_CPP 17
|
||||
#endif
|
||||
|
||||
#ifndef TOML_COMPILER_EXCEPTIONS
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#endif
|
||||
#if TOML_COMPILER_EXCEPTIONS
|
||||
#ifndef TOML_EXCEPTIONS
|
||||
#define TOML_EXCEPTIONS 1
|
||||
#endif
|
||||
#else
|
||||
#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
|
||||
#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
|
||||
#endif
|
||||
#undef TOML_EXCEPTIONS
|
||||
#define TOML_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#if TOML_EXCEPTIONS
|
||||
#define TOML_MAY_THROW
|
||||
#else
|
||||
#define TOML_MAY_THROW noexcept
|
||||
#endif
|
||||
|
||||
#ifndef TOML_INT_CHARCONV
|
||||
#define TOML_INT_CHARCONV 1
|
||||
#endif
|
||||
#ifndef TOML_FLOAT_CHARCONV
|
||||
#define TOML_FLOAT_CHARCONV 1
|
||||
#endif
|
||||
#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !__has_include(<charconv>)
|
||||
#undef TOML_INT_CHARCONV
|
||||
#undef TOML_FLOAT_CHARCONV
|
||||
#define TOML_INT_CHARCONV 0
|
||||
#define TOML_FLOAT_CHARCONV 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_PUSH_WARNINGS
|
||||
#define TOML_PUSH_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SWITCH_WARNINGS
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_INIT_WARNINGS
|
||||
#define TOML_DISABLE_INIT_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_VTABLE_WARNINGS
|
||||
#define TOML_DISABLE_VTABLE_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_PADDING_WARNINGS
|
||||
#define TOML_DISABLE_PADDING_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_FLOAT_WARNINGS
|
||||
#define TOML_DISABLE_FLOAT_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SHADOW_WARNINGS
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SUGGEST_WARNINGS
|
||||
#define TOML_DISABLE_SUGGEST_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_ALL_WARNINGS
|
||||
#define TOML_DISABLE_ALL_WARNINGS
|
||||
#endif
|
||||
#ifndef TOML_POP_WARNINGS
|
||||
#define TOML_POP_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ATTR
|
||||
#define TOML_ATTR(...)
|
||||
#endif
|
||||
|
||||
#ifndef TOML_INTERFACE
|
||||
#define TOML_INTERFACE
|
||||
#endif
|
||||
|
||||
#ifndef TOML_EMPTY_BASES
|
||||
#define TOML_EMPTY_BASES
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#ifndef TOML_NEVER_INLINE
|
||||
#define TOML_NEVER_INLINE
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ASSUME
|
||||
#define TOML_ASSUME(cond) (void)0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNREACHABLE
|
||||
#define TOML_UNREACHABLE TOML_ASSERT(false)
|
||||
#endif
|
||||
|
||||
#define TOML_NO_DEFAULT_CASE default: TOML_UNREACHABLE
|
||||
|
||||
#ifdef __cpp_consteval
|
||||
#define TOML_CONSTEVAL consteval
|
||||
#else
|
||||
#define TOML_CONSTEVAL constexpr
|
||||
#endif
|
||||
|
||||
#if !TOML_DOXYGEN && !defined(__INTELLISENSE__)
|
||||
#if !defined(TOML_LIKELY) && __has_cpp_attribute(likely)
|
||||
#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
|
||||
#endif
|
||||
#if !defined(TOML_UNLIKELY) && __has_cpp_attribute(unlikely)
|
||||
#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
|
||||
#endif
|
||||
#if __has_cpp_attribute(nodiscard) >= 201907L
|
||||
#define TOML_NODISCARD_CTOR [[nodiscard]]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TOML_LIKELY
|
||||
#define TOML_LIKELY(...) (__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef TOML_UNLIKELY
|
||||
#define TOML_UNLIKELY(...) (__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef TOML_NODISCARD_CTOR
|
||||
#define TOML_NODISCARD_CTOR
|
||||
#endif
|
||||
|
||||
#ifndef TOML_TRIVIAL_ABI
|
||||
#define TOML_TRIVIAL_ABI
|
||||
#endif
|
||||
|
||||
#ifndef TOML_RELOPS_REORDERING
|
||||
#define TOML_RELOPS_REORDERING 0
|
||||
#endif
|
||||
#if TOML_RELOPS_REORDERING
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(...)
|
||||
#else
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator == (RHS rhs, LHS lhs) noexcept { return lhs == rhs; } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
|
||||
#endif
|
||||
|
||||
#if TOML_ALL_INLINE
|
||||
#define TOML_EXTERNAL_LINKAGE inline
|
||||
#define TOML_INTERNAL_LINKAGE inline
|
||||
#define TOML_INTERNAL_NAMESPACE toml::impl
|
||||
#else
|
||||
#define TOML_EXTERNAL_LINKAGE
|
||||
#define TOML_INTERNAL_LINKAGE static
|
||||
#define TOML_INTERNAL_NAMESPACE
|
||||
#endif
|
||||
|
||||
#include "toml_version.h"
|
||||
//# {{
|
||||
#define TOML_LIB_SINGLE_HEADER 0
|
||||
//# }}
|
||||
|
||||
#define TOML_MAKE_VERSION(maj, min, rev) \
|
||||
((maj) * 1000 + (min) * 25 + (rev))
|
||||
|
||||
#if TOML_UNRELEASED_FEATURES
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
|
||||
#else
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
#endif
|
||||
|
||||
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
|
||||
(TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(maj, min, rev))
|
||||
|
||||
#define TOML_LANG_AT_LEAST(maj, min, rev) \
|
||||
(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev))
|
||||
|
||||
#define TOML_LANG_UNRELEASED \
|
||||
TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
|
||||
#if TOML_DOXYGEN || defined(__INTELLISENSE__)
|
||||
#define TOML_ABI_NAMESPACES 0
|
||||
#define TOML_ABI_NAMESPACE_START(name)
|
||||
#define TOML_ABI_NAMESPACE_END
|
||||
#else
|
||||
#define TOML_ABI_NAMESPACES 1
|
||||
#define TOML_ABI_NAMESPACE_START(name) inline namespace abi_##name {
|
||||
#define TOML_ABI_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
#ifndef TOML_ASSERT
|
||||
#if defined(NDEBUG) || !defined(_DEBUG)
|
||||
#define TOML_ASSERT(expr) (void)0
|
||||
#else
|
||||
#include <cassert>
|
||||
#define TOML_ASSERT(expr) assert(expr)
|
||||
#endif
|
||||
#endif
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
#define TOML_STRING_PREFIX_1(S) u8##S
|
||||
#define TOML_STRING_PREFIX(S) TOML_STRING_PREFIX_1(S)
|
||||
#else
|
||||
#define TOML_STRING_PREFIX(S) S
|
||||
#endif
|
||||
|
||||
//# {{
|
||||
#if TOML_DOXYGEN
|
||||
|
||||
/// \addtogroup configuration Library Configuration
|
||||
/// \brief Preprocessor macros for configuring library functionality.
|
||||
/// \detail Define these before including toml++ to alter the way it functions.
|
||||
/// \remarks Some of these options have ABI implications; inline namespaces are used to prevent
|
||||
/// you from trying to link incompatible combinations together.
|
||||
/// @{
|
||||
|
||||
|
||||
/// \def TOML_ALL_INLINE
|
||||
/// \brief Sets whether the library is entirely inline.
|
||||
/// \detail Defaults to `1`.
|
||||
/// \remark Disabling this means that you must define `TOML_IMPLEMENTATION` in
|
||||
/// <strong><em>exactly one</em></strong> translation unit in your project:
|
||||
/// \cpp
|
||||
/// // global_header_that_includes_toml++.h
|
||||
/// #define TOML_ALL_INLINE 0
|
||||
/// #include <toml.hpp>
|
||||
///
|
||||
/// // some_code_file.cpp
|
||||
/// #define TOML_IMPLEMENTATION
|
||||
/// #include "global_header_that_includes_toml++.h"
|
||||
/// \ecpp
|
||||
|
||||
|
||||
#define TOML_API
|
||||
/// \def TOML_API
|
||||
/// \brief An annotation to add to public symbols.
|
||||
/// \detail Not defined by default.
|
||||
/// \remark You'd override this with `__declspec(dllexport)` if you were building the library
|
||||
/// into the public API of a DLL on Windows.
|
||||
|
||||
|
||||
/// \def TOML_ASSERT(expr)
|
||||
/// \brief Sets the assert function used by the library.
|
||||
/// \detail Defaults to the standard C `assert()`.
|
||||
|
||||
|
||||
/// \def TOML_CHAR_8_STRINGS
|
||||
/// \brief Uses C++20 char8_t-based strings as the toml string data type.
|
||||
/// \detail Defaults to `0`.
|
||||
|
||||
|
||||
#define TOML_CONFIG_HEADER
|
||||
/// \def TOML_CONFIG_HEADER
|
||||
/// \brief An additional header to include before any other toml++ header files.
|
||||
/// \detail Not defined by default.
|
||||
|
||||
|
||||
/// \def TOML_EXCEPTIONS
|
||||
/// \brief Sets whether the library uses exceptions to report parsing failures.
|
||||
/// \detail Defaults to `1` or `0` according to your compiler's exception mode.
|
||||
|
||||
|
||||
/// \def TOML_IMPLEMENTATION
|
||||
/// \brief Enables the library's implementation when #TOML_ALL_INLINE is enabled.
|
||||
/// \detail Not defined by default. Meaningless when #TOML_ALL_INLINE is disabled.
|
||||
|
||||
|
||||
/// \def TOML_LARGE_FILES
|
||||
/// \brief Sets whether line and column indices are 32-bit integers.
|
||||
/// \detail Defaults to `0`.
|
||||
/// \see toml::source_index
|
||||
|
||||
|
||||
#define TOML_OPTIONAL_TYPE
|
||||
/// \def TOML_OPTIONAL_TYPE
|
||||
/// \brief Overrides the `optional<T>` type used by the library.
|
||||
/// \detail Not defined by default (use std::optional).
|
||||
/// \warning The library uses optionals internally in a few places; if you choose to replace the optional type
|
||||
/// it must be with something that is still API-compatible with std::optional
|
||||
/// (e.g. [tl::optional](https://github.com/TartanLlama/optional)).
|
||||
|
||||
|
||||
/// \def TOML_PARSER
|
||||
/// \brief Sets whether the parser-related parts of the library are included.
|
||||
/// \detail Defaults to `1`.
|
||||
/// \remarks If you don't need to parse TOML data from any strings or files (e.g. you're only using the library to
|
||||
/// serialize data as TOML), setting `TOML_PARSER` to `0` can yield decent compilation speed improvements.
|
||||
|
||||
|
||||
#define TOML_SMALL_FLOAT_TYPE
|
||||
/// \def TOML_SMALL_FLOAT_TYPE
|
||||
/// \brief If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it.
|
||||
/// \detail Not defined by default.
|
||||
|
||||
|
||||
#define TOML_SMALL_INT_TYPE
|
||||
/// \def TOML_SMALL_INT_TYPE
|
||||
/// \brief If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it.
|
||||
/// \detail Not defined by default.
|
||||
|
||||
|
||||
/// \def TOML_UNRELEASED_FEATURES
|
||||
/// \brief Enables support for unreleased TOML language features not yet part of a
|
||||
/// [numbered version](https://github.com/toml-lang/toml/releases).
|
||||
/// \detail Defaults to `0`.
|
||||
/// \see [TOML Language Support](https://github.com/marzer/tomlplusplus/blob/master/README.md#toml-language-support)
|
||||
|
||||
|
||||
/// @}
|
||||
#endif // TOML_DOXYGEN
|
||||
//# }}
|
||||
|
||||
// clang-format on
|
|
@ -0,0 +1,442 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_date_time.h"
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
#include <cmath>
|
||||
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
|
||||
#include <charconv>
|
||||
#endif
|
||||
#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
|
||||
#include <sstream>
|
||||
#endif
|
||||
#if !TOML_INT_CHARCONV
|
||||
#include <iomanip>
|
||||
#endif
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
|
||||
// A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
|
||||
// - I'm using <charconv> to format numerics. Faster and locale-independent.
|
||||
// - I can avoid forcing users to drag in <sstream> and <iomanip>.
|
||||
|
||||
// Q: "there's a bit of reinterpret_casting here, is any of it UB?"
|
||||
// A: - If the source string data is char and the output string is char8_t, then technically yes,
|
||||
// but not in the other direction. I test in both modes on Clang, GCC and MSVC and have yet to
|
||||
// see it actually causing an issue, but in the event it does present a problem it's not going to
|
||||
// be a show-stopper since all it means is I need to do duplicate some code.
|
||||
// - Strings in C++. Honestly.
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(std::basic_string_view<Char1> str, std::basic_ostream<Char2>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
|
||||
}
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const std::basic_string<Char1>& str, std::basic_ostream<Char2>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
stream.write(reinterpret_cast<const Char2*>(str.data()), static_cast<std::streamsize>(str.length()));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(char character, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const char* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
#if defined(__cpp_lib_char8_t)
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(char8_t character, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(const char8_t* str, size_t len, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T> inline constexpr size_t charconv_buffer_length = 0;
|
||||
template <> inline constexpr size_t charconv_buffer_length<double> = 60;
|
||||
template <> inline constexpr size_t charconv_buffer_length<float> = 40;
|
||||
template <> inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
|
||||
template <> inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
|
||||
template <> inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
|
||||
template <> inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
|
||||
template <> inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
|
||||
template <> inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
|
||||
template <> inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
|
||||
template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
|
||||
|
||||
template <typename T, typename Char>
|
||||
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
#if TOML_INT_CHARCONV
|
||||
|
||||
char buf[charconv_buffer_length<T>];
|
||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
|
||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
||||
print_to_stream(buf, len, stream);
|
||||
|
||||
#else
|
||||
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
|
||||
ss << static_cast<cast_type>(val);
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
TOML_ALWAYS_INLINE \
|
||||
void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
{ \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_integer_to_stream(val, stream); \
|
||||
}
|
||||
|
||||
TOML_P2S_OVERLOAD(int8_t)
|
||||
TOML_P2S_OVERLOAD(int16_t)
|
||||
TOML_P2S_OVERLOAD(int32_t)
|
||||
TOML_P2S_OVERLOAD(int64_t)
|
||||
TOML_P2S_OVERLOAD(uint8_t)
|
||||
TOML_P2S_OVERLOAD(uint16_t)
|
||||
TOML_P2S_OVERLOAD(uint32_t)
|
||||
TOML_P2S_OVERLOAD(uint64_t)
|
||||
|
||||
#undef TOML_P2S_OVERLOAD
|
||||
|
||||
template <typename T, typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void print_floating_point_to_stream(T val, std::basic_ostream<Char>& stream, bool hexfloat = false)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
switch (std::fpclassify(val))
|
||||
{
|
||||
case FP_INFINITE:
|
||||
if (val < T{})
|
||||
print_to_stream('-', stream);
|
||||
print_to_stream("inf"sv, stream);
|
||||
return;
|
||||
|
||||
case FP_NAN:
|
||||
print_to_stream("nan"sv, stream);
|
||||
return;
|
||||
|
||||
default:
|
||||
{
|
||||
static constexpr auto needs_decimal_point = [](auto&& s) noexcept
|
||||
{
|
||||
for (auto c : s)
|
||||
if (c == '.' || c == 'E' || c == 'e')
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
#if TOML_FLOAT_CHARCONV
|
||||
{
|
||||
char buf[charconv_buffer_length<T>];
|
||||
const auto res = hexfloat
|
||||
? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
|
||||
: std::to_chars(buf, buf + sizeof(buf), val);
|
||||
const auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
|
||||
print_to_stream(str, stream);
|
||||
if (!hexfloat && needs_decimal_point(str))
|
||||
print_to_stream(".0"sv, stream);
|
||||
}
|
||||
#else
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
ss.precision(std::numeric_limits<T>::digits10 + 1);
|
||||
if (hexfloat)
|
||||
ss << std::hexfloat;
|
||||
ss << val;
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
if (!hexfloat && needs_decimal_point(str))
|
||||
print_to_stream(".0"sv, stream);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
|
||||
extern template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
|
||||
#endif
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
TOML_ALWAYS_INLINE \
|
||||
void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
|
||||
{ \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_floating_point_to_stream(val, stream); \
|
||||
}
|
||||
|
||||
TOML_P2S_OVERLOAD(float)
|
||||
TOML_P2S_OVERLOAD(double)
|
||||
|
||||
#undef TOML_P2S_OVERLOAD
|
||||
|
||||
template <typename Char>
|
||||
TOML_ALWAYS_INLINE
|
||||
void print_to_stream(bool val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val ? "true"sv : "false"sv, stream);
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
inline void print_to_stream(T val, std::basic_ostream<Char>& stream, size_t zero_pad_to_digits)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
#if TOML_INT_CHARCONV
|
||||
|
||||
char buf[charconv_buffer_length<T>];
|
||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
|
||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
||||
for (size_t i = len; i < zero_pad_to_digits; i++)
|
||||
print_to_stream('0', stream);
|
||||
print_to_stream(buf, static_cast<size_t>(res.ptr - buf), stream);
|
||||
|
||||
#else
|
||||
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
|
||||
ss << std::setfill('0') << std::setw(static_cast<int>(zero_pad_to_digits)) << static_cast<cast_type>(val);
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::date& val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.year, stream, 4_sz);
|
||||
print_to_stream('-', stream);
|
||||
print_to_stream(val.month, stream, 2_sz);
|
||||
print_to_stream('-', stream);
|
||||
print_to_stream(val.day, stream, 2_sz);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::time& val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.hour, stream, 2_sz);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(val.minute, stream, 2_sz);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(val.second, stream, 2_sz);
|
||||
if (val.nanosecond && val.nanosecond <= 999999999u)
|
||||
{
|
||||
print_to_stream('.', stream);
|
||||
auto ns = val.nanosecond;
|
||||
size_t digits = 9_sz;
|
||||
while (ns % 10u == 0u)
|
||||
{
|
||||
ns /= 10u;
|
||||
digits--;
|
||||
}
|
||||
print_to_stream(ns, stream, digits);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(toml::time_offset val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
if (!val.minutes)
|
||||
print_to_stream('Z', stream);
|
||||
else
|
||||
{
|
||||
auto mins = static_cast<int>(val.minutes);
|
||||
if (mins < 0)
|
||||
{
|
||||
print_to_stream('-', stream);
|
||||
mins = -mins;
|
||||
}
|
||||
else
|
||||
print_to_stream('+', stream);
|
||||
const auto hours = mins / 60;
|
||||
if (hours)
|
||||
{
|
||||
print_to_stream(static_cast<unsigned int>(hours), stream, 2_sz);
|
||||
mins -= hours * 60;
|
||||
}
|
||||
else
|
||||
print_to_stream("00"sv, stream);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(static_cast<unsigned int>(mins), stream, 2_sz);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::date_time& val, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.date, stream);
|
||||
print_to_stream('T', stream);
|
||||
print_to_stream(val.time, stream);
|
||||
if (val.time_offset)
|
||||
print_to_stream(*val.time_offset, stream);
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_ALL_WARNINGS
|
||||
|
||||
template <typename T, typename Char>
|
||||
void print_to_stream_with_escapes(T && str, std::basic_ostream<Char>& stream)
|
||||
{
|
||||
static_assert(sizeof(Char) == 1);
|
||||
for (auto c : str)
|
||||
{
|
||||
if TOML_UNLIKELY(c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F'))
|
||||
print_to_stream(low_character_escape_table[c], stream);
|
||||
else if TOML_UNLIKELY(c == TOML_STRING_PREFIX('\x7F'))
|
||||
print_to_stream(TOML_STRING_PREFIX("\\u007F"sv), stream);
|
||||
else if TOML_UNLIKELY(c == TOML_STRING_PREFIX('"'))
|
||||
print_to_stream(TOML_STRING_PREFIX("\\\""sv), stream);
|
||||
else if TOML_UNLIKELY(c == TOML_STRING_PREFIX('\\'))
|
||||
print_to_stream(TOML_STRING_PREFIX("\\\\"sv), stream);
|
||||
else
|
||||
print_to_stream(c, stream);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
}
|
||||
|
||||
|
||||
namespace toml
|
||||
{
|
||||
/// \brief Prints a source_position to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("bar = 42"sv);
|
||||
///
|
||||
/// std::cout << "The value for 'bar' was found on "sv
|
||||
/// << tbl.get("bar")->source().begin()
|
||||
/// << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// The value for 'bar' was found on line 1, column 7
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
|
||||
/// \param lhs The stream.
|
||||
/// \param rhs The source_position.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_position& rhs)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
impl::print_to_stream("line "sv, lhs);
|
||||
impl::print_to_stream(rhs.line, lhs);
|
||||
impl::print_to_stream(", column "sv, lhs);
|
||||
impl::print_to_stream(rhs.column, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints a source_region to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("bar = 42", "config.toml");
|
||||
///
|
||||
/// std::cout << "The value for 'bar' was found on "sv
|
||||
/// << tbl.get("bar")->source()
|
||||
/// << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// The value for 'bar' was found on line 1, column 7 of 'config.toml'
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
|
||||
/// \param lhs The stream.
|
||||
/// \param rhs The source_position.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const source_region& rhs)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size."
|
||||
);
|
||||
lhs << rhs.begin;
|
||||
if (rhs.path)
|
||||
{
|
||||
impl::print_to_stream(" of '"sv, lhs);
|
||||
impl::print_to_stream(*rhs.path, lhs);
|
||||
impl::print_to_stream('\'', lhs);
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const source_position&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const source_region&);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,791 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_array.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <bool IsConst>
|
||||
struct table_proxy_pair final
|
||||
{
|
||||
using value_type = std::conditional_t<IsConst, const node, node>;
|
||||
|
||||
const string& first;
|
||||
value_type& second;
|
||||
};
|
||||
|
||||
template <bool IsConst>
|
||||
class table_iterator final
|
||||
{
|
||||
private:
|
||||
friend class ::toml::table;
|
||||
|
||||
using proxy_type = table_proxy_pair<IsConst>;
|
||||
using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator;
|
||||
using raw_const_iterator = string_map<std::unique_ptr<node>>::const_iterator;
|
||||
using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
|
||||
|
||||
mutable raw_iterator raw_;
|
||||
mutable std::aligned_storage_t<sizeof(proxy_type), alignof(proxy_type)> proxy;
|
||||
mutable bool proxy_instantiated = false;
|
||||
|
||||
[[nodiscard]]
|
||||
proxy_type* get_proxy() const noexcept
|
||||
{
|
||||
if (!proxy_instantiated)
|
||||
{
|
||||
auto p = new (&proxy) proxy_type{ raw_->first, *raw_->second.get() };
|
||||
proxy_instantiated = true;
|
||||
return p;
|
||||
}
|
||||
else
|
||||
return TOML_LAUNDER(reinterpret_cast<proxy_type*>(&proxy));
|
||||
}
|
||||
|
||||
table_iterator(raw_mutable_iterator raw) noexcept
|
||||
: raw_{ raw }
|
||||
{}
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<C>>
|
||||
TOML_NODISCARD_CTOR
|
||||
table_iterator(raw_const_iterator raw) noexcept
|
||||
: raw_{ raw }
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
table_iterator() noexcept = default;
|
||||
|
||||
table_iterator(const table_iterator& other) noexcept
|
||||
: raw_{ other.raw_ }
|
||||
{}
|
||||
|
||||
table_iterator& operator = (const table_iterator& rhs) noexcept
|
||||
{
|
||||
raw_ = rhs.raw_;
|
||||
proxy_instantiated = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
using value_type = table_proxy_pair<IsConst>;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
|
||||
table_iterator& operator++() noexcept // ++pre
|
||||
{
|
||||
++raw_;
|
||||
proxy_instantiated = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
table_iterator operator++(int) noexcept // post++
|
||||
{
|
||||
table_iterator out{ raw_ };
|
||||
++raw_;
|
||||
proxy_instantiated = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
table_iterator& operator--() noexcept // --pre
|
||||
{
|
||||
--raw_;
|
||||
proxy_instantiated = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
table_iterator operator--(int) noexcept // post--
|
||||
{
|
||||
table_iterator out{ raw_ };
|
||||
--raw_;
|
||||
proxy_instantiated = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return *get_proxy();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
pointer operator -> () const noexcept
|
||||
{
|
||||
return get_proxy();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator == (const table_iterator& lhs, const table_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ == rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
friend constexpr bool operator != (const table_iterator& lhs, const table_iterator& rhs) noexcept
|
||||
{
|
||||
return lhs.raw_ != rhs.raw_;
|
||||
}
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<!C>>
|
||||
[[nodiscard]]
|
||||
operator table_iterator<true>() const noexcept
|
||||
{
|
||||
return table_iterator<true>{ raw_ };
|
||||
}
|
||||
};
|
||||
|
||||
struct table_init_pair final
|
||||
{
|
||||
string key;
|
||||
std::unique_ptr<node> value;
|
||||
|
||||
template <typename T>
|
||||
table_init_pair(string&& k, T && v) noexcept
|
||||
: key{ std::move(k) },
|
||||
value{ make_node(std::forward<T>(v)) }
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
table_init_pair(string_view k, T&& v) noexcept
|
||||
: key{ k },
|
||||
value{ make_node(std::forward<T>(v)) }
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
table_init_pair(const string_char* k, T&& v) noexcept
|
||||
: key{ k },
|
||||
value{ make_node(std::forward<T>(v)) }
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
namespace toml
|
||||
{
|
||||
[[nodiscard]] TOML_API bool operator == (const table& lhs, const table& rhs) noexcept;
|
||||
[[nodiscard]] TOML_API bool operator != (const table& lhs, const table& rhs) noexcept;
|
||||
template <typename Char>
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
|
||||
using table_iterator = impl::table_iterator<false>;
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
|
||||
using const_table_iterator = impl::table_iterator<true>;
|
||||
|
||||
/// \brief A TOML table.
|
||||
///
|
||||
/// \remarks The interface of this type is modeled after std::map, with some
|
||||
/// additional considerations made for the heterogeneous nature of a
|
||||
/// TOML table, and for the removal of some cruft (the public interface of
|
||||
/// std::map is, simply, _a hot mess_).
|
||||
class TOML_API table final
|
||||
: public node
|
||||
{
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
impl::string_map<std::unique_ptr<node>> values;
|
||||
bool inline_ = false;
|
||||
|
||||
table(impl::table_init_pair*, size_t) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
|
||||
using iterator = table_iterator;
|
||||
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
|
||||
using const_iterator = const_table_iterator;
|
||||
|
||||
/// \brief Default constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
table() noexcept;
|
||||
|
||||
/// \brief Constructs a table with one or more initial key-value pairs.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{ // double braces required :( - see remark
|
||||
/// { "foo", 1 },
|
||||
/// { "bar", 2.0 },
|
||||
/// { "kek", "three" }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { foo = 1, bar = 2.0, kek = "three" }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam N Number of key-value pairs used to initialize the table.
|
||||
/// \param arr An array of key-value pairs used to initialize the table.
|
||||
///
|
||||
/// \remarks C++ std::initializer_lists represent their member elements as
|
||||
/// const even if the list's value type is non-const. This is great for
|
||||
/// compiler writers, I guess, but pretty annoying for me since
|
||||
/// TOML key-value pairs are polymorphic (and thus move-only). This means
|
||||
/// that for the human-friendly braced init list syntax to work I can't use
|
||||
/// std::initializer_list and must instead invent an annoying proxy type,
|
||||
/// which means an extra level of nesting.
|
||||
/// <br><br>
|
||||
/// See https://en.cppreference.com/w/cpp/utility/initializer_list
|
||||
/// if you'd like to learn more about this.
|
||||
template <size_t N>
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit table(impl::table_init_pair(&& arr)[N]) noexcept
|
||||
: table{ arr, N }
|
||||
{}
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
table(table&& other) noexcept;
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
table& operator= (table&& rhs) noexcept;
|
||||
|
||||
table(const table&) = delete;
|
||||
table& operator= (const table&) = delete;
|
||||
|
||||
/// \brief Always returns `node_type::table` for table nodes.
|
||||
[[nodiscard]] node_type type() const noexcept override;
|
||||
/// \brief Always returns `true` for table nodes.
|
||||
[[nodiscard]] bool is_table() const noexcept override;
|
||||
/// \brief Always returns `false` for table nodes.
|
||||
[[nodiscard]] bool is_array() const noexcept override;
|
||||
/// \brief Always returns `false` for table nodes.
|
||||
[[nodiscard]] bool is_value() const noexcept override;
|
||||
[[nodiscard]] table* as_table() noexcept override;
|
||||
[[nodiscard]] const table* as_table() const noexcept override;
|
||||
|
||||
/// \brief Returns true if this table is an inline table.
|
||||
///
|
||||
/// \remarks Runtime-constructed tables (i.e. those not created during
|
||||
/// parsing) are not inline by default.
|
||||
[[nodiscard]] bool is_inline() const noexcept;
|
||||
|
||||
/// \brief Sets whether this table is a TOML inline table.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 },
|
||||
/// { "d", toml::table{{ { "e", 4 } }} }
|
||||
/// }};
|
||||
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
|
||||
/// std::cout << tbl << std::endl << std::endl;
|
||||
///
|
||||
/// tbl.is_inline(!tbl.is_inline());
|
||||
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// is inline? false
|
||||
/// a = 1
|
||||
/// b = 2
|
||||
/// c = 3
|
||||
/// [d]
|
||||
/// e = 4
|
||||
///
|
||||
/// is inline? true
|
||||
/// { a = 1, b = 2, c = 3, d = { e = 4 } }
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks A table being 'inline' is only relevent during printing;
|
||||
/// it has no effect on the general functionality of the table
|
||||
/// object.
|
||||
///
|
||||
/// \param val The new value for 'inline'.
|
||||
void is_inline(bool val) noexcept;
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair.
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if one existed, or an empty node view.
|
||||
///
|
||||
/// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
|
||||
/// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
|
||||
/// <strong>This is not an error.</strong>
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<node> operator[] (string_view key) noexcept;
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair (const overload).
|
||||
[[nodiscard]] node_view<const node> operator[] (string_view key) const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
[[nodiscard]] iterator begin() noexcept;
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
[[nodiscard]] const_iterator begin() const noexcept;
|
||||
/// \brief Returns an iterator to the first key-value pair.
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
[[nodiscard]] iterator end() noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
[[nodiscard]] const_iterator end() const noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair.
|
||||
[[nodiscard]] const_iterator cend() const noexcept;
|
||||
|
||||
/// \brief Returns true if the table is empty.
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
/// \brief Returns the number of key-value pairs in the table.
|
||||
[[nodiscard]] size_t size() const noexcept;
|
||||
/// \brief Removes all key-value pairs from the table.
|
||||
void clear() noexcept;
|
||||
|
||||
/// \brief Inserts a new value at a specific key if one did not already exist.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// for (auto k : { "a", "d" })
|
||||
/// {
|
||||
/// auto result = tbl.insert(k, 42);
|
||||
/// std::cout << "inserted with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// }
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// inserted with key 'a': false
|
||||
/// inserted with key 'd': true
|
||||
/// { a = 1, b = 2, c = 3, d = 42 }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam K toml::string (or a type convertible to it).
|
||||
/// \tparam V One of the TOML value types (or a type promotable to one).
|
||||
/// \param key The key at which to insert the new value.
|
||||
/// \param val The new value to insert.
|
||||
///
|
||||
/// \returns A std::pair containing:
|
||||
/// - An iterator to the insertion position (or the position of the value that prevented insertion)
|
||||
/// - A boolean indicating if the insertion was successful.
|
||||
template <typename K, typename V, typename = std::enable_if_t<
|
||||
std::is_convertible_v<K&&, string_view>
|
||||
>>
|
||||
std::pair<iterator, bool> insert(K&& key, V&& val) noexcept
|
||||
{
|
||||
auto ipos = values.lower_bound(key);
|
||||
if (ipos == values.end() || ipos->first != key)
|
||||
{
|
||||
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
|
||||
return { ipos, true };
|
||||
}
|
||||
return { ipos, false };
|
||||
}
|
||||
|
||||
/// \brief Inserts a series of key-value pairs into the table.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// auto kvps = std::array<std::pair<toml::string, int>>{{
|
||||
/// { "d", 42 },
|
||||
/// { "a", 43 }
|
||||
/// }};
|
||||
/// tbl.insert(kvps.begin(), kvps.end());
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// { a = 1, b = 2, c = 3, d = 42 } //"a" already existed
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Iter An InputIterator to a collection of key-value pairs.
|
||||
/// \param first An iterator to the first value in the input collection.
|
||||
/// \param last An iterator to one-past-the-last value in the input collection.
|
||||
///
|
||||
/// \remarks This function is morally equivalent to calling `insert(key, value)` for each
|
||||
/// key-value pair covered by the iterator range, so any values with keys already found in the
|
||||
/// table will not be replaced.
|
||||
template <typename Iter, typename = std::enable_if_t<
|
||||
!std::is_convertible_v<Iter&&, string_view>
|
||||
>>
|
||||
void insert(Iter first, Iter last) noexcept
|
||||
{
|
||||
if (first == last)
|
||||
return;
|
||||
for (auto it = first; it != last; it++)
|
||||
{
|
||||
if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
|
||||
insert(std::move((*it).first), std::move((*it).second));
|
||||
else
|
||||
insert((*it).first, (*it).second);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Inserts or assigns a value at a specific key.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// for (auto k : { "a", "d" })
|
||||
/// {
|
||||
/// auto result = tbl.insert_or_assign(k, 42);
|
||||
/// std::cout << "value at key '"sv << k
|
||||
/// << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << std::endl;
|
||||
/// }
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// value at key 'a' was assigned
|
||||
/// value at key 'd' was inserted
|
||||
/// { a = 42, b = 2, c = 3, d = 42 }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam K toml::string (or a type convertible to it).
|
||||
/// \tparam V One of the TOML value types (or a type promotable to one).
|
||||
/// \param key The key at which to insert or assign the value.
|
||||
/// \param val The value to insert/assign.
|
||||
///
|
||||
/// \returns A std::pair containing:
|
||||
/// - An iterator to the value's position
|
||||
/// - A boolean containing `true` if the value was inserted, `false` if it was assigned.
|
||||
template <typename K, typename V>
|
||||
std::pair<iterator, bool> insert_or_assign(K&& key, V&& val) noexcept
|
||||
{
|
||||
auto ipos = values.lower_bound(key);
|
||||
if (ipos == values.end() || ipos->first != key)
|
||||
{
|
||||
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
|
||||
return { ipos, true };
|
||||
}
|
||||
else
|
||||
{
|
||||
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
|
||||
return { ipos, false };
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new value at a specific key if one did not already exist.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// for (auto k : { "a", "d" })
|
||||
/// {
|
||||
/// // add a string using std::string's substring constructor
|
||||
/// auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5);
|
||||
/// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << std::endl;
|
||||
/// }
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// emplaced with key 'a': false
|
||||
/// emplaced with key 'd': true
|
||||
/// { a = 1, b = 2, c = 3, d = "drill" }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam U One of the TOML node or value types.
|
||||
/// \tparam K toml::string (or a type convertible to it).
|
||||
/// \tparam V Value constructor argument types.
|
||||
/// \param key The key at which to emplace the new value.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns A std::pair containing:
|
||||
/// - An iterator to the emplacement position (or the position of the value that prevented emplacement)
|
||||
/// - A boolean indicating if the emplacement was successful.
|
||||
///
|
||||
/// \remark There is no difference between insert() and emplace() for trivial value types (floats, ints, bools).
|
||||
template <typename U, typename K, typename... V>
|
||||
std::pair<iterator, bool> emplace(K&& key, V&&... args) noexcept
|
||||
{
|
||||
using type = impl::unwrapped<U>;
|
||||
static_assert(
|
||||
impl::is_value_or_node<type>,
|
||||
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
||||
);
|
||||
|
||||
auto ipos = values.lower_bound(key);
|
||||
if (ipos == values.end() || ipos->first != key)
|
||||
{
|
||||
ipos = values.emplace_hint(
|
||||
ipos,
|
||||
std::forward<K>(key),
|
||||
new impl::node_of<type>{ std::forward<V>(args)... }
|
||||
);
|
||||
return { ipos, true };
|
||||
}
|
||||
return { ipos, false };
|
||||
}
|
||||
|
||||
/// \brief Removes the specified key-value pair from the table.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// tbl.erase(tbl.begin() + 1);
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// { a = 1, c = 3 }
|
||||
/// \eout
|
||||
///
|
||||
/// \param pos Iterator to the key-value pair being erased.
|
||||
///
|
||||
/// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
|
||||
iterator erase(iterator pos) noexcept;
|
||||
|
||||
/// \brief Removes the specified key-value pair from the table (const iterator overload).
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// tbl.erase(tbl.cbegin() + 1);
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// { a = 1, c = 3 }
|
||||
/// \eout
|
||||
///
|
||||
/// \param pos Iterator to the key-value pair being erased.
|
||||
///
|
||||
/// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
|
||||
iterator erase(const_iterator pos) noexcept;
|
||||
|
||||
/// \brief Removes the key-value pairs in the range [first, last) from the table.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", "bad" },
|
||||
/// { "c", "karma" },
|
||||
/// { "d", 2 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3);
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = "bad", c = "karma", d = 2 }
|
||||
/// { a = 1, d = 2 }
|
||||
/// \eout
|
||||
///
|
||||
/// \param first Iterator to the first key-value pair being erased.
|
||||
/// \param last Iterator to the one-past-the-last key-value pair being erased.
|
||||
///
|
||||
/// \returns Iterator to the first key-value pair immediately following the last removed key-value pair.
|
||||
iterator erase(const_iterator first, const_iterator last) noexcept;
|
||||
|
||||
/// \brief Removes the value with the given key from the table.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 1 },
|
||||
/// { "b", 2 },
|
||||
/// { "c", 3 }
|
||||
/// }};
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// std::cout << tbl.erase("b") << std::endl;
|
||||
/// std::cout << tbl.erase("not an existing key") << std::endl;
|
||||
/// std::cout << tbl << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// { a = 1, b = 2, c = 3 }
|
||||
/// true
|
||||
/// false
|
||||
/// { a = 1, c = 3 }
|
||||
/// \eout
|
||||
///
|
||||
/// \param key Key to erase.
|
||||
///
|
||||
/// \returns True if any values with matching keys were found and erased.
|
||||
bool erase(string_view key) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
template <typename Map, typename Key>
|
||||
[[nodiscard]] static auto do_get(Map& vals, const Key& key) noexcept
|
||||
{
|
||||
using return_type = std::conditional_t<
|
||||
std::is_const_v<Map>,
|
||||
const node*,
|
||||
node*
|
||||
>;
|
||||
|
||||
if (auto it = vals.find(key); it != vals.end())
|
||||
return return_type{ it->second.get() };
|
||||
return return_type{};
|
||||
}
|
||||
|
||||
template <typename T, typename Map, typename Key>
|
||||
[[nodiscard]] static auto do_get_as(Map& vals, const Key& key) noexcept
|
||||
{
|
||||
const auto node = do_get(vals, key);
|
||||
return node ? node->template as<T>() : nullptr;
|
||||
}
|
||||
|
||||
template <typename Map, typename Key>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
static bool do_contains(Map& vals, const Key& key) noexcept
|
||||
{
|
||||
#if TOML_CPP >= 20
|
||||
return vals.contains(key);
|
||||
#else
|
||||
return do_get(vals, key) != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Gets the node at a specific key.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 42, },
|
||||
/// { "b", "is the meaning of life, apparently." }
|
||||
/// }};
|
||||
/// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << std::endl;
|
||||
/// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << std::endl;
|
||||
/// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << std::endl;
|
||||
/// if (auto val = arr.get("a"))
|
||||
/// std::cout << R"(node ["a"] was an )"sv << val->type() << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// node ["a"] exists: true
|
||||
/// node ["b"] exists: true
|
||||
/// node ["c"] exists: false
|
||||
/// node ["a"] was an integer
|
||||
/// \eout
|
||||
///
|
||||
/// \param key The node's key.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key, or nullptr.
|
||||
[[nodiscard]] node* get(string_view key) noexcept;
|
||||
|
||||
/// \brief Gets the node at a specific key (const overload).
|
||||
///
|
||||
/// \param key The node's key.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key, or nullptr.
|
||||
[[nodiscard]] const node* get(string_view key) const noexcept;
|
||||
|
||||
[[nodiscard]] iterator find(string_view key) noexcept;
|
||||
[[nodiscard]] const_iterator find(string_view key) const noexcept;
|
||||
|
||||
/// \brief Gets the node at a specific key if it is a particular type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "a", 42, },
|
||||
/// { "b", "is the meaning of life, apparently." }
|
||||
/// }};
|
||||
/// if (auto val = arr.get_as<int64_t>("a"))
|
||||
/// std::cout << R"(node ["a"] was an integer with value )"sv << **val << std::endl;
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// node ["a"] was an integer with value 42
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam T The node's type.
|
||||
/// \param key The node's key.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] impl::node_of<T>* get_as(string_view key) noexcept
|
||||
{
|
||||
return do_get_as<T>(values, key);
|
||||
}
|
||||
|
||||
/// \brief Gets the node at a specific key if it is a particular type (const overload).
|
||||
///
|
||||
/// \tparam T The node's type.
|
||||
/// \param key The node's key.
|
||||
///
|
||||
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
|
||||
template <typename T>
|
||||
[[nodiscard]] const impl::node_of<T>* get_as(string_view key) const noexcept
|
||||
{
|
||||
return do_get_as<T>(values, key);
|
||||
}
|
||||
|
||||
/// \brief Returns true if the table contains a node at the given key.
|
||||
[[nodiscard]] bool contains(string_view key) const noexcept;
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS table.
|
||||
/// \param rhs The RHS table.
|
||||
///
|
||||
/// \returns True if the tables contained the same keys and values.
|
||||
friend bool operator == (const table& lhs, const table& rhs) noexcept;
|
||||
|
||||
/// \brief Inequality operator.
|
||||
///
|
||||
/// \param lhs The LHS table.
|
||||
/// \param rhs The RHS table.
|
||||
///
|
||||
/// \returns True if the tables did not contain the same keys and values.
|
||||
friend bool operator != (const table& lhs, const table& rhs) noexcept;
|
||||
|
||||
template <typename Char>
|
||||
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
|
||||
};
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_VTABLE_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,186 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_table.h"
|
||||
#include "toml_node_view.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_SUGGEST_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table(impl::table_init_pair* pairs, size_t count) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
values.insert_or_assign(
|
||||
std::move(pairs[i].key),
|
||||
std::move(pairs[i].value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table() noexcept {}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table(table&& other) noexcept
|
||||
: node{ std::move(other) },
|
||||
values{ std::move(other.values) },
|
||||
inline_{ other.inline_ }
|
||||
{}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table& table::operator = (table&& rhs) noexcept
|
||||
{
|
||||
node::operator=(std::move(rhs));
|
||||
values = std::move(rhs.values);
|
||||
inline_ = rhs.inline_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) node_type table::type() const noexcept { return node_type::table; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_table() const noexcept { return true; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_array() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_value() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) const table* table::as_table() const noexcept { return this; }
|
||||
TOML_MEMBER_ATTR(const) table* table::as_table() noexcept { return this; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) bool table::is_inline() const noexcept { return inline_; }
|
||||
TOML_EXTERNAL_LINKAGE void table::is_inline(bool val) noexcept { inline_ = val; }
|
||||
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { values.begin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { values.end() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { values.cbegin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { values.cend() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { values.begin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { values.end() }; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return values.empty(); }
|
||||
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return values.size(); }
|
||||
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { values.clear(); }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<node> table::operator[] (string_view key) noexcept
|
||||
{
|
||||
return { this->get(key) };
|
||||
}
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<const node> table::operator[] (string_view key) const noexcept
|
||||
{
|
||||
return { this->get(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(iterator pos) noexcept
|
||||
{
|
||||
return { values.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(const_iterator pos) noexcept
|
||||
{
|
||||
return { values.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(const_iterator first, const_iterator last) noexcept
|
||||
{
|
||||
return { values.erase(first.raw_, last.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::erase(string_view key) noexcept
|
||||
{
|
||||
if (auto it = values.find(key); it != values.end())
|
||||
{
|
||||
values.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node* table::get(string_view key) noexcept
|
||||
{
|
||||
return do_get(values, key);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const node* table::get(string_view key) const noexcept
|
||||
{
|
||||
return do_get(values, key);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::find(string_view key) noexcept
|
||||
{
|
||||
return { values.find(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::const_iterator table::find(string_view key) const noexcept
|
||||
{
|
||||
return { values.find(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::contains(string_view key) const noexcept
|
||||
{
|
||||
return do_contains(values, key);
|
||||
}
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator == (const table& lhs, const table& rhs) noexcept
|
||||
{
|
||||
if (&lhs == &rhs)
|
||||
return true;
|
||||
if (lhs.values.size() != rhs.values.size())
|
||||
return false;
|
||||
|
||||
for (auto l = lhs.values.begin(), r = rhs.values.begin(), e = lhs.values.end(); l != e; l++, r++)
|
||||
{
|
||||
if (l->first != r->first)
|
||||
return false;
|
||||
|
||||
const auto lhs_type = l->second->type();
|
||||
const node& rhs_ = *r->second;
|
||||
const auto rhs_type = rhs_.type();
|
||||
if (lhs_type != rhs_type)
|
||||
return false;
|
||||
|
||||
const bool equal = l->second->visit([&](const auto& lhs_) noexcept
|
||||
{
|
||||
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
|
||||
});
|
||||
if (!equal)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_API
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator != (const table& lhs, const table& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_SUGGEST_WARNINGS
|
|
@ -0,0 +1,254 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de> (utf8_decoder)
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_utf8_generated.h"
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename... T>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_match(char32_t codepoint, T... vals) noexcept
|
||||
{
|
||||
static_assert((std::is_same_v<char32_t, T> && ...));
|
||||
return ((codepoint == vals) || ...);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint == U'\t' || codepoint == U' ';
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_unicode_whitespace(char32_t codepoint) noexcept
|
||||
{
|
||||
// see: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
// (characters that don't say "is a line-break")
|
||||
|
||||
return codepoint == U'\u00A0' // no-break space
|
||||
|| codepoint == U'\u1680' // ogham space mark
|
||||
|| (codepoint >= U'\u2000' && codepoint <= U'\u200A') // em quad -> hair space
|
||||
|| codepoint == U'\u202F' // narrow no-break space
|
||||
|| codepoint == U'\u205F' // medium mathematical space
|
||||
|| codepoint == U'\u3000' // ideographic space
|
||||
;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_whitespace(char32_t codepoint) noexcept
|
||||
{
|
||||
return is_ascii_whitespace(codepoint) || is_unicode_whitespace(codepoint);
|
||||
}
|
||||
|
||||
template <bool IncludeCarriageReturn = true>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_ascii_line_break(char32_t codepoint) noexcept
|
||||
{
|
||||
constexpr auto low_range_end = IncludeCarriageReturn ? U'\r' : U'\f';
|
||||
return (codepoint >= U'\n' && codepoint <= low_range_end);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_unicode_line_break(char32_t codepoint) noexcept
|
||||
{
|
||||
// see https://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
// (characters that say "is a line-break")
|
||||
|
||||
return codepoint == U'\u0085' // next line
|
||||
|| codepoint == U'\u2028' // line separator
|
||||
|| codepoint == U'\u2029' // paragraph separator
|
||||
;
|
||||
}
|
||||
|
||||
template <bool IncludeCarriageReturn = true>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_line_break(char32_t codepoint) noexcept
|
||||
{
|
||||
return is_ascii_line_break<IncludeCarriageReturn>(codepoint) || is_unicode_line_break(codepoint);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_string_delimiter(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint == U'"' || codepoint == U'\'';
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_ascii_letter(char32_t codepoint) noexcept
|
||||
{
|
||||
return (codepoint >= U'a' && codepoint <= U'z')
|
||||
|| (codepoint >= U'A' && codepoint <= U'Z');
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_binary_digit(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint == U'0' || codepoint == U'1';
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_octal_digit(char32_t codepoint) noexcept
|
||||
{
|
||||
return (codepoint >= U'0' && codepoint <= U'7');
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_decimal_digit(char32_t codepoint) noexcept
|
||||
{
|
||||
return (codepoint >= U'0' && codepoint <= U'9');
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr std::uint_least32_t hex_to_dec(const T codepoint) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<remove_cvref_t<T>, std::uint_least32_t>)
|
||||
return codepoint >= 0x41u // >= 'A'
|
||||
? 10u + (codepoint | 0x20u) - 0x61u // - 'a'
|
||||
: codepoint - 0x30u // - '0'
|
||||
;
|
||||
else
|
||||
return hex_to_dec(static_cast<std::uint_least32_t>(codepoint));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_bare_key_character(char32_t codepoint) noexcept
|
||||
{
|
||||
return is_ascii_letter(codepoint)
|
||||
|| is_decimal_digit(codepoint)
|
||||
|| codepoint == U'-'
|
||||
|| codepoint == U'_'
|
||||
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
|
||||
|| codepoint == U'+'
|
||||
|| is_unicode_letter(codepoint)
|
||||
|| is_unicode_number(codepoint)
|
||||
|| is_unicode_combining_mark(codepoint)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_value_terminator(char32_t codepoint) noexcept
|
||||
{
|
||||
return is_ascii_line_break(codepoint)
|
||||
|| is_ascii_whitespace(codepoint)
|
||||
|| codepoint == U']'
|
||||
|| codepoint == U'}'
|
||||
|| codepoint == U','
|
||||
|| codepoint == U'#'
|
||||
|| is_unicode_line_break(codepoint)
|
||||
|| is_unicode_whitespace(codepoint)
|
||||
;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_control_character(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint <= U'\u001F' || codepoint == U'\u007F';
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_nontab_control_character(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint <= U'\u0008'
|
||||
|| (codepoint >= U'\u000A' && codepoint <= U'\u001F')
|
||||
|| codepoint == U'\u007F';
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr bool is_unicode_surrogate(char32_t codepoint) noexcept
|
||||
{
|
||||
return codepoint >= 0xD800u && codepoint <= 0xDFFF;
|
||||
}
|
||||
|
||||
struct utf8_decoder final
|
||||
{
|
||||
uint_least32_t state{};
|
||||
char32_t codepoint{};
|
||||
|
||||
static constexpr uint8_t state_table[]
|
||||
{
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
|
||||
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
||||
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
||||
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
||||
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
||||
12,36,12,12,12,12,12,12,12,12,12,12
|
||||
};
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool error() const noexcept
|
||||
{
|
||||
return state == uint_least32_t{ 12u };
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool has_code_point() const noexcept
|
||||
{
|
||||
return state == uint_least32_t{};
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool needs_more_input() const noexcept
|
||||
{
|
||||
return state > uint_least32_t{} && state != uint_least32_t{ 12u };
|
||||
}
|
||||
|
||||
constexpr void operator () (uint8_t byte) noexcept
|
||||
{
|
||||
TOML_ASSERT(!error());
|
||||
|
||||
const auto type = state_table[byte];
|
||||
|
||||
codepoint = static_cast<char32_t>(
|
||||
has_code_point()
|
||||
? (uint_least32_t{ 255u } >> type) & byte
|
||||
: (byte & uint_least32_t{ 63u }) | (static_cast<uint_least32_t>(codepoint) << 6)
|
||||
);
|
||||
|
||||
state = state_table[state + uint_least32_t{ 256u } + type];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,756 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
//#-----
|
||||
//# this file was generated by generate_unicode_functions.py - do not modify it directly
|
||||
|
||||
#pragma once
|
||||
#include "toml_preprocessor.h"
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
//# Returns true if a codepoint matches any of:
|
||||
//# 0 - 9, A - F, a - f
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_hexadecimal_digit(char32_t cp) noexcept
|
||||
{
|
||||
using ui64 = std::uint_least64_t;
|
||||
|
||||
return cp >= U'0' && cp <= U'f' && (1ull << (static_cast<ui64>(cp) - 0x30ull)) & 0x7E0000007E03FFull;
|
||||
}
|
||||
|
||||
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
|
||||
|
||||
//# Returns true if a codepoint belongs to any of these categories:
|
||||
//# Ll, Lm, Lo, Lt, Lu
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_unicode_letter(char32_t cp) noexcept
|
||||
{
|
||||
using ui64 = std::uint_least64_t;
|
||||
using ui32 = std::uint_least32_t;
|
||||
|
||||
if (cp < U'\u00AA' || cp > U'\U00031349')
|
||||
return false;
|
||||
|
||||
const auto child_index_0 = (static_cast<ui64>(cp) - 0xAAull) / 0xC4Bull;
|
||||
if ((1ull << child_index_0) & 0x8A7FFC004001CFA0ull)
|
||||
return true;
|
||||
if ((1ull << child_index_0) & 0x26180C0000ull)
|
||||
return false;
|
||||
switch (child_index_0)
|
||||
{
|
||||
case 0x00: // [0] 00AA - 0CF4
|
||||
{
|
||||
if (cp > U'\u0CF2')
|
||||
return false;
|
||||
TOML_ASSUME(cp >= U'\u00AA');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFDFFFFFC10801ull, 0xFFFFFFFFFFFFDFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x07C000FFF0FFFFFFull, 0x0000000000000014ull, 0x0000000000000000ull, 0xFEFFFFF5D02F37C0ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFEFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00FFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFC09FFFFFFFFFBFull, 0x000000007FFFFFFFull,
|
||||
0xFFFFFFC000000000ull, 0xFFC00000000001E1ull, 0x00000001FFFFFFFFull, 0xFFFFFFFFFFFFFFB0ull,
|
||||
0x18000BFFFFFFFFFFull, 0xFFFFFF4000270030ull, 0xFFFFFFF80000003Full, 0x0FFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFF00000080ull, 0x44010FFFFFC10C01ull, 0xFFC07FFFFFC00000ull, 0xFFC0000000000001ull,
|
||||
0x000000003FFFF7FFull, 0xFFFFFFFFFC000000ull, 0x00FFC0400008FFFFull, 0x7FFFFE67F87FFF80ull,
|
||||
0x00EC00100008F17Full, 0x7FFFFE61F80400C0ull, 0x001780000000DB7Full, 0x7FFFFEEFF8000700ull,
|
||||
0x00C000400008FB7Full, 0x7FFFFE67F8008000ull, 0x00EC00000008FB7Full, 0xC6358F71FA000080ull,
|
||||
0x000000400000FFF1ull, 0x7FFFFF77F8000000ull, 0x00C1C0000008FFFFull, 0x7FFFFF77F8400000ull,
|
||||
0x00D000000008FBFFull, 0x0000000000000180ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xAAull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xAAull) % 0x40ull));
|
||||
//# chunk summary: 1922 codepoints from 124 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x01: // [1] 0CF5 - 193F
|
||||
{
|
||||
if (cp < U'\u0D04' || cp > U'\u191E')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x027FFFFFFFFFDDFFull, 0x0FC0000038070400ull, 0xF2FFBFFFFFC7FFFEull, 0xE000000000000007ull,
|
||||
0xF000DFFFFFFFFFFFull, 0x6000000000000007ull, 0xF200DFFAFFFFFF7Dull, 0x100000000F000005ull,
|
||||
0xF000000000000000ull, 0x000001FFFFFFFFEFull, 0x00000000000001F0ull, 0xF000000000000000ull,
|
||||
0x0800007FFFFFFFFFull, 0x3FFE1C0623C3F000ull, 0xFFFFFFFFF0000400ull, 0xFF7FFFFFFFFFF20Bull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFF3D7F3DFull, 0xD7F3DFFFFFFFF3DFull, 0xFFFFFFFFFFF7FFF3ull,
|
||||
0xFFFFFFFFFFF3DFFFull, 0xF0000000007FFFFFull, 0xFFFFFFFFF0000FFFull, 0xE3F3FFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xEFFFF9FFFFFFFFFFull, 0xFFFFFFFFF07FFFFFull, 0xF01FE07FFFFFFFFFull,
|
||||
0xF0003FFFF0003DFFull, 0xF0001DFFF0003FFFull, 0x0000FFFFFFFFFFFFull, 0x0000000001080000ull,
|
||||
0xFFFFFFFFF0000000ull, 0xF01FFFFFFFFFFFFFull, 0xFFFFF05FFFFFFFF9ull, 0xF003FFFFFFFFFFFFull,
|
||||
0x0000000007FFFFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xD04ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xD04ull) % 0x40ull));
|
||||
//# chunk summary: 2239 codepoints from 83 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x02: // [2] 1940 - 258A
|
||||
{
|
||||
if (cp < U'\u1950' || cp > U'\u2184')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFF001F3FFFFFFFull, 0x03FFFFFF0FFFFFFFull, 0xFFFF000000000000ull, 0xFFFFFFFFFFFF007Full,
|
||||
0x000000000000001Full, 0x0000000000800000ull, 0xFFE0000000000000ull, 0x0FE0000FFFFFFFFFull,
|
||||
0xFFF8000000000000ull, 0xFFFFFC00C001FFFFull, 0xFFFF0000003FFFFFull, 0xE0000000000FFFFFull,
|
||||
0x01FF3FFFFFFFFC00ull, 0x0000E7FFFFFFFFFFull, 0xFFFF046FDE000000ull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x0000FFFFFFFFFFFFull, 0xFFFF000000000000ull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x3F3FFFFFFFFF3F3Full,
|
||||
0xFFFF3FFFFFFFAAFFull, 0x1FDC5FDFFFFFFFFFull, 0x00001FDC1FFF0FCFull, 0x0000000000000000ull,
|
||||
0x0000800200000000ull, 0x0000000000001FFFull, 0xFC84000000000000ull, 0x43E0F3FFBD503E2Full,
|
||||
0x0018000000000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x1950ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x1950ull) % 0x40ull));
|
||||
//# chunk summary: 1184 codepoints from 59 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x03: // [3] 258B - 31D5
|
||||
{
|
||||
if (cp < U'\u2C00' || cp > U'\u31BF')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFF7FFFFFFFFFFFull, 0xFFFFFFFF7FFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x000C781FFFFFFFFFull,
|
||||
0xFFFF20BFFFFFFFFFull, 0x000080FFFFFFFFFFull, 0x7F7F7F7F007FFFFFull, 0x000000007F7F7F7Full,
|
||||
0x0000800000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x183E000000000060ull, 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFEE07FFFFFull, 0xF7FFFFFFFFFFFFFFull,
|
||||
0xFFFEFFFFFFFFFFE0ull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00007FFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x2C00ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 771 codepoints from 30 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x04: return (cp >= U'\u31F0' && cp <= U'\u31FF') || (cp >= U'\u3400' && cp <= U'\u3E20');
|
||||
case 0x06: return (cp >= U'\u4A6C' && cp <= U'\u4DBE') || (cp >= U'\u4E00' && cp <= U'\u56B6');
|
||||
case 0x0C: return (cp >= U'\u942E' && cp <= U'\u9FFB') || (cp >= U'\uA000' && cp <= U'\uA078');
|
||||
case 0x0D: // [13] A079 - ACC3
|
||||
{
|
||||
TOML_ASSUME(cp >= U'\uA079' && cp <= U'\uACC3');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x00000000000FFFFFull, 0xFFFFFFFFFF800000ull, 0xFFFFFFFFFFFFFF9Full, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x0006007FFF8FFFFFull, 0x003FFFFFFFFFFF80ull,
|
||||
0xFFFFFF9FFFFFFFC0ull, 0x00001FFFFFFFFFFFull, 0xFFFFFE7FC0000000ull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFCFFFFull, 0xF00000000003FE7Full, 0x000003FFFFFBDDFFull, 0x07FFFFFFFFFFFF80ull,
|
||||
0x07FFFFFFFFFFFE00ull, 0x7E00000000000000ull, 0xFF801FFFFFFE0034ull, 0xFFFFFF8000003FFFull,
|
||||
0x03FFFFFFFFFFF80Full, 0x007FEF8000400000ull, 0x0000FFFFFFFFFFBEull, 0x3FFFFF800007FB80ull,
|
||||
0x317FFFFFFFFFFFE2ull, 0x0E03FF9C0000029Full, 0xFFBFBF803F3F3F00ull, 0xFF81FFFBFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x000003FFFFFFFFFFull, 0xFFFFFFFFFFFFFF80ull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x00000000000007FFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xA079ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xA079ull) % 0x40ull));
|
||||
//# chunk summary: 2554 codepoints from 52 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x11: return (cp >= U'\uD1A5' && cp <= U'\uD7A2') || (cp >= U'\uD7B0' && cp <= U'\uD7C6')
|
||||
|| (cp >= U'\uD7CB' && cp <= U'\uD7FB');
|
||||
case 0x14: // [20] F686 - 102D0
|
||||
{
|
||||
if (cp < U'\uF900')
|
||||
return false;
|
||||
TOML_ASSUME(cp <= U'\U000102D0');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFF3FFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x0000000003FFFFFFull,
|
||||
0x5F7FFDFFA0F8007Full, 0xFFFFFFFFFFFFFFDBull, 0x0003FFFFFFFFFFFFull, 0xFFFFFFFFFFF80000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x3FFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFF0000ull, 0xFFFFFFFFFFFCFFFFull, 0x0FFF0000000000FFull,
|
||||
0x0000000000000000ull, 0xFFDF000000000000ull, 0xFFFFFFFFFFFFFFFFull, 0x1FFFFFFFFFFFFFFFull,
|
||||
0x07FFFFFE00000000ull, 0xFFFFFFC007FFFFFEull, 0x7FFFFFFFFFFFFFFFull, 0x000000001CFCFCFCull,
|
||||
0xB7FFFF7FFFFFEFFFull, 0x000000003FFF3FFFull, 0xFFFFFFFFFFFFFFFFull, 0x07FFFFFFFFFFFFFFull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xFFFFFFFF1FFFFFFFull, 0x000000000001FFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xF900ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 1710 codepoints from 34 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x15: // [21] 102D1 - 10F1B
|
||||
{
|
||||
if (cp < U'\U00010300')
|
||||
return false;
|
||||
TOML_ASSUME(cp <= U'\U00010F1B');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFE000FFFFFFFFull, 0x003FFFFFFFFF03FDull, 0xFFFFFFFF3FFFFFFFull, 0x000000000000FF0Full,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFF00003FFFFFFFull, 0x0FFFFFFFFF0FFFFFull,
|
||||
0xFFFF00FFFFFFFFFFull, 0x0000000FFFFFFFFFull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x007FFFFFFFFFFFFFull, 0x000000FF003FFFFFull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x91BFFFFFFFFFFD3Full, 0x007FFFFF003FFFFFull, 0x000000007FFFFFFFull, 0x0037FFFF00000000ull,
|
||||
0x03FFFFFF003FFFFFull, 0x0000000000000000ull, 0xC0FFFFFFFFFFFFFFull, 0x0000000000000000ull,
|
||||
0x003FFFFFFEEF0001ull, 0x1FFFFFFF00000000ull, 0x000000001FFFFFFFull, 0x0000001FFFFFFEFFull,
|
||||
0x003FFFFFFFFFFFFFull, 0x0007FFFF003FFFFFull, 0x000000000003FFFFull, 0x0000000000000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x00000000000001FFull, 0x0007FFFFFFFFFFFFull, 0x0007FFFFFFFFFFFFull,
|
||||
0x0000000FFFFFFFFFull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x000303FFFFFFFFFFull, 0x0000000000000000ull,
|
||||
0x000000000FFFFFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x10300ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 1620 codepoints from 48 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x16: // [22] 10F1C - 11B66
|
||||
{
|
||||
if (cp > U'\U00011AF8')
|
||||
return false;
|
||||
TOML_ASSUME(cp >= U'\U00010F1C');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x000003FFFFF00801ull, 0x0000000000000000ull, 0x000001FFFFF00000ull, 0xFFFFFF8007FFFFF0ull,
|
||||
0x000000000FFFFFFFull, 0xFFFFFF8000000000ull, 0xFFF00000000FFFFFull, 0xFFFFFF8000001FFFull,
|
||||
0xFFF00900000007FFull, 0xFFFFFF80047FFFFFull, 0x400001E0007FFFFFull, 0xFFBFFFF000000001ull,
|
||||
0x000000000000FFFFull, 0xFFFBD7F000000000ull, 0xFFFFFFFFFFF01FFBull, 0xFF99FE0000000007ull,
|
||||
0x001000023EDFDFFFull, 0x000000000000003Eull, 0x0000000000000000ull, 0xFFFFFFF000000000ull,
|
||||
0x0000780001FFFFFFull, 0xFFFFFFF000000038ull, 0x00000B00000FFFFFull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0xFFFFFFF000000000ull, 0xF00000000007FFFFull, 0xFFFFFFF000000000ull,
|
||||
0x00000100000FFFFFull, 0xFFFFFFF000000000ull, 0x0000000010007FFFull, 0x7FFFFFF000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0xFFFFFFF000000000ull,
|
||||
0x000000000000FFFFull, 0x0000000000000000ull, 0xFFFFFFFFFFFFFFF0ull, 0xF6FF27F80000000Full,
|
||||
0x00000028000FFFFFull, 0x0000000000000000ull, 0x001FFFFFFFFFCFF0ull, 0xFFFF8010000000A0ull,
|
||||
0x00100000407FFFFFull, 0x00003FFFFFFFFFFFull, 0xFFFFFFF000000002ull, 0x000000001FFFFFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x10F1Cull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x10F1Cull) % 0x40ull));
|
||||
//# chunk summary: 1130 codepoints from 67 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x17: // [23] 11B67 - 127B1
|
||||
{
|
||||
if (cp < U'\U00011C00' || cp > U'\U00012543')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00007FFFFFFFFDFFull, 0xFFFC000000000001ull, 0x000000000000FFFFull, 0x0000000000000000ull,
|
||||
0x0001FFFFFFFFFB7Full, 0xFFFFFDBF00000040ull, 0x00000000010003FFull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0007FFFF00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0001000000000000ull, 0x0000000000000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x0000000003FFFFFFull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x000000000000000Full,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x11C00ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 1304 codepoints from 16 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x18: return cp >= U'\U00013000';
|
||||
case 0x19: return cp <= U'\U0001342E';
|
||||
case 0x1A: return cp >= U'\U00014400' && cp <= U'\U00014646';
|
||||
case 0x1D: // [29] 16529 - 17173
|
||||
{
|
||||
if (cp < U'\U00016800')
|
||||
return false;
|
||||
TOML_ASSUME(cp <= U'\U00017173');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x01FFFFFFFFFFFFFFull, 0x000000007FFFFFFFull, 0x0000000000000000ull, 0x00003FFFFFFF0000ull,
|
||||
0x0000FFFFFFFFFFFFull, 0xE0FFFFF80000000Full, 0x000000000000FFFFull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0xFFFFFFFFFFFFFFFFull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x00000000000107FFull, 0x00000000FFF80000ull, 0x0000000B00000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x000FFFFFFFFFFFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x16800ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 1250 codepoints from 14 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x1F: return (cp >= U'\U00017DBF' && cp <= U'\U000187F6') || (cp >= U'\U00018800' && cp <= U'\U00018A09');
|
||||
case 0x20: return (cp >= U'\U00018A0A' && cp <= U'\U00018CD5') || (cp >= U'\U00018D00' && cp <= U'\U00018D07');
|
||||
case 0x23: // [35] 1AEEB - 1BB35
|
||||
{
|
||||
if (cp < U'\U0001B000' || cp > U'\U0001B2FB')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0x000000007FFFFFFFull, 0xFFFF00F000070000ull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x0FFFFFFFFFFFFFFFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x1B000ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 690 codepoints from 4 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x24: // [36] 1BB36 - 1C780
|
||||
{
|
||||
if (cp < U'\U0001BC00' || cp > U'\U0001BC99')
|
||||
return false;
|
||||
|
||||
switch ((static_cast<ui64>(cp) - 0x1BC00ull) / 0x40ull)
|
||||
{
|
||||
case 0x01: return cp <= U'\U0001BC7C'
|
||||
&& (1ull << (static_cast<ui64>(cp) - 0x1BC40ull)) & 0x1FFF07FFFFFFFFFFull;
|
||||
case 0x02: return (1u << (static_cast<ui32>(cp) - 0x1BC80u)) & 0x3FF01FFu;
|
||||
default: return true;
|
||||
}
|
||||
//# chunk summary: 139 codepoints from 4 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x26: // [38] 1D3CC - 1E016
|
||||
{
|
||||
if (cp < U'\U0001D400' || cp > U'\U0001D7CB')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFDFFFFFull, 0xEBFFDE64DFFFFFFFull, 0xFFFFFFFFFFFFFFEFull,
|
||||
0x7BFFFFFFDFDFE7BFull, 0xFFFFFFFFFFFDFC5Full, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFF3FFFFFFFFFull, 0xF7FFFFFFF7FFFFFDull,
|
||||
0xFFDFFFFFFFDFFFFFull, 0xFFFF7FFFFFFF7FFFull, 0xFFFFFDFFFFFFFDFFull, 0x0000000000000FF7ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x1D400ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 936 codepoints from 30 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x27: // [39] 1E017 - 1EC61
|
||||
{
|
||||
if (cp < U'\U0001E100' || cp > U'\U0001E94B')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x3F801FFFFFFFFFFFull, 0x0000000000004000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x00000FFFFFFFFFFFull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0x000000000000001Full,
|
||||
0xFFFFFFFFFFFFFFFFull, 0x000000000000080Full,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x1E100ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 363 codepoints from 7 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x28: // [40] 1EC62 - 1F8AC
|
||||
{
|
||||
if (cp < U'\U0001EE00' || cp > U'\U0001EEBB')
|
||||
return false;
|
||||
|
||||
switch ((static_cast<ui64>(cp) - 0x1EE00ull) / 0x40ull)
|
||||
{
|
||||
case 0x00: return cp <= U'\U0001EE3B'
|
||||
&& (1ull << (static_cast<ui64>(cp) - 0x1EE00ull)) & 0xAF7FE96FFFFFFEFull;
|
||||
case 0x01: return cp >= U'\U0001EE42' && cp <= U'\U0001EE7E'
|
||||
&& (1ull << (static_cast<ui64>(cp) - 0x1EE42ull)) & 0x17BDFDE5AAA5BAA1ull;
|
||||
case 0x02: return (1ull << (static_cast<ui64>(cp) - 0x1EE80ull)) & 0xFFFFBEE0FFFFBFFull;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
//# chunk summary: 141 codepoints from 33 ranges (spanning a search area of 3147)
|
||||
}
|
||||
case 0x29: return cp >= U'\U00020000';
|
||||
case 0x37: return (cp >= U'\U0002A4C7' && cp <= U'\U0002A6DC') || (cp >= U'\U0002A700' && cp <= U'\U0002B111');
|
||||
case 0x38: return (cp >= U'\U0002B112' && cp <= U'\U0002B733') || (cp >= U'\U0002B740' && cp <= U'\U0002B81C')
|
||||
|| (cp >= U'\U0002B820' && cp <= U'\U0002BD5C');
|
||||
case 0x3A: return (cp >= U'\U0002C9A8' && cp <= U'\U0002CEA0') || (cp >= U'\U0002CEB0' && cp <= U'\U0002D5F2');
|
||||
case 0x3C: return cp <= U'\U0002EBDF';
|
||||
case 0x3D: return cp >= U'\U0002F800' && cp <= U'\U0002FA1D';
|
||||
case 0x3E: return cp >= U'\U00030000';
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
//# chunk summary: 131178 codepoints from 620 ranges (spanning a search area of 201376)
|
||||
}
|
||||
|
||||
//# Returns true if a codepoint belongs to any of these categories:
|
||||
//# Nd, Nl
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_unicode_number(char32_t cp) noexcept
|
||||
{
|
||||
using ui64 = std::uint_least64_t;
|
||||
|
||||
if (cp < U'\u0660' || cp > U'\U0001FBF9')
|
||||
return false;
|
||||
|
||||
const auto child_index_0 = (static_cast<ui64>(cp) - 0x660ull) / 0x7D7ull;
|
||||
if ((1ull << child_index_0) & 0x47FFDFE07FCFFFD0ull)
|
||||
return false;
|
||||
switch (child_index_0)
|
||||
{
|
||||
case 0x00: // [0] 0660 - 0E36
|
||||
{
|
||||
if (cp > U'\u0DEF')
|
||||
return false;
|
||||
TOML_ASSUME(cp >= U'\u0660');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00000000000003FFull, 0x0000000000000000ull, 0x0000000003FF0000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x000003FF00000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x000000000000FFC0ull, 0x0000000000000000ull, 0x000000000000FFC0ull, 0x0000000000000000ull,
|
||||
0x000000000000FFC0ull, 0x0000000000000000ull, 0x000000000000FFC0ull, 0x0000000000000000ull,
|
||||
0x000000000000FFC0ull, 0x0000000000000000ull, 0x000000000000FFC0ull, 0x0000000000000000ull,
|
||||
0x000000000000FFC0ull, 0x0000000000000000ull, 0x000000000000FFC0ull, 0x0000000000000000ull,
|
||||
0x000000000000FFC0ull, 0x0000000000000000ull, 0x000000000000FFC0ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x660ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x660ull) % 0x40ull));
|
||||
//# chunk summary: 130 codepoints from 13 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x01: // [1] 0E37 - 160D
|
||||
{
|
||||
if (cp < U'\u0E50' || cp > U'\u1099')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00000000000003FFull, 0x0000000000000000ull, 0x00000000000003FFull, 0x0000000003FF0000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x03FF000000000000ull,
|
||||
0x0000000000000000ull, 0x00000000000003FFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xE50ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xE50ull) % 0x40ull));
|
||||
//# chunk summary: 50 codepoints from 5 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x02: // [2] 160E - 1DE4
|
||||
{
|
||||
if (cp < U'\u16EE' || cp > U'\u1C59')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x0000000000000007ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0FFC000000000000ull,
|
||||
0x00000FFC00000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x00000003FF000000ull, 0x0000000000000000ull, 0x00000FFC00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x00000FFC0FFC0000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x00000FFC00000000ull, 0x0000000000000000ull, 0x0000000000000FFCull,
|
||||
0x0000000000000000ull, 0x00000FFC0FFC0000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x16EEull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x16EEull) % 0x40ull));
|
||||
//# chunk summary: 103 codepoints from 11 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x03: return cp >= U'\u2160' && cp <= U'\u2188'
|
||||
&& (1ull << (static_cast<ui64>(cp) - 0x2160ull)) & 0x1E7FFFFFFFFull;
|
||||
case 0x05: return cp >= U'\u3007' && cp <= U'\u303A'
|
||||
&& (1ull << (static_cast<ui64>(cp) - 0x3007ull)) & 0xE0007FC000001ull;
|
||||
case 0x14: // [20] A32C - AB02
|
||||
{
|
||||
if (cp < U'\uA620' || cp > U'\uAA59')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00000000000003FFull, 0x0000000000000000ull, 0x0000000000000000ull, 0x000000000000FFC0ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x03FF000000000000ull, 0x000003FF00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x03FF000000000000ull, 0x0000000003FF0000ull,
|
||||
0x03FF000000000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xA620ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xA620ull) % 0x40ull));
|
||||
//# chunk summary: 70 codepoints from 7 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x15: return cp >= U'\uABF0' && cp <= U'\uABF9';
|
||||
case 0x1F: return cp >= U'\uFF10' && cp <= U'\uFF19';
|
||||
case 0x20: // [32] 10140 - 10916
|
||||
{
|
||||
if (cp > U'\U000104A9')
|
||||
return false;
|
||||
TOML_ASSUME(cp >= U'\U00010140');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x001FFFFFFFFFFFFFull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000402ull, 0x0000000000000000ull, 0x00000000003E0000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x000003FF00000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x10140ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 70 codepoints from 5 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x21: return (cp >= U'\U00010D30' && cp <= U'\U00010D39') || (cp >= U'\U00011066' && cp <= U'\U0001106F');
|
||||
case 0x22: // [34] 110EE - 118C4
|
||||
{
|
||||
if (cp < U'\U000110F0' || cp > U'\U00011739')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00000000000003FFull, 0x000000000000FFC0ull, 0x0000000000000000ull, 0x000003FF00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x00000000000003FFull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x000003FF00000000ull, 0x0000000000000000ull, 0x000003FF00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x000003FF00000000ull, 0x0000000000000000ull, 0x0000000003FF0000ull,
|
||||
0x0000000000000000ull, 0x00000000000003FFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x110F0ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x110F0ull) % 0x40ull));
|
||||
//# chunk summary: 90 codepoints from 9 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x23: // [35] 118C5 - 1209B
|
||||
{
|
||||
if (cp < U'\U000118E0' || cp > U'\U00011DA9')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x00000000000003FFull, 0x03FF000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x03FF000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x03FF000000000000ull, 0x0000000000000000ull, 0x00000000000003FFull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x118E0ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x118E0ull) % 0x40ull));
|
||||
//# chunk summary: 50 codepoints from 5 ranges (spanning a search area of 2007)
|
||||
}
|
||||
case 0x24: return cp >= U'\U00012400' && cp <= U'\U0001246E';
|
||||
case 0x2D: return (cp >= U'\U00016A60' && cp <= U'\U00016A69') || (cp >= U'\U00016B50' && cp <= U'\U00016B59');
|
||||
case 0x3B: return cp >= U'\U0001D7CE' && cp <= U'\U0001D7FF';
|
||||
case 0x3C: return (cp >= U'\U0001E140' && cp <= U'\U0001E149') || (cp >= U'\U0001E2F0' && cp <= U'\U0001E2F9');
|
||||
case 0x3D: return cp >= U'\U0001E950' && cp <= U'\U0001E959';
|
||||
case 0x3F: return cp >= U'\U0001FBF0';
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
//# chunk summary: 876 codepoints from 72 ranges (spanning a search area of 128410)
|
||||
}
|
||||
|
||||
//# Returns true if a codepoint belongs to any of these categories:
|
||||
//# Mn, Mc
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
constexpr bool is_unicode_combining_mark(char32_t cp) noexcept
|
||||
{
|
||||
using ui64 = std::uint_least64_t;
|
||||
|
||||
if (cp < U'\u0300' || cp > U'\U000E01EF')
|
||||
return false;
|
||||
|
||||
const auto child_index_0 = (static_cast<ui64>(cp) - 0x300ull) / 0x37FCull;
|
||||
if ((1ull << child_index_0) & 0x7FFFFFFFFFFFFE02ull)
|
||||
return false;
|
||||
switch (child_index_0)
|
||||
{
|
||||
case 0x00: // [0] 0300 - 3AFB
|
||||
{
|
||||
if (cp > U'\u309A')
|
||||
return false;
|
||||
TOML_ASSUME(cp >= U'\u0300');
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0xFFFFFFFFFFFFFFFFull, 0x0000FFFFFFFFFFFFull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x00000000000000F8ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xBFFFFFFFFFFE0000ull, 0x00000000000000B6ull,
|
||||
0x0000000007FF0000ull, 0x00010000FFFFF800ull, 0x0000000000000000ull, 0x00003D9F9FC00000ull,
|
||||
0xFFFF000000020000ull, 0x00000000000007FFull, 0x0001FFC000000000ull, 0x200FF80000000000ull,
|
||||
0x00003EEFFBC00000ull, 0x000000000E000000ull, 0x0000000000000000ull, 0xFFFFFFFBFFF80000ull,
|
||||
0xDC0000000000000Full, 0x0000000C00FEFFFFull, 0xD00000000000000Eull, 0x4000000C0080399Full,
|
||||
0xD00000000000000Eull, 0x0023000000023987ull, 0xD00000000000000Eull, 0xFC00000C00003BBFull,
|
||||
0xD00000000000000Eull, 0x0000000C00E0399Full, 0xC000000000000004ull, 0x0000000000803DC7ull,
|
||||
0xC00000000000001Full, 0x0000000C00603DDFull, 0xD00000000000000Eull, 0x0000000C00603DDFull,
|
||||
0xD80000000000000Full, 0x0000000C00803DDFull, 0x000000000000000Eull, 0x000C0000FF5F8400ull,
|
||||
0x07F2000000000000ull, 0x0000000000007F80ull, 0x1FF2000000000000ull, 0x0000000000003F00ull,
|
||||
0xC2A0000003000000ull, 0xFFFE000000000000ull, 0x1FFFFFFFFEFFE0DFull, 0x0000000000000040ull,
|
||||
0x7FFFF80000000000ull, 0x001E3F9DC3C00000ull, 0x000000003C00BFFCull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x00000000E0000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x001C0000001C0000ull, 0x000C0000000C0000ull, 0xFFF0000000000000ull, 0x00000000200FFFFFull,
|
||||
0x0000000000003800ull, 0x0000000000000000ull, 0x0000020000000060ull, 0x0000000000000000ull,
|
||||
0x0FFF0FFF00000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x000000000F800000ull, 0x9FFFFFFF7FE00000ull, 0xBFFF000000000000ull, 0x0000000000000001ull,
|
||||
0xFFF000000000001Full, 0x000FF8000000001Full, 0x00003FFE00000007ull, 0x000FFFC000000000ull,
|
||||
0x00FFFFF000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x039021FFFFF70000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0xFBFFFFFFFFFFFFFFull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0001FFE21FFF0000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0003800000000000ull,
|
||||
0x0000000000000000ull, 0x8000000000000000ull, 0x0000000000000000ull, 0xFFFFFFFF00000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000FC0000000000ull, 0x0000000000000000ull, 0x0000000006000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x300ull) / 0x40ull]
|
||||
& (0x1ull << (static_cast<ui64>(cp) % 0x40ull));
|
||||
//# chunk summary: 1106 codepoints from 156 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x02: // [2] 72F8 - AAF3
|
||||
{
|
||||
if (cp < U'\uA66F' || cp > U'\uAAEF')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x0001800000007FE1ull, 0x0000000000000000ull, 0x0000000000000006ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x21F0000010880000ull, 0x0000000000000000ull,
|
||||
0x0000000000060000ull, 0xFFFE0000007FFFE0ull, 0x7F80000000010007ull, 0x0000001FFF000000ull,
|
||||
0x00000000001E0000ull, 0x004000000003FFF0ull, 0xFC00000000000000ull, 0x00000000601000FFull,
|
||||
0x0000000000007000ull, 0xF00000000005833Aull, 0x0000000000000001ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xA66Full) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xA66Full) % 0x40ull));
|
||||
//# chunk summary: 137 codepoints from 28 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x03: return cp == U'\uAAF5' || cp == U'\uAAF6' || (cp >= U'\uABE3' && cp <= U'\uABEA') || cp == U'\uABEC'
|
||||
|| cp == U'\uABED';
|
||||
case 0x04: // [4] E2F0 - 11AEB
|
||||
{
|
||||
if (cp < U'\uFB1E' || cp > U'\U00011A99')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x0000000000000001ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0003FFFC00000000ull,
|
||||
0x000000000003FFFCull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000080000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000004ull,
|
||||
0x0000000000000000ull, 0x000000001F000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0003C1B800000000ull,
|
||||
0x000000021C000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000180ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x00000000000003C0ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000006000ull, 0x0000000000000000ull,
|
||||
0x0007FF0000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000001C00000000ull,
|
||||
0x000001FFFC000000ull, 0x0000001E00000000ull, 0x000000001FFC0000ull, 0x0000001C00000000ull,
|
||||
0x00000180007FFE00ull, 0x0000001C00200000ull, 0x00037807FFE00000ull, 0x0000000000000000ull,
|
||||
0x0000000103FFC000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000003C00001FFEull,
|
||||
0x0200E67F60000000ull, 0x00000000007C7F30ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x000001FFFF800000ull, 0x0000000000000001ull, 0x0000003FFFFC0000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xC0000007FCFE0000ull, 0x0000000000000000ull,
|
||||
0x00000007FFFC0000ull, 0x0000000000000000ull, 0x0000000003FFE000ull, 0x8000000000000000ull,
|
||||
0x0000000000003FFFull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x000000001FFFC000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x00000035E6FC0000ull, 0x0000000000000000ull, 0xF3F8000000000000ull, 0x00001FF800000047ull,
|
||||
0x3FF80201EFE00000ull, 0x0FFFF00000000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0xFB1Eull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0xFB1Eull) % 0x40ull));
|
||||
//# chunk summary: 402 codepoints from 63 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x05: // [5] 11AEC - 152E7
|
||||
{
|
||||
if (cp < U'\U00011C2F' || cp > U'\U00011EF6')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x000000000001FEFFull, 0xFDFFFFF800000000ull, 0x00000000000000FFull, 0x0000000000000000ull,
|
||||
0x00000000017F68FCull, 0x000001F6F8000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x00000000000000F0ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x11C2Full) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x11C2Full) % 0x40ull));
|
||||
//# chunk summary: 85 codepoints from 13 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x06: // [6] 152E8 - 18AE3
|
||||
{
|
||||
if (cp < U'\U00016AF0' || cp > U'\U00016FF1')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x000000000000001Full, 0x000000000000007Full, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0xFFFFFFFE80000000ull, 0x0000000780FFFFFFull, 0x0010000000000000ull,
|
||||
0x0000000000000003ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x16AF0ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x16AF0ull) % 0x40ull));
|
||||
//# chunk summary: 75 codepoints from 7 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x07: return cp >= U'\U0001BC9D' && cp <= U'\U0001BC9E';
|
||||
case 0x08: // [8] 1C2E0 - 1FADB
|
||||
{
|
||||
if (cp < U'\U0001D165' || cp > U'\U0001E94A')
|
||||
return false;
|
||||
|
||||
constexpr ui64 bitmask_table_1[] =
|
||||
{
|
||||
0x0000007F3FC03F1Full, 0x00000000000001E0ull, 0x0000000000000000ull, 0x00000000E0000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xFFFFFFFFF8000000ull, 0xFFFFFFFFFFC3FFFFull,
|
||||
0xF7C00000800100FFull, 0x00000000000007FFull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0xDFCFFFFBF8000000ull, 0x000000000000003Eull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x000000000003F800ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000780ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull,
|
||||
0x0000000000000000ull, 0x0003F80000000000ull, 0x0000000000000000ull, 0x0000003F80000000ull,
|
||||
};
|
||||
return bitmask_table_1[(static_cast<ui64>(cp) - 0x1D165ull) / 0x40ull]
|
||||
& (0x1ull << ((static_cast<ui64>(cp) - 0x1D165ull) % 0x40ull));
|
||||
//# chunk summary: 223 codepoints from 21 ranges (spanning a search area of 14332)
|
||||
}
|
||||
case 0x3F: return cp >= U'\U000E0100';
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
//# chunk summary: 2282 codepoints from 293 ranges (spanning a search area of 917232)
|
||||
}
|
||||
|
||||
#endif // TOML_LANG_UNRELEASED
|
||||
} // toml::impl
|
|
@ -0,0 +1,494 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_parse_error.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml::impl
|
||||
{
|
||||
template <typename T>
|
||||
class utf8_byte_stream;
|
||||
|
||||
inline constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
|
||||
|
||||
template <typename Char>
|
||||
class utf8_byte_stream<std::basic_string_view<Char>> final
|
||||
{
|
||||
static_assert(sizeof(Char) == 1_sz);
|
||||
|
||||
private:
|
||||
std::basic_string_view<Char> source;
|
||||
size_t position = {};
|
||||
|
||||
public:
|
||||
explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept
|
||||
: source{ sv }
|
||||
{
|
||||
// trim trailing nulls
|
||||
size_t actual_len = source.length();
|
||||
for (size_t i = actual_len; i --> 0_sz;)
|
||||
{
|
||||
if (source[i] != Char{}) // not '\0'
|
||||
{
|
||||
actual_len = i + 1_sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (source.length() != actual_len) // not '\0'
|
||||
source = source.substr(0_sz, actual_len);
|
||||
|
||||
// skip bom
|
||||
if (source.length() >= 3_sz && memcmp(utf8_byte_order_mark.data(), source.data(), 3_sz) == 0)
|
||||
position += 3_sz;
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool eof() const noexcept
|
||||
{
|
||||
return position >= source.length();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool peek_eof() const noexcept
|
||||
{
|
||||
return eof();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
constexpr bool error() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr unsigned int operator() () noexcept
|
||||
{
|
||||
if (position >= source.length())
|
||||
return 0xFFFFFFFFu;
|
||||
return static_cast<unsigned int>(static_cast<uint8_t>(source[position++]));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
class utf8_byte_stream<std::basic_istream<Char>> final
|
||||
{
|
||||
static_assert(sizeof(Char) == 1_sz);
|
||||
|
||||
private:
|
||||
std::basic_istream<Char>* source;
|
||||
|
||||
public:
|
||||
explicit utf8_byte_stream(std::basic_istream<Char>& stream)
|
||||
: source{ &stream }
|
||||
{
|
||||
if (!source->good()) // eof, fail, bad
|
||||
return;
|
||||
|
||||
const auto initial_pos = source->tellg();
|
||||
Char bom[3];
|
||||
source->read(bom, 3);
|
||||
if (source->bad() || (source->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3_sz) == 0))
|
||||
return;
|
||||
|
||||
source->clear();
|
||||
source->seekg(initial_pos, std::ios::beg);
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool eof() const noexcept
|
||||
{
|
||||
return source->eof();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool peek_eof() const
|
||||
{
|
||||
using stream_traits = typename std::remove_pointer_t<decltype(source)>::traits_type;
|
||||
return eof() || source->peek() == stream_traits::eof();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
bool error() const noexcept
|
||||
{
|
||||
return !(*source);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
unsigned int operator() ()
|
||||
{
|
||||
auto val = source->get();
|
||||
if (val == std::basic_istream<Char>::traits_type::eof())
|
||||
return 0xFFFFFFFFu;
|
||||
return static_cast<unsigned int>(val);
|
||||
}
|
||||
};
|
||||
|
||||
#if TOML_LARGE_FILES
|
||||
TOML_ABI_NAMESPACE_START(impl_lf)
|
||||
#else
|
||||
TOML_ABI_NAMESPACE_START(impl_sf)
|
||||
#endif
|
||||
|
||||
struct utf8_codepoint final
|
||||
{
|
||||
char32_t value;
|
||||
string_char bytes[4];
|
||||
source_position position;
|
||||
|
||||
template <typename Char = string_char>
|
||||
[[nodiscard]]
|
||||
TOML_ALWAYS_INLINE
|
||||
std::basic_string_view<Char> as_view() const noexcept
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Char) == 1,
|
||||
"The string view's underlying character type must be 1 byte in size."
|
||||
);
|
||||
|
||||
return bytes[3]
|
||||
? std::basic_string_view<Char>{ reinterpret_cast<const Char*>(bytes), 4_sz }
|
||||
: std::basic_string_view<Char>{ reinterpret_cast<const Char*>(bytes) };
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(pure)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr operator char32_t& () noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(pure)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr operator const char32_t& () const noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(pure)
|
||||
TOML_ALWAYS_INLINE
|
||||
constexpr const char32_t& operator* () const noexcept
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_trivial_v<utf8_codepoint>);
|
||||
static_assert(std::is_standard_layout_v<utf8_codepoint>);
|
||||
|
||||
TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
|
||||
|
||||
#if TOML_EXCEPTIONS
|
||||
#define TOML_ERROR_CHECK (void)0
|
||||
#define TOML_ERROR throw parse_error
|
||||
TOML_ABI_NAMESPACE_START(impl_ex)
|
||||
#else
|
||||
#define TOML_ERROR_CHECK if (err) return nullptr
|
||||
#define TOML_ERROR err.emplace
|
||||
TOML_ABI_NAMESPACE_START(impl_noex)
|
||||
#endif
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
|
||||
struct TOML_INTERFACE utf8_reader_interface
|
||||
{
|
||||
[[nodiscard]]
|
||||
virtual const source_path_ptr& source_path() const noexcept = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const utf8_codepoint* read_next() = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool peek_eof() const = 0;
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
|
||||
[[nodiscard]]
|
||||
virtual optional<parse_error>&& error() noexcept = 0;
|
||||
|
||||
#endif
|
||||
|
||||
virtual ~utf8_reader_interface() noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TOML_EMPTY_BASES utf8_reader final
|
||||
: public utf8_reader_interface
|
||||
{
|
||||
private:
|
||||
utf8_byte_stream<T> stream;
|
||||
utf8_decoder decoder;
|
||||
utf8_codepoint codepoints[2];
|
||||
size_t cp_idx = 1;
|
||||
uint8_t current_byte_count{};
|
||||
source_path_ptr source_path_;
|
||||
#if !TOML_EXCEPTIONS
|
||||
optional<parse_error> err;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
template <typename U, typename String = std::string_view>
|
||||
explicit utf8_reader(U && source, String&& source_path = {})
|
||||
noexcept(std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
|
||||
: stream{ std::forward<U>(source) }
|
||||
{
|
||||
std::memset(codepoints, 0, sizeof(codepoints));
|
||||
codepoints[0].position = { 1, 1 };
|
||||
codepoints[1].position = { 1, 1 };
|
||||
|
||||
if (!source_path.empty())
|
||||
source_path_ = std::make_shared<const std::string>(std::forward<String>(source_path));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const source_path_ptr& source_path() const noexcept override
|
||||
{
|
||||
return source_path_;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const utf8_codepoint* read_next() override
|
||||
{
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
auto& prev = codepoints[(cp_idx - 1_sz) % 2_sz];
|
||||
|
||||
if (stream.eof())
|
||||
return nullptr;
|
||||
else if (stream.error())
|
||||
TOML_ERROR("An error occurred while reading from the underlying stream", prev.position, source_path_ );
|
||||
else if (decoder.error())
|
||||
TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint8_t next_byte;
|
||||
{
|
||||
unsigned int next_byte_raw{ 0xFFFFFFFFu };
|
||||
if constexpr (noexcept(stream()) || !TOML_EXCEPTIONS)
|
||||
{
|
||||
next_byte_raw = stream();
|
||||
}
|
||||
#if TOML_EXCEPTIONS
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
next_byte_raw = stream();
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
{
|
||||
throw parse_error{ exc.what(), prev.position, source_path_ };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw parse_error{ "An unspecified error occurred", prev.position, source_path_ };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (next_byte_raw >= 256u)
|
||||
{
|
||||
if (stream.eof())
|
||||
{
|
||||
if (decoder.needs_more_input())
|
||||
TOML_ERROR("Encountered EOF during incomplete utf-8 code point sequence",
|
||||
prev.position, source_path_);
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
TOML_ERROR("An error occurred while reading from the underlying stream",
|
||||
prev.position, source_path_);
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
next_byte = static_cast<uint8_t>(next_byte_raw);
|
||||
}
|
||||
|
||||
decoder(next_byte);
|
||||
if (decoder.error())
|
||||
TOML_ERROR( "Encountered invalid utf-8 sequence", prev.position, source_path_ );
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
auto& current = codepoints[cp_idx % 2_sz];
|
||||
current.bytes[current_byte_count++] = static_cast<string_char>(next_byte);
|
||||
if (decoder.has_code_point())
|
||||
{
|
||||
//store codepoint
|
||||
current.value = decoder.codepoint;
|
||||
|
||||
//reset prev (will be the next 'current')
|
||||
std::memset(prev.bytes, 0, sizeof(prev.bytes));
|
||||
current_byte_count = {};
|
||||
if (is_line_break<false>(current.value))
|
||||
prev.position = { static_cast<source_index>(current.position.line + 1), 1 };
|
||||
else
|
||||
prev.position = { current.position.line, static_cast<source_index>(current.position.column + 1) };
|
||||
cp_idx++;
|
||||
return ¤t;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool peek_eof() const override
|
||||
{
|
||||
return stream.peek_eof();
|
||||
}
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
|
||||
[[nodiscard]]
|
||||
optional<parse_error>&& error() noexcept override
|
||||
{
|
||||
return std::move(err);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
|
||||
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
|
||||
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
|
||||
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
#undef TOML_ERROR_CHECK
|
||||
#define TOML_ERROR_CHECK if (reader.error()) return nullptr
|
||||
#endif
|
||||
|
||||
class TOML_EMPTY_BASES utf8_buffered_reader final
|
||||
: public utf8_reader_interface
|
||||
{
|
||||
public:
|
||||
static constexpr size_t max_history_length = 72;
|
||||
|
||||
private:
|
||||
static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
|
||||
utf8_reader_interface& reader;
|
||||
struct
|
||||
{
|
||||
|
||||
utf8_codepoint buffer[history_buffer_size];
|
||||
size_t count, first;
|
||||
}
|
||||
history = {};
|
||||
const utf8_codepoint* head = {};
|
||||
size_t negative_offset = {};
|
||||
|
||||
public:
|
||||
|
||||
explicit utf8_buffered_reader(utf8_reader_interface& reader_) noexcept
|
||||
: reader{ reader_ }
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
const source_path_ptr& source_path() const noexcept override
|
||||
{
|
||||
return reader.source_path();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const utf8_codepoint* read_next() override
|
||||
{
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
if (negative_offset)
|
||||
{
|
||||
negative_offset--;
|
||||
|
||||
// an entry negative offset of 1 just means "replay the current head"
|
||||
if (!negative_offset)
|
||||
return head;
|
||||
|
||||
// otherwise step back into the history buffer
|
||||
else
|
||||
return history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first character read from stream
|
||||
if TOML_UNLIKELY(!history.count && !head)
|
||||
head = reader.read_next();
|
||||
|
||||
// subsequent characters and not eof
|
||||
else if (head)
|
||||
{
|
||||
if TOML_UNLIKELY(history.count < history_buffer_size)
|
||||
history.buffer[history.count++] = *head;
|
||||
else
|
||||
history.buffer[(history.first++ + history_buffer_size) % history_buffer_size] = *head;
|
||||
|
||||
head = reader.read_next();
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const utf8_codepoint* step_back(size_t count) noexcept
|
||||
{
|
||||
TOML_ERROR_CHECK;
|
||||
TOML_ASSERT(history.count);
|
||||
TOML_ASSERT(negative_offset + count <= history.count);
|
||||
|
||||
negative_offset += count;
|
||||
|
||||
return negative_offset
|
||||
? history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size)
|
||||
: head;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool peek_eof() const override
|
||||
{
|
||||
return reader.peek_eof();
|
||||
}
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
|
||||
[[nodiscard]]
|
||||
optional<parse_error>&& error() noexcept override
|
||||
{
|
||||
return reader.error();
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#undef TOML_ERROR_CHECK
|
||||
#undef TOML_ERROR
|
||||
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
|
||||
TOML_POP_WARNINGS
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,506 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_node.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_FLOAT_WARNINGS
|
||||
TOML_DISABLE_PADDING_WARNINGS
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template <typename Char, typename T>
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const value<T>&);
|
||||
|
||||
/// \brief A TOML value.
|
||||
///
|
||||
/// \tparam T The value's data type. Can be one of:
|
||||
/// - toml::string
|
||||
/// - int64_t
|
||||
/// - double
|
||||
/// - bool
|
||||
/// - toml::date
|
||||
/// - toml::time
|
||||
/// - toml::date_time
|
||||
template <typename T>
|
||||
class TOML_API value final : public node
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value<T>,
|
||||
"Template type parameter must be one of the TOML value types"
|
||||
);
|
||||
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
template <typename U, typename V>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
static auto as_value([[maybe_unused]] V* ptr) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return ptr;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T val_;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief The value's underlying data type.
|
||||
using value_type = T;
|
||||
|
||||
/// \brief A type alias for 'value arguments'.
|
||||
/// \details This differs according to the value's type argument:
|
||||
/// - ints, floats, booleans: `value_type`
|
||||
/// - strings: `string_view`
|
||||
/// - everything else: `const value_type&`
|
||||
using value_arg = std::conditional_t<
|
||||
std::is_same_v<T, string>,
|
||||
string_view,
|
||||
std::conditional_t<impl::is_one_of<T, double, int64_t, bool>, T, const T&>
|
||||
>;
|
||||
|
||||
/// \brief Constructs a toml value.
|
||||
///
|
||||
/// \tparam U Constructor argument types.
|
||||
/// \param args Arguments to forward to the internal value's constructor.
|
||||
template <typename... U>
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit value(U&&... args) noexcept(std::is_nothrow_constructible_v<T, U&&...>)
|
||||
: val_{ std::forward<U>(args)... }
|
||||
{}
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
value(value&& other) noexcept
|
||||
: node{ std::move(other) },
|
||||
val_{ std::move(other.val_) }
|
||||
{}
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
value& operator= (value&& rhs) noexcept
|
||||
{
|
||||
node::operator=(std::move(rhs));
|
||||
val_ = std::move(rhs.val_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value(const value&) = delete;
|
||||
value& operator= (const value&) = delete;
|
||||
|
||||
/// \brief Returns the value's node type identifier.
|
||||
///
|
||||
/// \returns One of:
|
||||
/// - node_type::string
|
||||
/// - node_type::integer
|
||||
/// - node_type::floating_point
|
||||
/// - node_type::boolean
|
||||
/// - node_type::date
|
||||
/// - node_type::time
|
||||
/// - node_type::date_time
|
||||
[[nodiscard]] node_type type() const noexcept override { return impl::node_type_of<T>; }
|
||||
|
||||
/// \brief Always returns `false` for value nodes.
|
||||
[[nodiscard]] bool is_table() const noexcept override { return false; }
|
||||
/// \brief Always returns `false` for value nodes.
|
||||
[[nodiscard]] bool is_array() const noexcept override { return false; }
|
||||
/// \brief Always returns `true` for value nodes.
|
||||
[[nodiscard]] bool is_value() const noexcept override { return true; }
|
||||
|
||||
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<T, string>; }
|
||||
[[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<T, int64_t>; }
|
||||
[[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<T, double>; }
|
||||
[[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of<T, int64_t, double>; }
|
||||
[[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<T, bool>; }
|
||||
[[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<T, date>; }
|
||||
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<T, time>; }
|
||||
[[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<T, date_time>; }
|
||||
|
||||
/// \brief Returns a pointer to the value if the data type is a string.
|
||||
[[nodiscard]] value<string>* as_string() noexcept override { return as_value<string>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is an integer.
|
||||
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is a floating-point.
|
||||
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is boolean.
|
||||
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is a date.
|
||||
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is a time.
|
||||
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(this); }
|
||||
/// \brief Returns a pointer to the value if the data type is date-time.
|
||||
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(this); }
|
||||
|
||||
/// \brief Returns a const pointer to the value if the data type is a string.
|
||||
[[nodiscard]] const value<string>* as_string() const noexcept override { return as_value<string>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is an integer.
|
||||
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is a floating-point.
|
||||
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is a boolean.
|
||||
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is a date.
|
||||
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is a time.
|
||||
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
|
||||
/// \brief Returns a const pointer to the value if the data type is a date-time.
|
||||
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] T& get() & noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] T&& get() && noexcept { return std::move(val_); }
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] const T& get() const & noexcept { return val_; }
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] T& operator* () & noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] T&& operator* () && noexcept { return std::move(val_); }
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] const T& operator* () const& noexcept { return val_; }
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] explicit operator T& () & noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] explicit operator T&& () && noexcept { return std::move(val_); }
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
|
||||
|
||||
template <typename Char, typename U>
|
||||
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<U>& rhs);
|
||||
|
||||
/// \brief Value-assignment operator.
|
||||
value& operator= (value_arg rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, string>)
|
||||
val_.assign(rhs);
|
||||
else
|
||||
val_ = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = T, typename = std::enable_if_t<std::is_same_v<U, string>>>
|
||||
value& operator= (string&& rhs) noexcept
|
||||
{
|
||||
val_ = std::move(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Value equality operator.
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, value_arg rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<value_type, double>)
|
||||
{
|
||||
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
|
||||
{
|
||||
return ((static_cast<uint64_t>(l) << 32) | static_cast<uint64_t>(r));
|
||||
};
|
||||
|
||||
switch (pack(std::fpclassify(lhs.val_), std::fpclassify(rhs)))
|
||||
{
|
||||
case pack(FP_INFINITE, FP_INFINITE): return (lhs.val_ < 0.0) == (rhs < 0.0);
|
||||
case pack(FP_NAN, FP_NAN): return true;
|
||||
default: return lhs.val_ == rhs;
|
||||
}
|
||||
}
|
||||
else
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, )
|
||||
|
||||
/// \brief Value less-than operator.
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }
|
||||
/// \brief Value less-than operator.
|
||||
[[nodiscard]] friend bool operator < (value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; }
|
||||
/// \brief Value less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator <= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; }
|
||||
/// \brief Value less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator <= (value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; }
|
||||
|
||||
/// \brief Value greater-than operator.
|
||||
[[nodiscard]] friend bool operator > (const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; }
|
||||
/// \brief Value greater-than operator.
|
||||
[[nodiscard]] friend bool operator > (value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; }
|
||||
/// \brief Value greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator >= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; }
|
||||
/// \brief Value greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator >= (value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; }
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS value.
|
||||
/// \param rhs The RHS value.
|
||||
///
|
||||
/// \returns True if the values were of the same type and contained the same value.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator == (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
///
|
||||
/// \param lhs The LHS value.
|
||||
/// \param rhs The RHS value.
|
||||
///
|
||||
/// \returns True if the values were not of the same type, or did not contain the same value.
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator != (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() < rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() < rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ < rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<T> < impl::node_type_of<U>;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() <= rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() <= rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator <= (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ <= rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<T> <= impl::node_type_of<U>;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() > rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() > rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator > (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ > rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<T> > impl::node_type_of<U>;
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() >= rhs.get()` <br>
|
||||
/// <strong><em>Different value types:</em></strong> `lhs.type() >= rhs.type()`
|
||||
template <typename U>
|
||||
[[nodiscard]] friend bool operator >= (const value& lhs, const value<U>& rhs) noexcept
|
||||
{
|
||||
if constexpr (std::is_same_v<T, U>)
|
||||
return lhs.val_ >= rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<T> >= impl::node_type_of<U>;
|
||||
}
|
||||
};
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_VTABLE_WARNINGS
|
||||
extern template class TOML_API value<string>;
|
||||
extern template class TOML_API value<int64_t>;
|
||||
extern template class TOML_API value<double>;
|
||||
extern template class TOML_API value<bool>;
|
||||
extern template class TOML_API value<date>;
|
||||
extern template class TOML_API value<time>;
|
||||
extern template class TOML_API value<date_time>;
|
||||
TOML_POP_WARNINGS
|
||||
#endif
|
||||
|
||||
template <size_t N> value(const string_char(&)[N]) -> value<string>;
|
||||
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
|
||||
value(const string_char*) -> value<string>;
|
||||
template <size_t N> value(string_char(&)[N]) -> value<string>;
|
||||
template <size_t N> value(string_char(&&)[N]) -> value<string>;
|
||||
value(string_char*) -> value<string>;
|
||||
value(string_view) -> value<string>;
|
||||
value(string) -> value<string>;
|
||||
value(bool) -> value<bool>;
|
||||
value(float) -> value<double>;
|
||||
value(double) -> value<double>;
|
||||
value(int8_t) -> value<int64_t>;
|
||||
value(int16_t) -> value<int64_t>;
|
||||
value(int32_t) -> value<int64_t>;
|
||||
value(int64_t) -> value<int64_t>;
|
||||
value(uint8_t) -> value<int64_t>;
|
||||
value(uint16_t) -> value<int64_t>;
|
||||
value(uint32_t) -> value<int64_t>;
|
||||
value(date) -> value<date>;
|
||||
value(time) -> value<time>;
|
||||
value(date_time) -> value<date_time>;
|
||||
#ifdef TOML_SMALL_FLOAT_TYPE
|
||||
value(TOML_SMALL_FLOAT_TYPE) -> value<double>;
|
||||
#endif
|
||||
#ifdef TOML_SMALL_INT_TYPE
|
||||
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
|
||||
#endif
|
||||
|
||||
/// \brief Prints the value out to a stream.
|
||||
template <typename Char, typename T>
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs)
|
||||
{
|
||||
// this is the same behaviour as default_formatter, but it's so simple that there's
|
||||
// no need to spin up a new instance of it just for individual values.
|
||||
|
||||
if constexpr (std::is_same_v<T, string>)
|
||||
{
|
||||
impl::print_to_stream('"', lhs);
|
||||
impl::print_to_stream_with_escapes(rhs.val_, lhs);
|
||||
impl::print_to_stream('"', lhs);
|
||||
}
|
||||
else
|
||||
impl::print_to_stream(rhs.val_, lhs);
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !TOML_ALL_INLINE
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::string>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
|
||||
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
|
||||
#endif
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
TOML_DISABLE_INIT_WARNINGS
|
||||
|
||||
template <typename T>
|
||||
inline optional<T> node::value() const noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value<T> || std::is_same_v<T, string_view>,
|
||||
"Value type must be one of the TOML value types (or string_view)"
|
||||
);
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case node_type::none: [[fallthrough]];
|
||||
case node_type::table: [[fallthrough]];
|
||||
case node_type::array:
|
||||
return {};
|
||||
|
||||
case node_type::string:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, string> || std::is_same_v<T, string_view>)
|
||||
return { T{ ref_cast<string>().get() } };
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::integer:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, int64_t>)
|
||||
return ref_cast<int64_t>().get();
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return static_cast<double>(ref_cast<int64_t>().get());
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::floating_point:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, double>)
|
||||
return ref_cast<double>().get();
|
||||
else if constexpr (std::is_same_v<T, int64_t>)
|
||||
return static_cast<int64_t>(ref_cast<double>().get());
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::boolean:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, bool>)
|
||||
return ref_cast<bool>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::date:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, date>)
|
||||
return ref_cast<date>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::time:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, time>)
|
||||
return ref_cast<time>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
case node_type::date_time:
|
||||
{
|
||||
if constexpr (std::is_same_v<T, date_time>)
|
||||
return ref_cast<date_time>().get();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
template <typename T>
|
||||
inline auto node::value_or(T&& default_value) const noexcept
|
||||
{
|
||||
static_assert(
|
||||
impl::is_value_or_promotable<impl::remove_cvref_t<T>>,
|
||||
"Default value type must be (or be promotable to) one of the TOML value types"
|
||||
);
|
||||
|
||||
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
|
||||
using return_type = std::conditional_t<
|
||||
std::is_same_v<value_type, string>,
|
||||
std::conditional_t<std::is_same_v<impl::remove_cvref_t<T>, string>, string, string_view>,
|
||||
value_type
|
||||
>;
|
||||
|
||||
if (auto val = this->value<return_type>())
|
||||
return *val;
|
||||
return return_type{ std::forward<T>(default_value) };
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS // TOML_DISABLE_FLOAT_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|
|
@ -0,0 +1,14 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TOML_LIB_MAJOR 1
|
||||
#define TOML_LIB_MINOR 3
|
||||
#define TOML_LIB_PATCH 3
|
||||
|
||||
#define TOML_LANG_MAJOR 1
|
||||
#define TOML_LANG_MINOR 0
|
||||
#define TOML_LANG_PATCH 0
|
124
src/data/state.h
124
src/data/state.h
|
@ -5,6 +5,9 @@
|
|||
#define MAX_FPS 240
|
||||
#define REPORT_BUFFER_SIZE 128
|
||||
|
||||
#include <toml.h>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include "glm.hpp"
|
||||
#include "circular_buffer.hpp"
|
||||
|
@ -12,32 +15,123 @@
|
|||
#include "../world/World.hpp"
|
||||
#include "../control/Camera.hpp"
|
||||
|
||||
inline ImColor fromHex(const std::string& str) {
|
||||
int rgb[3] = {UCHAR_MAX};
|
||||
sscanf(str.c_str() + 1, "%02X%02X%02X", (unsigned int *)&rgb[0], (unsigned int *)&rgb[1], (unsigned int *)&rgb[2]);
|
||||
return ImColor(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
inline std::string toHexa(const ImVec4& rgba) {
|
||||
auto out = (char*)malloc(8 * sizeof(char));
|
||||
sprintf(out, "#%02X%02X%02X", (int)(rgba.x * UCHAR_MAX), (int)(rgba.y * UCHAR_MAX), (int)(rgba.z * UCHAR_MAX));
|
||||
return std::string(out);
|
||||
}
|
||||
|
||||
/// Savable game options
|
||||
struct options {
|
||||
bool show_debug_menu = false;
|
||||
bool show_debug_render = false;
|
||||
int target_fps = 60;
|
||||
int samples = -1;
|
||||
bool fullscreen = false;
|
||||
ImVec4 clear_color = ImColor(85, 56, 104);
|
||||
const char *PATH = "config.toml";
|
||||
options() {
|
||||
auto config = std::filesystem::exists(PATH) ? toml::parse_file(PATH) : toml::table();
|
||||
target_fps = config["window"]["fps"].value_or(60);
|
||||
samples = config["window"]["samples"].value_or(-1);
|
||||
fullscreen = config["window"]["fullscreen"].value_or(false);
|
||||
|
||||
renderer.textures = config["render"]["textures"].value_or(renderer.textures);
|
||||
renderer.mipMapLOD = config["render"]["texture_quality"].value_or(renderer.mipMapLOD);
|
||||
renderer.main.pbr = config["render"]["pbr"].value_or(renderer.main.pbr);
|
||||
renderer.main.triplanar = config["render"]["triplanar"].value_or(renderer.main.triplanar);
|
||||
renderer.main.fog = config["render"]["fog"].value_or(renderer.main.fog);
|
||||
const std::string fog = config["render"]["fog_color"].value_or(std::string{"#553868"});
|
||||
renderer.clear_color = fromHex(fog);
|
||||
|
||||
world.loadDistance = config["world"]["load_distance"].value_or(world.loadDistance);
|
||||
world.keepDistance = config["world"]["keep_distance"].value_or(world.keepDistance);
|
||||
voxel_size = config["world"]["unit_size"].value_or(1.f);
|
||||
|
||||
//TODO: contouring
|
||||
|
||||
camera.far = config["camera"]["far"].value_or(camera.far);
|
||||
camera.near = config["camera"]["near"].value_or(camera.near);
|
||||
camera.fov = config["camera"]["fov"].value_or(camera.fov);
|
||||
camera.sensibility = config["camera"]["sensibility"].value_or(camera.sensibility);
|
||||
camera.speed = config["camera"]["speed"].value_or(camera.speed);
|
||||
|
||||
overlay_show = config["overlay"]["visible"].value_or(true);
|
||||
overlay_corner = config["overlay"]["corner"].value_or(3);
|
||||
//TODO: console
|
||||
|
||||
show_debug_menu = config["show_debug"]["menu"].value_or(false);
|
||||
show_debug_render = config["show_debug"]["render"].value_or(false);
|
||||
show_debug_world = config["show_debug"]["world"].value_or(false);
|
||||
show_debug_contouring = config["show_debug"]["contouring"].value_or(false);
|
||||
show_debug_controls = config["show_debug"]["controls"].value_or(false);
|
||||
}
|
||||
void save() {
|
||||
auto config = toml::table();
|
||||
config.insert_or_assign("window", toml::table({
|
||||
{"fps", target_fps},
|
||||
{"samples", samples},
|
||||
{"fullscreen", fullscreen},
|
||||
}));
|
||||
config.insert_or_assign("render", toml::table({
|
||||
{"textures", renderer.textures},
|
||||
{"texture_quality", renderer.mipMapLOD},
|
||||
{"pbr", renderer.main.pbr},
|
||||
{"triplanar", renderer.main.triplanar},
|
||||
{"fog", renderer.main.fog},
|
||||
{"fog_color", toHexa(renderer.clear_color)},
|
||||
}));
|
||||
config.insert_or_assign("world", toml::table({
|
||||
{"load_distance", world.loadDistance},
|
||||
{"keep_distance", world.keepDistance},
|
||||
{"unit_size", voxel_size}
|
||||
}));
|
||||
config.insert_or_assign("camera", toml::table({
|
||||
{"far", camera.far},
|
||||
{"near", camera.near},
|
||||
{"fov", camera.fov},
|
||||
{"sensibility", camera.sensibility},
|
||||
{"speed", camera.speed}
|
||||
}));
|
||||
config.insert_or_assign("overlay", toml::table({
|
||||
{"visible", overlay_show},
|
||||
{"corner", overlay_corner}
|
||||
}));
|
||||
config.insert_or_assign("show_debug", toml::table({
|
||||
{"menu", show_debug_menu},
|
||||
{"render", show_debug_render},
|
||||
{"world", show_debug_world},
|
||||
{"contouring", show_debug_contouring},
|
||||
{"controls", show_debug_controls}
|
||||
}));
|
||||
|
||||
std::ofstream out;
|
||||
out.open(PATH, std::ios::out | std::ios::trunc);
|
||||
out << config << "\n\n";
|
||||
out.close();
|
||||
}
|
||||
|
||||
bool show_debug_menu;
|
||||
bool show_debug_render;
|
||||
int target_fps;
|
||||
int samples;
|
||||
bool fullscreen;
|
||||
Renderer::options renderer;
|
||||
bool debug_wireframe = false;
|
||||
bool culling = true;
|
||||
|
||||
bool show_debug_world = false;
|
||||
bool show_debug_world;
|
||||
World::options world;
|
||||
float voxel_size = 1;
|
||||
float voxel_size;
|
||||
|
||||
bool show_debug_contouring = false;
|
||||
bool show_debug_contouring;
|
||||
int contouring_idx = 0;
|
||||
bool culling = true; // TODO: move to contouring
|
||||
|
||||
bool show_debug_controls = false;
|
||||
bool show_debug_controls;
|
||||
Camera::options camera;
|
||||
|
||||
bool show_overlay = true;
|
||||
int overlay_corner = 0;
|
||||
bool overlay_show;
|
||||
int overlay_corner;
|
||||
|
||||
bool show_console = false;
|
||||
bool console_show = false;
|
||||
bool console_scrool = true;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ int main(int, char *[]){
|
|||
if(window == NULL)
|
||||
return 1;
|
||||
|
||||
glClearColor(options.clear_color.x, options.clear_color.y, options.clear_color.z, options.clear_color.w);
|
||||
glClearColor(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z, options.renderer.clear_color.w);
|
||||
glfwSwapInterval(options.target_fps < MIN_FPS);
|
||||
|
||||
InputMap inputs(window);
|
||||
|
@ -87,7 +87,8 @@ int main(int, char *[]){
|
|||
}
|
||||
}
|
||||
if(actions && UI::Actions::ClearColor) {
|
||||
glClearColor(options.clear_color.x, options.clear_color.y, options.clear_color.z, options.clear_color.w);
|
||||
renderer->FogColor = glm::vec3(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z);
|
||||
glClearColor(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z, options.renderer.clear_color.w);
|
||||
}
|
||||
if(actions && UI::Actions::RendererSharders) {
|
||||
renderer->reloadShaders(options.renderer.main);
|
||||
|
@ -95,7 +96,6 @@ int main(int, char *[]){
|
|||
if(actions && UI::Actions::RendererTextures) {
|
||||
renderer->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD);
|
||||
}
|
||||
renderer->FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
|
||||
if(actions && UI::Actions::World) {
|
||||
world.setOptions(options.world);
|
||||
}
|
||||
|
@ -152,5 +152,7 @@ int main(int, char *[]){
|
|||
// Close OpenGL window and terminate GLFW
|
||||
glfwTerminate();
|
||||
|
||||
options.save();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -9,6 +9,7 @@ Renderer::Renderer(const Renderer::options& options) {
|
|||
|
||||
MainPass = new MainProgram(options.main);
|
||||
|
||||
FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
|
||||
loadTextures(options.textures, options.mipMapLOD);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <imgui.h>
|
||||
#include "pass/MainProgram.hpp"
|
||||
#include "pass/PassContext.hpp"
|
||||
|
||||
|
@ -13,6 +14,7 @@ public:
|
|||
bool wireframe = false;
|
||||
std::string textures = "1024-realistic";
|
||||
float mipMapLOD = -.5;
|
||||
ImVec4 clear_color;
|
||||
};
|
||||
|
||||
Renderer(const options&);
|
||||
|
|
|
@ -50,7 +50,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::PlotHistogram("Wait", reports.main.wait.buffer.get(), reports.main.wait.size, 0, std::to_string(reports.main.wait.current()).c_str(), 0);
|
||||
ImGui::Text("Tris: %ld (%ld models)", reports.main.tris_count, reports.main.models_count);
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox("Overlay", &options.show_overlay);
|
||||
ImGui::Checkbox("Overlay", &options.overlay_show);
|
||||
if (ImGui::SliderInt("FPS", &options.target_fps, MIN_FPS-1, MAX_FPS+1, options.target_fps > MIN_FPS ? (options.target_fps < MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
|
||||
actions = actions | Actions::FPS;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
if (ImGui::Checkbox("Fullscreen", &options.fullscreen)){
|
||||
actions = actions | Actions::FullScreen;
|
||||
}
|
||||
if (ImGui::ColorEdit3("Fog color", (float *)&options.clear_color)) {
|
||||
if (ImGui::ColorEdit3("Fog color", (float *)&options.renderer.clear_color)) {
|
||||
actions = actions | Actions::ClearColor;
|
||||
}
|
||||
|
||||
|
@ -74,8 +74,8 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
actions = actions | Actions::RendererSharders;
|
||||
}
|
||||
}
|
||||
if (ImGui::Checkbox("Wireframe", &options.debug_wireframe))
|
||||
glPolygonMode(GL_FRONT_AND_BACK, options.debug_wireframe ? GL_LINE : GL_FILL);
|
||||
if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe))
|
||||
glPolygonMode(GL_FRONT_AND_BACK, options.renderer.wireframe ? GL_LINE : GL_FILL);
|
||||
ImGui::Checkbox("Culling", &options.culling);
|
||||
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
|
||||
if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1)) {
|
||||
|
@ -118,7 +118,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::Begin("Debug: Controls", &options.show_debug_controls, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
ImGui::Text("Position: (%.3f, %.3f, %.3f)", state.position.x, state.position.y, state.position.z);
|
||||
if (state.look_at.has_value()) {
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%d, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, state.look_at.value().second.Material, state.look_at.value().second.Density / UCHAR_MAX);
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%d, %.1d)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, state.look_at.value().second.Material, state.look_at.value().second.Density / UCHAR_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * options.voxel_size, state.look_at.value().first.y * options.voxel_size, state.look_at.value().first.z * options.voxel_size);
|
||||
} else {
|
||||
ImGui::Text("Look at: none");
|
||||
|
@ -169,14 +169,14 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
ImGui::End();
|
||||
}*/
|
||||
|
||||
if (options.show_overlay) {
|
||||
if (options.overlay_show) {
|
||||
if (options.overlay_corner != -1) {
|
||||
ImVec2 window_pos = ImVec2((options.overlay_corner & 1) ? io.DisplaySize.x - UI_MARGIN : UI_MARGIN, (options.overlay_corner & 2) ? io.DisplaySize.y - UI_MARGIN : UI_MARGIN);
|
||||
ImVec2 window_pos_pivot = ImVec2((options.overlay_corner & 1) ? 1.0f : 0.0f, (options.overlay_corner & 2) ? 1.0f : 0.0f);
|
||||
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
|
||||
}
|
||||
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
||||
ImGui::Begin("Overlay", &options.show_overlay, (options.overlay_corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav);
|
||||
ImGui::Begin("Overlay", &options.overlay_show, (options.overlay_corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav);
|
||||
ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||
ImGui::Text("%ld tris(%ld models)", reports.main.tris_count, reports.main.models_count);
|
||||
if (ImGui::BeginPopupContextWindow()) {
|
||||
|
@ -190,8 +190,8 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
options.overlay_corner = 2;
|
||||
if (ImGui::MenuItem("Bottom-right", NULL, options.overlay_corner == 3))
|
||||
options.overlay_corner = 3;
|
||||
if (options.show_overlay && ImGui::MenuItem("Close"))
|
||||
options.show_overlay = false;
|
||||
if (options.overlay_show && ImGui::MenuItem("Close"))
|
||||
options.overlay_show = false;
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::End();
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
#include <string>
|
||||
|
||||
namespace materials {
|
||||
static const auto count = 6;
|
||||
static const std::array<std::string, count> textures = {{"Air", "Sand", "Stone_path", "Seaside_rock", "Stone_wall", "Rough_rock"}};
|
||||
static const auto count = 8;
|
||||
static const std::array<std::string, count> textures = {{"Air", "Sand", "Stone_path", "Mapl", "Seaside_rock", "Stone_wall", "Rough_rock", "Alien"}};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue