1
0
Fork 0

Add config

This commit is contained in:
May B. 2020-07-12 15:46:51 +02:00
parent ca0fae3d83
commit c0e84d67e7
51 changed files with 12383 additions and 32 deletions

View File

@ -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)

View File

@ -27,6 +27,7 @@ Experimental project using OpenGL.
* OpenGL
* ImGui
* FasNoiseSIMD
* Toml++
* Love and insomnia

View File

@ -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 );

BIN
content/textures-src/1024-realistic/Abstract_006_COLOR.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Abstract_006_DISP.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Abstract_006_HOS.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Abstract_006_NORM.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Abstract_006_OCC.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Abstract_006_SPEC.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Bark_005_HOS.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Bark_005_baseColor.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures-src/1024-realistic/Bark_005_normal.jpg (Stored with Git LFS) Normal file

Binary file not shown.

21
content/textures-src/merge.py Executable file
View File

@ -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)

BIN
content/textures/terrain/1024-realistic/Alien.dds (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures/terrain/1024-realistic/Alien.hos.dds (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures/terrain/1024-realistic/Alien.nrm.dds (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures/terrain/1024-realistic/Mapl.dds (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures/terrain/1024-realistic/Mapl.hos.dds (Stored with Git LFS) Normal file

Binary file not shown.

BIN
content/textures/terrain/1024-realistic/Mapl.nrm.dds (Stored with Git LFS) Normal file

Binary file not shown.

106
include/toml++/toml.h Normal file
View File

@ -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
//# }}

951
include/toml++/toml_array.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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>;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

535
include/toml++/toml_node.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

791
include/toml++/toml_table.h Normal file
View File

@ -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

View File

@ -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

254
include/toml++/toml_utf8.h Normal file
View File

@ -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];
}
};
}

View File

@ -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

View File

@ -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 &current;
}
}
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

506
include/toml++/toml_value.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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&);

View File

@ -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();

View File

@ -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"}};
}