Path: blob/a-new-beginning/SharedDependencies/Sources/toml/include/toml.hpp
2 views
#ifndef TOML11_VERSION_HPP1#define TOML11_VERSION_HPP23#define TOML11_VERSION_MAJOR 44#define TOML11_VERSION_MINOR 45#define TOML11_VERSION_PATCH 067#ifndef __cplusplus8# error "__cplusplus is not defined"9#endif1011/*12* Defines a name for an inline namespace that includes the current version13* number. This becomes necessary if multiple software packages use toml11 as an14* internal build-time dependency, since multiple packages will in general not15* use the same version of toml11. An inline namespace with a version number16* ensures that the symbols emitted by compiling toml11 into downstream17* applications will be distinguished by the specific used version of toml11,18* making it possible to link multiple packages that internally use toml11 in19* different versions.20*/21#define TOML11_CONCAT(a, b, c, d, e, f) a##b##c##d##e##f2223#define TOML11_GENERATE_INLINE_VERSION_NAMESPACE(major, minor, patch) \24TOML11_CONCAT(toml11_, major, _, minor, _, patch)2526#define TOML11_INLINE_VERSION_NAMESPACE \27TOML11_GENERATE_INLINE_VERSION_NAMESPACE( \28TOML11_VERSION_MAJOR, TOML11_VERSION_MINOR, TOML11_VERSION_PATCH)2930// Since MSVC does not define `__cplusplus` correctly unless you pass31// `/Zc:__cplusplus` when compiling, the workaround macros are added.32//33// The value of `__cplusplus` macro is defined in the C++ standard spec, but34// MSVC ignores the value, maybe because of backward compatibility. Instead,35// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in36// the C++ standard. So we check if _MSVC_LANG is defined before using `__cplusplus`.37//38// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-17039// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-17040//4142#if defined(_MSVC_LANG) && defined(_MSC_VER) && 190024210 <= _MSC_FULL_VER43# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG44#else45# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus46#endif4748#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L49# error "toml11 requires C++11 or later."50#endif5152#if ! defined(__has_include)53# define __has_include(x) 054#endif5556#if ! defined(__has_cpp_attribute)57# define __has_cpp_attribute(x) 058#endif5960#if ! defined(__has_builtin)61# define __has_builtin(x) 062#endif6364// hard to remember6566#ifndef TOML11_CXX14_VALUE67#define TOML11_CXX14_VALUE 201402L68#endif//TOML11_CXX14_VALUE6970#ifndef TOML11_CXX17_VALUE71#define TOML11_CXX17_VALUE 201703L72#endif//TOML11_CXX17_VALUE7374#ifndef TOML11_CXX20_VALUE75#define TOML11_CXX20_VALUE 202002L76#endif//TOML11_CXX20_VALUE7778#if defined(__cpp_char8_t)79# if __cpp_char8_t >= 201811L80# define TOML11_HAS_CHAR8_T 181# endif82#endif8384#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE85# if __has_include(<string_view>)86# define TOML11_HAS_STRING_VIEW 187# endif88#endif8990#ifndef TOML11_DISABLE_STD_FILESYSTEM91# if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE92# if __has_include(<filesystem>)93# define TOML11_HAS_FILESYSTEM 194# endif95# endif96#endif9798#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE99# if __has_include(<optional>)100# define TOML11_HAS_OPTIONAL 1101# endif102#endif103104#if defined(TOML11_COMPILE_SOURCES)105# define TOML11_INLINE106#else107# define TOML11_INLINE inline108#endif109110namespace toml111{112inline namespace TOML11_INLINE_VERSION_NAMESPACE113{114115inline const char* license_notice() noexcept116{117return R"(The MIT License (MIT)118119Copyright (c) 2017-now Toru Niina120121Permission is hereby granted, free of charge, to any person obtaining a copy122of this software and associated documentation files (the "Software"), to deal123in the Software without restriction, including without limitation the rights124to use, copy, modify, merge, publish, distribute, sublicense, and/or sell125copies of the Software, and to permit persons to whom the Software is126furnished to do so, subject to the following conditions:127128The above copyright notice and this permission notice shall be included in129all copies or substantial portions of the Software.130131THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR132IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,133FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE134AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER135LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,136OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN137THE SOFTWARE.)";138}139140} // TOML11_INLINE_VERSION_NAMESPACE141} // toml142#endif // TOML11_VERSION_HPP143#ifndef TOML11_SPEC_HPP144#define TOML11_SPEC_HPP145146#include <array>147#include <functional>148#include <ostream>149#include <sstream>150#include <utility>151152#include <cstdint>153154155namespace toml156{157inline namespace TOML11_INLINE_VERSION_NAMESPACE158{159160struct semantic_version161{162constexpr semantic_version(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept163: major{mjr}, minor{mnr}, patch{p}164{}165166std::uint32_t major;167std::uint32_t minor;168std::uint32_t patch;169};170171constexpr inline semantic_version172make_semver(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept173{174return semantic_version(mjr, mnr, p);175}176177constexpr inline bool178operator==(const semantic_version& lhs, const semantic_version& rhs) noexcept179{180return lhs.major == rhs.major &&181lhs.minor == rhs.minor &&182lhs.patch == rhs.patch;183}184constexpr inline bool185operator!=(const semantic_version& lhs, const semantic_version& rhs) noexcept186{187return !(lhs == rhs);188}189constexpr inline bool190operator<(const semantic_version& lhs, const semantic_version& rhs) noexcept191{192return lhs.major < rhs.major ||193(lhs.major == rhs.major && lhs.minor < rhs.minor) ||194(lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch < rhs.patch);195}196constexpr inline bool197operator>(const semantic_version& lhs, const semantic_version& rhs) noexcept198{199return rhs < lhs;200}201constexpr inline bool202operator<=(const semantic_version& lhs, const semantic_version& rhs) noexcept203{204return !(lhs > rhs);205}206constexpr inline bool207operator>=(const semantic_version& lhs, const semantic_version& rhs) noexcept208{209return !(lhs < rhs);210}211212inline std::ostream& operator<<(std::ostream& os, const semantic_version& v)213{214os << v.major << '.' << v.minor << '.' << v.patch;215return os;216}217218inline std::string to_string(const semantic_version& v)219{220std::ostringstream oss;221oss << v;222return oss.str();223}224225struct spec226{227constexpr static spec default_version() noexcept228{229return spec::v(1, 0, 0);230}231232constexpr static spec v(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept233{234return spec(make_semver(mjr, mnr, p));235}236237constexpr explicit spec(const semantic_version& semver) noexcept238: version{semver},239v1_1_0_allow_newlines_in_inline_tables {semantic_version{1, 1, 0} <= semver},240v1_1_0_allow_trailing_comma_in_inline_tables{semantic_version{1, 1, 0} <= semver},241v1_1_0_add_escape_sequence_e {semantic_version{1, 1, 0} <= semver},242v1_1_0_add_escape_sequence_x {semantic_version{1, 1, 0} <= semver},243v1_1_0_make_seconds_optional {semantic_version{1, 1, 0} <= semver},244ext_allow_control_characters_in_comments{false},245ext_allow_non_english_in_bare_keys{false},246ext_hex_float {false},247ext_num_suffix{false},248ext_null_value{false}249{}250251semantic_version version; // toml version252253// diff from v1.0.0 -> v1.1.0254bool v1_1_0_allow_newlines_in_inline_tables;255bool v1_1_0_allow_trailing_comma_in_inline_tables;256bool v1_1_0_add_escape_sequence_e;257bool v1_1_0_add_escape_sequence_x;258bool v1_1_0_make_seconds_optional;259260// discussed in toml-lang, but currently not in it261bool ext_allow_control_characters_in_comments;262bool ext_allow_non_english_in_bare_keys;263264// library extensions265bool ext_hex_float; // allow hex float (in C++ style)266bool ext_num_suffix; // allow number suffix (in C++ style)267bool ext_null_value; // allow `null` as a value268};269270namespace detail271{272inline std::pair<const semantic_version&, std::array<bool, 10>>273to_tuple(const spec& s) noexcept274{275return std::make_pair(std::cref(s.version), std::array<bool, 10>{{276s.v1_1_0_allow_newlines_in_inline_tables,277s.v1_1_0_allow_trailing_comma_in_inline_tables,278s.v1_1_0_add_escape_sequence_e,279s.v1_1_0_add_escape_sequence_x,280s.v1_1_0_make_seconds_optional,281s.ext_allow_control_characters_in_comments,282s.ext_allow_non_english_in_bare_keys,283s.ext_hex_float,284s.ext_num_suffix,285s.ext_null_value286}});287}288} // detail289290inline bool operator==(const spec& lhs, const spec& rhs) noexcept291{292return detail::to_tuple(lhs) == detail::to_tuple(rhs);293}294inline bool operator!=(const spec& lhs, const spec& rhs) noexcept295{296return detail::to_tuple(lhs) != detail::to_tuple(rhs);297}298inline bool operator< (const spec& lhs, const spec& rhs) noexcept299{300return detail::to_tuple(lhs) < detail::to_tuple(rhs);301}302inline bool operator<=(const spec& lhs, const spec& rhs) noexcept303{304return detail::to_tuple(lhs) <= detail::to_tuple(rhs);305}306inline bool operator> (const spec& lhs, const spec& rhs) noexcept307{308return detail::to_tuple(lhs) > detail::to_tuple(rhs);309}310inline bool operator>=(const spec& lhs, const spec& rhs) noexcept311{312return detail::to_tuple(lhs) >= detail::to_tuple(rhs);313}314315} // TOML11_INLINE_VERSION_NAMESPACE316} // namespace toml317#endif // TOML11_SPEC_HPP318#ifndef TOML11_ORDERED_MAP_HPP319#define TOML11_ORDERED_MAP_HPP320321#include <algorithm>322#include <stdexcept>323#include <utility>324#include <vector>325326327namespace toml328{329inline namespace TOML11_INLINE_VERSION_NAMESPACE330{331332namespace detail333{334template<typename Cmp>335struct ordered_map_ebo_container336{337Cmp cmp_; // empty base optimization for empty Cmp type338};339} // detail340341template<typename Key, typename Val, typename Cmp = std::equal_to<Key>,342typename Allocator = std::allocator<std::pair<Key, Val>>>343class ordered_map : detail::ordered_map_ebo_container<Cmp>344{345public:346using key_type = Key;347using mapped_type = Val;348using value_type = std::pair<Key, Val>;349350using key_compare = Cmp;351using allocator_type = Allocator;352353using container_type = std::vector<value_type, Allocator>;354using reference = typename container_type::reference;355using pointer = typename container_type::pointer;356using const_reference = typename container_type::const_reference;357using const_pointer = typename container_type::const_pointer;358using iterator = typename container_type::iterator;359using const_iterator = typename container_type::const_iterator;360using size_type = typename container_type::size_type;361using difference_type = typename container_type::difference_type;362363private:364365using ebo_base = detail::ordered_map_ebo_container<Cmp>;366367public:368369ordered_map() = default;370~ordered_map() = default;371ordered_map(const ordered_map&) = default;372ordered_map(ordered_map&&) = default;373ordered_map& operator=(const ordered_map&) = default;374ordered_map& operator=(ordered_map&&) = default;375376ordered_map(const ordered_map& other, const Allocator& alloc)377: container_(other.container_, alloc)378{}379ordered_map(ordered_map&& other, const Allocator& alloc)380: container_(std::move(other.container_), alloc)381{}382383explicit ordered_map(const Cmp& cmp, const Allocator& alloc = Allocator())384: ebo_base{cmp}, container_(alloc)385{}386explicit ordered_map(const Allocator& alloc)387: container_(alloc)388{}389390template<typename InputIterator>391ordered_map(InputIterator first, InputIterator last, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator())392: ebo_base{cmp}, container_(first, last, alloc)393{}394template<typename InputIterator>395ordered_map(InputIterator first, InputIterator last, const Allocator& alloc)396: container_(first, last, alloc)397{}398399ordered_map(std::initializer_list<value_type> v, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator())400: ebo_base{cmp}, container_(std::move(v), alloc)401{}402ordered_map(std::initializer_list<value_type> v, const Allocator& alloc)403: container_(std::move(v), alloc)404{}405ordered_map& operator=(std::initializer_list<value_type> v)406{407this->container_ = std::move(v);408return *this;409}410411iterator begin() noexcept {return container_.begin();}412iterator end() noexcept {return container_.end();}413const_iterator begin() const noexcept {return container_.begin();}414const_iterator end() const noexcept {return container_.end();}415const_iterator cbegin() const noexcept {return container_.cbegin();}416const_iterator cend() const noexcept {return container_.cend();}417418bool empty() const noexcept {return container_.empty();}419std::size_t size() const noexcept {return container_.size();}420std::size_t max_size() const noexcept {return container_.max_size();}421422void clear() {container_.clear();}423424void push_back(const value_type& v)425{426if(this->contains(v.first))427{428throw std::out_of_range("ordered_map: value already exists");429}430container_.push_back(v);431}432void push_back(value_type&& v)433{434if(this->contains(v.first))435{436throw std::out_of_range("ordered_map: value already exists");437}438container_.push_back(std::move(v));439}440void emplace_back(key_type k, mapped_type v)441{442if(this->contains(k))443{444throw std::out_of_range("ordered_map: value already exists");445}446container_.emplace_back(std::move(k), std::move(v));447}448void pop_back() {container_.pop_back();}449450void insert(value_type kv)451{452if(this->contains(kv.first))453{454throw std::out_of_range("ordered_map: value already exists");455}456container_.push_back(std::move(kv));457}458void emplace(key_type k, mapped_type v)459{460if(this->contains(k))461{462throw std::out_of_range("ordered_map: value already exists");463}464container_.emplace_back(std::move(k), std::move(v));465}466467std::size_t count(const key_type& key) const468{469if(this->find(key) != this->end())470{471return 1;472}473else474{475return 0;476}477}478bool contains(const key_type& key) const479{480return this->find(key) != this->end();481}482iterator find(const key_type& key) noexcept483{484return std::find_if(this->begin(), this->end(),485[&key, this](const value_type& v) {return this->cmp_(v.first, key);});486}487const_iterator find(const key_type& key) const noexcept488{489return std::find_if(this->begin(), this->end(),490[&key, this](const value_type& v) {return this->cmp_(v.first, key);});491}492493mapped_type& at(const key_type& k)494{495const auto iter = this->find(k);496if(iter == this->end())497{498throw std::out_of_range("ordered_map: no such element");499}500return iter->second;501}502mapped_type const& at(const key_type& k) const503{504const auto iter = this->find(k);505if(iter == this->end())506{507throw std::out_of_range("ordered_map: no such element");508}509return iter->second;510}511512iterator erase(iterator pos)513{514return container_.erase(pos);515}516517iterator erase(const_iterator pos)518{519return container_.erase(pos);520}521522iterator erase(const_iterator first, const_iterator last)523{524return container_.erase(first, last);525}526527size_type erase(const key_type& key)528{529auto it = this->find(key);530if (it != this->end())531{532container_.erase(it);533return 1;534}535return 0;536}537538mapped_type& operator[](const key_type& k)539{540const auto iter = this->find(k);541if(iter == this->end())542{543this->container_.emplace_back(k, mapped_type{});544return this->container_.back().second;545}546return iter->second;547}548549mapped_type const& operator[](const key_type& k) const550{551const auto iter = this->find(k);552if(iter == this->end())553{554throw std::out_of_range("ordered_map: no such element");555}556return iter->second;557}558559key_compare key_comp() const {return this->cmp_;}560561void swap(ordered_map& other)562{563container_.swap(other.container_);564}565566private:567568container_type container_;569};570571template<typename K, typename V, typename C, typename A>572bool operator==(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)573{574return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());575}576template<typename K, typename V, typename C, typename A>577bool operator!=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)578{579return !(lhs == rhs);580}581template<typename K, typename V, typename C, typename A>582bool operator<(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)583{584return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());585}586template<typename K, typename V, typename C, typename A>587bool operator>(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)588{589return rhs < lhs;590}591template<typename K, typename V, typename C, typename A>592bool operator<=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)593{594return !(lhs > rhs);595}596template<typename K, typename V, typename C, typename A>597bool operator>=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)598{599return !(lhs < rhs);600}601602template<typename K, typename V, typename C, typename A>603void swap(ordered_map<K,V,C,A>& lhs, ordered_map<K,V,C,A>& rhs)604{605lhs.swap(rhs);606return;607}608609610} // TOML11_INLINE_VERSION_NAMESPACE611} // toml612#endif // TOML11_ORDERED_MAP_HPP613#ifndef TOML11_INTO_HPP614#define TOML11_INTO_HPP615616namespace toml617{618inline namespace TOML11_INLINE_VERSION_NAMESPACE619{620621template<typename T>622struct into;623// {624// static toml::value into_toml(const T& user_defined_type)625// {626// // User-defined conversions ...627// }628// };629630} // TOML11_INLINE_VERSION_NAMESPACE631} // toml632#endif // TOML11_INTO_HPP633#ifndef TOML11_FROM_HPP634#define TOML11_FROM_HPP635636namespace toml637{638inline namespace TOML11_INLINE_VERSION_NAMESPACE639{640641template<typename T>642struct from;643// {644// static T from_toml(const toml::value& v)645// {646// // User-defined conversions ...647// }648// };649650} // TOML11_INLINE_VERSION_NAMESPACE651} // toml652#endif // TOML11_FROM_HPP653#ifndef TOML11_FORMAT_HPP654#define TOML11_FORMAT_HPP655656#ifndef TOML11_FORMAT_FWD_HPP657#define TOML11_FORMAT_FWD_HPP658659#include <iosfwd>660#include <string>661#include <utility>662663#include <cstddef>664#include <cstdint>665666667namespace toml668{669inline namespace TOML11_INLINE_VERSION_NAMESPACE670{671672// toml types with serialization info673674enum class indent_char : std::uint8_t675{676space, // use space677tab, // use tab678none // no indent679};680681std::ostream& operator<<(std::ostream& os, const indent_char& c);682std::string to_string(const indent_char c);683684// ----------------------------------------------------------------------------685// boolean686687struct boolean_format_info688{689// nothing, for now690};691692inline bool operator==(const boolean_format_info&, const boolean_format_info&) noexcept693{694return true;695}696inline bool operator!=(const boolean_format_info&, const boolean_format_info&) noexcept697{698return false;699}700701// ----------------------------------------------------------------------------702// integer703704enum class integer_format : std::uint8_t705{706dec = 0,707bin = 1,708oct = 2,709hex = 3,710};711712std::ostream& operator<<(std::ostream& os, const integer_format f);713std::string to_string(const integer_format);714715struct integer_format_info716{717integer_format fmt = integer_format::dec;718bool uppercase = true; // hex with uppercase719std::size_t width = 0; // minimal width (may exceed)720std::size_t spacer = 0; // position of `_` (if 0, no spacer)721std::string suffix = ""; // _suffix (library extension)722};723724bool operator==(const integer_format_info&, const integer_format_info&) noexcept;725bool operator!=(const integer_format_info&, const integer_format_info&) noexcept;726727// ----------------------------------------------------------------------------728// floating729730enum class floating_format : std::uint8_t731{732defaultfloat = 0,733fixed = 1, // does not include exponential part734scientific = 2, // always include exponential part735hex = 3 // hexfloat extension736};737738std::ostream& operator<<(std::ostream& os, const floating_format f);739std::string to_string(const floating_format);740741struct floating_format_info742{743floating_format fmt = floating_format::defaultfloat;744std::size_t prec = 0; // precision (if 0, use the default)745std::string suffix = ""; // 1.0e+2_suffix (library extension)746};747748bool operator==(const floating_format_info&, const floating_format_info&) noexcept;749bool operator!=(const floating_format_info&, const floating_format_info&) noexcept;750751// ----------------------------------------------------------------------------752// string753754enum class string_format : std::uint8_t755{756basic = 0,757literal = 1,758multiline_basic = 2,759multiline_literal = 3760};761762std::ostream& operator<<(std::ostream& os, const string_format f);763std::string to_string(const string_format);764765struct string_format_info766{767string_format fmt = string_format::basic;768bool start_with_newline = false;769};770771bool operator==(const string_format_info&, const string_format_info&) noexcept;772bool operator!=(const string_format_info&, const string_format_info&) noexcept;773774// ----------------------------------------------------------------------------775// datetime776777enum class datetime_delimiter_kind : std::uint8_t778{779upper_T = 0,780lower_t = 1,781space = 2,782};783std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d);784std::string to_string(const datetime_delimiter_kind);785786struct offset_datetime_format_info787{788datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T;789bool has_seconds = true;790std::size_t subsecond_precision = 6; // [us]791};792793bool operator==(const offset_datetime_format_info&, const offset_datetime_format_info&) noexcept;794bool operator!=(const offset_datetime_format_info&, const offset_datetime_format_info&) noexcept;795796struct local_datetime_format_info797{798datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T;799bool has_seconds = true;800std::size_t subsecond_precision = 6; // [us]801};802803bool operator==(const local_datetime_format_info&, const local_datetime_format_info&) noexcept;804bool operator!=(const local_datetime_format_info&, const local_datetime_format_info&) noexcept;805806struct local_date_format_info807{808// nothing, for now809};810811bool operator==(const local_date_format_info&, const local_date_format_info&) noexcept;812bool operator!=(const local_date_format_info&, const local_date_format_info&) noexcept;813814struct local_time_format_info815{816bool has_seconds = true;817std::size_t subsecond_precision = 6; // [us]818};819820bool operator==(const local_time_format_info&, const local_time_format_info&) noexcept;821bool operator!=(const local_time_format_info&, const local_time_format_info&) noexcept;822823// ----------------------------------------------------------------------------824// array825826enum class array_format : std::uint8_t827{828default_format = 0,829oneline = 1,830multiline = 2,831array_of_tables = 3 // [[format.in.this.way]]832};833834std::ostream& operator<<(std::ostream& os, const array_format f);835std::string to_string(const array_format);836837struct array_format_info838{839array_format fmt = array_format::default_format;840indent_char indent_type = indent_char::space;841std::int32_t body_indent = 4; // indent in case of multiline842std::int32_t closing_indent = 0; // indent of `]`843};844845bool operator==(const array_format_info&, const array_format_info&) noexcept;846bool operator!=(const array_format_info&, const array_format_info&) noexcept;847848// ----------------------------------------------------------------------------849// table850851enum class table_format : std::uint8_t852{853multiline = 0, // [foo] \n bar = "baz"854oneline = 1, // foo = {bar = "baz"}855dotted = 2, // foo.bar = "baz"856multiline_oneline = 3, // foo = { \n bar = "baz" \n }857implicit = 4 // [x] defined by [x.y.z]. skip in serializer.858};859860std::ostream& operator<<(std::ostream& os, const table_format f);861std::string to_string(const table_format);862863struct table_format_info864{865table_format fmt = table_format::multiline;866indent_char indent_type = indent_char::space;867std::int32_t body_indent = 0; // indent of values868std::int32_t name_indent = 0; // indent of [table]869std::int32_t closing_indent = 0; // in case of {inline-table}870};871872bool operator==(const table_format_info&, const table_format_info&) noexcept;873bool operator!=(const table_format_info&, const table_format_info&) noexcept;874875// ----------------------------------------------------------------------------876// wrapper877878namespace detail879{880template<typename T, typename F>881struct value_with_format882{883using value_type = T;884using format_type = F;885886value_with_format() = default;887~value_with_format() = default;888value_with_format(const value_with_format&) = default;889value_with_format(value_with_format&&) = default;890value_with_format& operator=(const value_with_format&) = default;891value_with_format& operator=(value_with_format&&) = default;892893value_with_format(value_type v, format_type f)894: value{std::move(v)}, format{std::move(f)}895{}896897template<typename U>898value_with_format(value_with_format<U, format_type> other)899: value{std::move(other.value)}, format{std::move(other.format)}900{}901902value_type value;903format_type format;904};905} // detail906907} // TOML11_INLINE_VERSION_NAMESPACE908} // namespace toml909#endif // TOML11_FORMAT_FWD_HPP910911#if ! defined(TOML11_COMPILE_SOURCES)912#ifndef TOML11_FORMAT_IMPL_HPP913#define TOML11_FORMAT_IMPL_HPP914915916#include <ostream>917#include <sstream>918919namespace toml920{921inline namespace TOML11_INLINE_VERSION_NAMESPACE922{923924// toml types with serialization info925926TOML11_INLINE std::ostream& operator<<(std::ostream& os, const indent_char& c)927{928switch(c)929{930case indent_char::space: {os << "space" ; break;}931case indent_char::tab: {os << "tab" ; break;}932case indent_char::none: {os << "none" ; break;}933default:934{935os << "unknown indent char: " << static_cast<std::uint8_t>(c);936}937}938return os;939}940941TOML11_INLINE std::string to_string(const indent_char c)942{943std::ostringstream oss;944oss << c;945return oss.str();946}947948// ----------------------------------------------------------------------------949// boolean950951// ----------------------------------------------------------------------------952// integer953954TOML11_INLINE std::ostream& operator<<(std::ostream& os, const integer_format f)955{956switch(f)957{958case integer_format::dec: {os << "dec"; break;}959case integer_format::bin: {os << "bin"; break;}960case integer_format::oct: {os << "oct"; break;}961case integer_format::hex: {os << "hex"; break;}962default:963{964os << "unknown integer_format: " << static_cast<std::uint8_t>(f);965break;966}967}968return os;969}970TOML11_INLINE std::string to_string(const integer_format c)971{972std::ostringstream oss;973oss << c;974return oss.str();975}976977978TOML11_INLINE bool operator==(const integer_format_info& lhs, const integer_format_info& rhs) noexcept979{980return lhs.fmt == rhs.fmt &&981lhs.uppercase == rhs.uppercase &&982lhs.width == rhs.width &&983lhs.spacer == rhs.spacer &&984lhs.suffix == rhs.suffix ;985}986TOML11_INLINE bool operator!=(const integer_format_info& lhs, const integer_format_info& rhs) noexcept987{988return !(lhs == rhs);989}990991// ----------------------------------------------------------------------------992// floating993994TOML11_INLINE std::ostream& operator<<(std::ostream& os, const floating_format f)995{996switch(f)997{998case floating_format::defaultfloat: {os << "defaultfloat"; break;}999case floating_format::fixed : {os << "fixed" ; break;}1000case floating_format::scientific : {os << "scientific" ; break;}1001case floating_format::hex : {os << "hex" ; break;}1002default:1003{1004os << "unknown floating_format: " << static_cast<std::uint8_t>(f);1005break;1006}1007}1008return os;1009}1010TOML11_INLINE std::string to_string(const floating_format c)1011{1012std::ostringstream oss;1013oss << c;1014return oss.str();1015}10161017TOML11_INLINE bool operator==(const floating_format_info& lhs, const floating_format_info& rhs) noexcept1018{1019return lhs.fmt == rhs.fmt &&1020lhs.prec == rhs.prec &&1021lhs.suffix == rhs.suffix ;1022}1023TOML11_INLINE bool operator!=(const floating_format_info& lhs, const floating_format_info& rhs) noexcept1024{1025return !(lhs == rhs);1026}10271028// ----------------------------------------------------------------------------1029// string10301031TOML11_INLINE std::ostream& operator<<(std::ostream& os, const string_format f)1032{1033switch(f)1034{1035case string_format::basic : {os << "basic" ; break;}1036case string_format::literal : {os << "literal" ; break;}1037case string_format::multiline_basic : {os << "multiline_basic" ; break;}1038case string_format::multiline_literal: {os << "multiline_literal"; break;}1039default:1040{1041os << "unknown string_format: " << static_cast<std::uint8_t>(f);1042break;1043}1044}1045return os;1046}1047TOML11_INLINE std::string to_string(const string_format c)1048{1049std::ostringstream oss;1050oss << c;1051return oss.str();1052}10531054TOML11_INLINE bool operator==(const string_format_info& lhs, const string_format_info& rhs) noexcept1055{1056return lhs.fmt == rhs.fmt &&1057lhs.start_with_newline == rhs.start_with_newline ;1058}1059TOML11_INLINE bool operator!=(const string_format_info& lhs, const string_format_info& rhs) noexcept1060{1061return !(lhs == rhs);1062}1063// ----------------------------------------------------------------------------1064// datetime10651066TOML11_INLINE std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d)1067{1068switch(d)1069{1070case datetime_delimiter_kind::upper_T: { os << "upper_T, "; break; }1071case datetime_delimiter_kind::lower_t: { os << "lower_t, "; break; }1072case datetime_delimiter_kind::space: { os << "space, "; break; }1073default:1074{1075os << "unknown datetime delimiter: " << static_cast<std::uint8_t>(d);1076break;1077}1078}1079return os;1080}1081TOML11_INLINE std::string to_string(const datetime_delimiter_kind c)1082{1083std::ostringstream oss;1084oss << c;1085return oss.str();1086}10871088TOML11_INLINE bool operator==(const offset_datetime_format_info& lhs, const offset_datetime_format_info& rhs) noexcept1089{1090return lhs.delimiter == rhs.delimiter &&1091lhs.has_seconds == rhs.has_seconds &&1092lhs.subsecond_precision == rhs.subsecond_precision ;1093}1094TOML11_INLINE bool operator!=(const offset_datetime_format_info& lhs, const offset_datetime_format_info& rhs) noexcept1095{1096return !(lhs == rhs);1097}10981099TOML11_INLINE bool operator==(const local_datetime_format_info& lhs, const local_datetime_format_info& rhs) noexcept1100{1101return lhs.delimiter == rhs.delimiter &&1102lhs.has_seconds == rhs.has_seconds &&1103lhs.subsecond_precision == rhs.subsecond_precision ;1104}1105TOML11_INLINE bool operator!=(const local_datetime_format_info& lhs, const local_datetime_format_info& rhs) noexcept1106{1107return !(lhs == rhs);1108}11091110TOML11_INLINE bool operator==(const local_date_format_info&, const local_date_format_info&) noexcept1111{1112return true;1113}1114TOML11_INLINE bool operator!=(const local_date_format_info& lhs, const local_date_format_info& rhs) noexcept1115{1116return !(lhs == rhs);1117}11181119TOML11_INLINE bool operator==(const local_time_format_info& lhs, const local_time_format_info& rhs) noexcept1120{1121return lhs.has_seconds == rhs.has_seconds &&1122lhs.subsecond_precision == rhs.subsecond_precision ;1123}1124TOML11_INLINE bool operator!=(const local_time_format_info& lhs, const local_time_format_info& rhs) noexcept1125{1126return !(lhs == rhs);1127}11281129// ----------------------------------------------------------------------------1130// array11311132TOML11_INLINE std::ostream& operator<<(std::ostream& os, const array_format f)1133{1134switch(f)1135{1136case array_format::default_format : {os << "default_format" ; break;}1137case array_format::oneline : {os << "oneline" ; break;}1138case array_format::multiline : {os << "multiline" ; break;}1139case array_format::array_of_tables: {os << "array_of_tables"; break;}1140default:1141{1142os << "unknown array_format: " << static_cast<std::uint8_t>(f);1143break;1144}1145}1146return os;1147}1148TOML11_INLINE std::string to_string(const array_format c)1149{1150std::ostringstream oss;1151oss << c;1152return oss.str();1153}11541155TOML11_INLINE bool operator==(const array_format_info& lhs, const array_format_info& rhs) noexcept1156{1157return lhs.fmt == rhs.fmt &&1158lhs.indent_type == rhs.indent_type &&1159lhs.body_indent == rhs.body_indent &&1160lhs.closing_indent == rhs.closing_indent ;1161}1162TOML11_INLINE bool operator!=(const array_format_info& lhs, const array_format_info& rhs) noexcept1163{1164return !(lhs == rhs);1165}11661167// ----------------------------------------------------------------------------1168// table11691170TOML11_INLINE std::ostream& operator<<(std::ostream& os, const table_format f)1171{1172switch(f)1173{1174case table_format::multiline : {os << "multiline" ; break;}1175case table_format::oneline : {os << "oneline" ; break;}1176case table_format::dotted : {os << "dotted" ; break;}1177case table_format::multiline_oneline: {os << "multiline_oneline"; break;}1178case table_format::implicit : {os << "implicit" ; break;}1179default:1180{1181os << "unknown table_format: " << static_cast<std::uint8_t>(f);1182break;1183}1184}1185return os;1186}1187TOML11_INLINE std::string to_string(const table_format c)1188{1189std::ostringstream oss;1190oss << c;1191return oss.str();1192}11931194TOML11_INLINE bool operator==(const table_format_info& lhs, const table_format_info& rhs) noexcept1195{1196return lhs.fmt == rhs.fmt &&1197lhs.indent_type == rhs.indent_type &&1198lhs.body_indent == rhs.body_indent &&1199lhs.name_indent == rhs.name_indent &&1200lhs.closing_indent == rhs.closing_indent ;1201}1202TOML11_INLINE bool operator!=(const table_format_info& lhs, const table_format_info& rhs) noexcept1203{1204return !(lhs == rhs);1205}12061207} // TOML11_INLINE_VERSION_NAMESPACE1208} // namespace toml1209#endif // TOML11_FORMAT_IMPL_HPP1210#endif12111212#endif// TOML11_FORMAT_HPP1213#ifndef TOML11_EXCEPTION_HPP1214#define TOML11_EXCEPTION_HPP12151216#include <exception>121712181219namespace toml1220{1221inline namespace TOML11_INLINE_VERSION_NAMESPACE1222{12231224struct exception : public std::exception1225{1226public:1227virtual ~exception() noexcept override = default;1228virtual const char* what() const noexcept override {return "";}1229};12301231} // TOML11_INLINE_VERSION_NAMESPACE1232} // toml1233#endif // TOMl11_EXCEPTION_HPP1234#ifndef TOML11_DATETIME_HPP1235#define TOML11_DATETIME_HPP12361237#ifndef TOML11_DATETIME_FWD_HPP1238#define TOML11_DATETIME_FWD_HPP12391240#include <chrono>1241#include <iosfwd>1242#include <string>12431244#include <cstdint>1245#include <cstdlib>1246#include <ctime>124712481249namespace toml1250{1251inline namespace TOML11_INLINE_VERSION_NAMESPACE1252{12531254enum class month_t : std::uint8_t1255{1256Jan = 0,1257Feb = 1,1258Mar = 2,1259Apr = 3,1260May = 4,1261Jun = 5,1262Jul = 6,1263Aug = 7,1264Sep = 8,1265Oct = 9,1266Nov = 10,1267Dec = 111268};12691270// ----------------------------------------------------------------------------12711272struct local_date1273{1274std::int16_t year{0}; // A.D. (like, 2018)1275std::uint8_t month{0}; // [0, 11]1276std::uint8_t day{0}; // [1, 31]12771278local_date(int y, month_t m, int d)1279: year {static_cast<std::int16_t>(y)},1280month{static_cast<std::uint8_t>(m)},1281day {static_cast<std::uint8_t>(d)}1282{}12831284explicit local_date(const std::tm& t)1285: year {static_cast<std::int16_t>(t.tm_year + 1900)},1286month{static_cast<std::uint8_t>(t.tm_mon)},1287day {static_cast<std::uint8_t>(t.tm_mday)}1288{}12891290explicit local_date(const std::chrono::system_clock::time_point& tp);1291explicit local_date(const std::time_t t);12921293operator std::chrono::system_clock::time_point() const;1294operator std::time_t() const;12951296local_date() = default;1297~local_date() = default;1298local_date(local_date const&) = default;1299local_date(local_date&&) = default;1300local_date& operator=(local_date const&) = default;1301local_date& operator=(local_date&&) = default;1302};1303bool operator==(const local_date& lhs, const local_date& rhs);1304bool operator!=(const local_date& lhs, const local_date& rhs);1305bool operator< (const local_date& lhs, const local_date& rhs);1306bool operator<=(const local_date& lhs, const local_date& rhs);1307bool operator> (const local_date& lhs, const local_date& rhs);1308bool operator>=(const local_date& lhs, const local_date& rhs);13091310std::ostream& operator<<(std::ostream& os, const local_date& date);1311std::string to_string(const local_date& date);13121313// -----------------------------------------------------------------------------13141315struct local_time1316{1317std::uint8_t hour{0}; // [0, 23]1318std::uint8_t minute{0}; // [0, 59]1319std::uint8_t second{0}; // [0, 60]1320std::uint16_t millisecond{0}; // [0, 999]1321std::uint16_t microsecond{0}; // [0, 999]1322std::uint16_t nanosecond{0}; // [0, 999]13231324local_time(int h, int m, int s,1325int ms = 0, int us = 0, int ns = 0)1326: hour {static_cast<std::uint8_t>(h)},1327minute{static_cast<std::uint8_t>(m)},1328second{static_cast<std::uint8_t>(s)},1329millisecond{static_cast<std::uint16_t>(ms)},1330microsecond{static_cast<std::uint16_t>(us)},1331nanosecond {static_cast<std::uint16_t>(ns)}1332{}13331334explicit local_time(const std::tm& t)1335: hour {static_cast<std::uint8_t>(t.tm_hour)},1336minute{static_cast<std::uint8_t>(t.tm_min )},1337second{static_cast<std::uint8_t>(t.tm_sec )},1338millisecond{0}, microsecond{0}, nanosecond{0}1339{}13401341template<typename Rep, typename Period>1342explicit local_time(const std::chrono::duration<Rep, Period>& t)1343{1344const auto h = std::chrono::duration_cast<std::chrono::hours>(t);1345this->hour = static_cast<std::uint8_t>(h.count());1346const auto t2 = t - h;1347const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);1348this->minute = static_cast<std::uint8_t>(m.count());1349const auto t3 = t2 - m;1350const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);1351this->second = static_cast<std::uint8_t>(s.count());1352const auto t4 = t3 - s;1353const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);1354this->millisecond = static_cast<std::uint16_t>(ms.count());1355const auto t5 = t4 - ms;1356const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);1357this->microsecond = static_cast<std::uint16_t>(us.count());1358const auto t6 = t5 - us;1359const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);1360this->nanosecond = static_cast<std::uint16_t>(ns.count());1361}13621363operator std::chrono::nanoseconds() const;13641365local_time() = default;1366~local_time() = default;1367local_time(local_time const&) = default;1368local_time(local_time&&) = default;1369local_time& operator=(local_time const&) = default;1370local_time& operator=(local_time&&) = default;1371};13721373bool operator==(const local_time& lhs, const local_time& rhs);1374bool operator!=(const local_time& lhs, const local_time& rhs);1375bool operator< (const local_time& lhs, const local_time& rhs);1376bool operator<=(const local_time& lhs, const local_time& rhs);1377bool operator> (const local_time& lhs, const local_time& rhs);1378bool operator>=(const local_time& lhs, const local_time& rhs);13791380std::ostream& operator<<(std::ostream& os, const local_time& time);1381std::string to_string(const local_time& time);13821383// ----------------------------------------------------------------------------13841385struct time_offset1386{1387std::int8_t hour{0}; // [-12, 12]1388std::int8_t minute{0}; // [-59, 59]13891390time_offset(int h, int m)1391: hour {static_cast<std::int8_t>(h)},1392minute{static_cast<std::int8_t>(m)}1393{}13941395operator std::chrono::minutes() const;13961397time_offset() = default;1398~time_offset() = default;1399time_offset(time_offset const&) = default;1400time_offset(time_offset&&) = default;1401time_offset& operator=(time_offset const&) = default;1402time_offset& operator=(time_offset&&) = default;1403};14041405bool operator==(const time_offset& lhs, const time_offset& rhs);1406bool operator!=(const time_offset& lhs, const time_offset& rhs);1407bool operator< (const time_offset& lhs, const time_offset& rhs);1408bool operator<=(const time_offset& lhs, const time_offset& rhs);1409bool operator> (const time_offset& lhs, const time_offset& rhs);1410bool operator>=(const time_offset& lhs, const time_offset& rhs);14111412std::ostream& operator<<(std::ostream& os, const time_offset& offset);14131414std::string to_string(const time_offset& offset);14151416// -----------------------------------------------------------------------------14171418struct local_datetime1419{1420local_date date{};1421local_time time{};14221423local_datetime(local_date d, local_time t): date{d}, time{t} {}14241425explicit local_datetime(const std::tm& t): date{t}, time{t}{}14261427explicit local_datetime(const std::chrono::system_clock::time_point& tp);1428explicit local_datetime(const std::time_t t);14291430operator std::chrono::system_clock::time_point() const;1431operator std::time_t() const;14321433local_datetime() = default;1434~local_datetime() = default;1435local_datetime(local_datetime const&) = default;1436local_datetime(local_datetime&&) = default;1437local_datetime& operator=(local_datetime const&) = default;1438local_datetime& operator=(local_datetime&&) = default;1439};14401441bool operator==(const local_datetime& lhs, const local_datetime& rhs);1442bool operator!=(const local_datetime& lhs, const local_datetime& rhs);1443bool operator< (const local_datetime& lhs, const local_datetime& rhs);1444bool operator<=(const local_datetime& lhs, const local_datetime& rhs);1445bool operator> (const local_datetime& lhs, const local_datetime& rhs);1446bool operator>=(const local_datetime& lhs, const local_datetime& rhs);14471448std::ostream& operator<<(std::ostream& os, const local_datetime& dt);14491450std::string to_string(const local_datetime& dt);14511452// -----------------------------------------------------------------------------14531454struct offset_datetime1455{1456local_date date{};1457local_time time{};1458time_offset offset{};14591460offset_datetime(local_date d, local_time t, time_offset o)1461: date{d}, time{t}, offset{o}1462{}1463offset_datetime(const local_datetime& dt, time_offset o)1464: date{dt.date}, time{dt.time}, offset{o}1465{}1466// use the current local timezone offset1467explicit offset_datetime(const local_datetime& ld);1468explicit offset_datetime(const std::chrono::system_clock::time_point& tp);1469explicit offset_datetime(const std::time_t& t);1470explicit offset_datetime(const std::tm& t);14711472operator std::chrono::system_clock::time_point() const;14731474operator std::time_t() const;14751476offset_datetime() = default;1477~offset_datetime() = default;1478offset_datetime(offset_datetime const&) = default;1479offset_datetime(offset_datetime&&) = default;1480offset_datetime& operator=(offset_datetime const&) = default;1481offset_datetime& operator=(offset_datetime&&) = default;14821483private:14841485static time_offset get_local_offset(const std::time_t* tp);1486};14871488bool operator==(const offset_datetime& lhs, const offset_datetime& rhs);1489bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs);1490bool operator< (const offset_datetime& lhs, const offset_datetime& rhs);1491bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs);1492bool operator> (const offset_datetime& lhs, const offset_datetime& rhs);1493bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs);14941495std::ostream& operator<<(std::ostream& os, const offset_datetime& dt);14961497std::string to_string(const offset_datetime& dt);14981499} // TOML11_INLINE_VERSION_NAMESPACE1500} // toml1501#endif // TOML11_DATETIME_FWD_HPP15021503#if ! defined(TOML11_COMPILE_SOURCES)1504#ifndef TOML11_DATETIME_IMPL_HPP1505#define TOML11_DATETIME_IMPL_HPP150615071508#include <array>1509#include <iomanip>1510#include <ostream>1511#include <sstream>1512#include <tuple>15131514#include <cstdlib>1515#include <ctime>15161517namespace toml1518{1519inline namespace TOML11_INLINE_VERSION_NAMESPACE1520{15211522// To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is1523// provided in the absolutely same purpose, but C++11 is actually not compatible1524// with C11. We need to dispatch the function depending on the OS.1525namespace detail1526{1527// TODO: find more sophisticated way to handle this1528#if defined(_MSC_VER)1529TOML11_INLINE std::tm localtime_s(const std::time_t* src)1530{1531std::tm dst;1532const auto result = ::localtime_s(&dst, src);1533if (result) { throw std::runtime_error("localtime_s failed."); }1534return dst;1535}1536TOML11_INLINE std::tm gmtime_s(const std::time_t* src)1537{1538std::tm dst;1539const auto result = ::gmtime_s(&dst, src);1540if (result) { throw std::runtime_error("gmtime_s failed."); }1541return dst;1542}1543#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)1544TOML11_INLINE std::tm localtime_s(const std::time_t* src)1545{1546std::tm dst;1547const auto result = ::localtime_r(src, &dst);1548if (!result) { throw std::runtime_error("localtime_r failed."); }1549return dst;1550}1551TOML11_INLINE std::tm gmtime_s(const std::time_t* src)1552{1553std::tm dst;1554const auto result = ::gmtime_r(src, &dst);1555if (!result) { throw std::runtime_error("gmtime_r failed."); }1556return dst;1557}1558#else // fallback. not threadsafe1559TOML11_INLINE std::tm localtime_s(const std::time_t* src)1560{1561const auto result = std::localtime(src);1562if (!result) { throw std::runtime_error("localtime failed."); }1563return *result;1564}1565TOML11_INLINE std::tm gmtime_s(const std::time_t* src)1566{1567const auto result = std::gmtime(src);1568if (!result) { throw std::runtime_error("gmtime failed."); }1569return *result;1570}1571#endif1572} // detail15731574// ----------------------------------------------------------------------------15751576TOML11_INLINE local_date::local_date(const std::chrono::system_clock::time_point& tp)1577{1578const auto t = std::chrono::system_clock::to_time_t(tp);1579const auto time = detail::localtime_s(&t);1580*this = local_date(time);1581}15821583TOML11_INLINE local_date::local_date(const std::time_t t)1584: local_date{std::chrono::system_clock::from_time_t(t)}1585{}15861587TOML11_INLINE local_date::operator std::chrono::system_clock::time_point() const1588{1589// std::mktime returns date as local time zone. no conversion needed1590std::tm t;1591t.tm_sec = 0;1592t.tm_min = 0;1593t.tm_hour = 0;1594t.tm_mday = static_cast<int>(this->day);1595t.tm_mon = static_cast<int>(this->month);1596t.tm_year = static_cast<int>(this->year) - 1900;1597t.tm_wday = 0; // the value will be ignored1598t.tm_yday = 0; // the value will be ignored1599t.tm_isdst = -1;1600return std::chrono::system_clock::from_time_t(std::mktime(&t));1601}16021603TOML11_INLINE local_date::operator std::time_t() const1604{1605return std::chrono::system_clock::to_time_t(1606std::chrono::system_clock::time_point(*this));1607}16081609TOML11_INLINE bool operator==(const local_date& lhs, const local_date& rhs)1610{1611return std::make_tuple(lhs.year, lhs.month, lhs.day) ==1612std::make_tuple(rhs.year, rhs.month, rhs.day);1613}1614TOML11_INLINE bool operator!=(const local_date& lhs, const local_date& rhs)1615{1616return !(lhs == rhs);1617}1618TOML11_INLINE bool operator< (const local_date& lhs, const local_date& rhs)1619{1620return std::make_tuple(lhs.year, lhs.month, lhs.day) <1621std::make_tuple(rhs.year, rhs.month, rhs.day);1622}1623TOML11_INLINE bool operator<=(const local_date& lhs, const local_date& rhs)1624{1625return (lhs < rhs) || (lhs == rhs);1626}1627TOML11_INLINE bool operator> (const local_date& lhs, const local_date& rhs)1628{1629return !(lhs <= rhs);1630}1631TOML11_INLINE bool operator>=(const local_date& lhs, const local_date& rhs)1632{1633return !(lhs < rhs);1634}16351636TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_date& date)1637{1638os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';1639os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';1640os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day ) ;1641return os;1642}16431644TOML11_INLINE std::string to_string(const local_date& date)1645{1646std::ostringstream oss;1647oss.imbue(std::locale::classic());1648oss << date;1649return oss.str();1650}16511652// -----------------------------------------------------------------------------16531654TOML11_INLINE local_time::operator std::chrono::nanoseconds() const1655{1656return std::chrono::nanoseconds (this->nanosecond) +1657std::chrono::microseconds(this->microsecond) +1658std::chrono::milliseconds(this->millisecond) +1659std::chrono::seconds(this->second) +1660std::chrono::minutes(this->minute) +1661std::chrono::hours(this->hour);1662}16631664TOML11_INLINE bool operator==(const local_time& lhs, const local_time& rhs)1665{1666return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) ==1667std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);1668}1669TOML11_INLINE bool operator!=(const local_time& lhs, const local_time& rhs)1670{1671return !(lhs == rhs);1672}1673TOML11_INLINE bool operator< (const local_time& lhs, const local_time& rhs)1674{1675return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) <1676std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);1677}1678TOML11_INLINE bool operator<=(const local_time& lhs, const local_time& rhs)1679{1680return (lhs < rhs) || (lhs == rhs);1681}1682TOML11_INLINE bool operator> (const local_time& lhs, const local_time& rhs)1683{1684return !(lhs <= rhs);1685}1686TOML11_INLINE bool operator>=(const local_time& lhs, const local_time& rhs)1687{1688return !(lhs < rhs);1689}16901691TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_time& time)1692{1693os << std::setfill('0') << std::setw(2) << static_cast<int>(time.hour ) << ':';1694os << std::setfill('0') << std::setw(2) << static_cast<int>(time.minute) << ':';1695os << std::setfill('0') << std::setw(2) << static_cast<int>(time.second);1696if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0)1697{1698os << '.';1699os << std::setfill('0') << std::setw(3) << static_cast<int>(time.millisecond);1700if(time.microsecond != 0 || time.nanosecond != 0)1701{1702os << std::setfill('0') << std::setw(3) << static_cast<int>(time.microsecond);1703if(time.nanosecond != 0)1704{1705os << std::setfill('0') << std::setw(3) << static_cast<int>(time.nanosecond);1706}1707}1708}1709return os;1710}17111712TOML11_INLINE std::string to_string(const local_time& time)1713{1714std::ostringstream oss;1715oss.imbue(std::locale::classic());1716oss << time;1717return oss.str();1718}17191720// ----------------------------------------------------------------------------17211722TOML11_INLINE time_offset::operator std::chrono::minutes() const1723{1724return std::chrono::minutes(this->minute) +1725std::chrono::hours(this->hour);1726}17271728TOML11_INLINE bool operator==(const time_offset& lhs, const time_offset& rhs)1729{1730return std::make_tuple(lhs.hour, lhs.minute) ==1731std::make_tuple(rhs.hour, rhs.minute);1732}1733TOML11_INLINE bool operator!=(const time_offset& lhs, const time_offset& rhs)1734{1735return !(lhs == rhs);1736}1737TOML11_INLINE bool operator< (const time_offset& lhs, const time_offset& rhs)1738{1739return std::make_tuple(lhs.hour, lhs.minute) <1740std::make_tuple(rhs.hour, rhs.minute);1741}1742TOML11_INLINE bool operator<=(const time_offset& lhs, const time_offset& rhs)1743{1744return (lhs < rhs) || (lhs == rhs);1745}1746TOML11_INLINE bool operator> (const time_offset& lhs, const time_offset& rhs)1747{1748return !(lhs <= rhs);1749}1750TOML11_INLINE bool operator>=(const time_offset& lhs, const time_offset& rhs)1751{1752return !(lhs < rhs);1753}17541755TOML11_INLINE std::ostream& operator<<(std::ostream& os, const time_offset& offset)1756{1757if(offset.hour == 0 && offset.minute == 0)1758{1759os << 'Z';1760return os;1761}1762int minute = static_cast<int>(offset.hour) * 60 + offset.minute;1763if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';}1764os << std::setfill('0') << std::setw(2) << minute / 60 << ':';1765os << std::setfill('0') << std::setw(2) << minute % 60;1766return os;1767}17681769TOML11_INLINE std::string to_string(const time_offset& offset)1770{1771std::ostringstream oss;1772oss.imbue(std::locale::classic());1773oss << offset;1774return oss.str();1775}17761777// -----------------------------------------------------------------------------17781779TOML11_INLINE local_datetime::local_datetime(const std::chrono::system_clock::time_point& tp)1780{1781const auto t = std::chrono::system_clock::to_time_t(tp);1782std::tm ltime = detail::localtime_s(&t);17831784this->date = local_date(ltime);1785this->time = local_time(ltime);17861787// std::tm lacks subsecond information, so diff between tp and tm1788// can be used to get millisecond & microsecond information.1789const auto t_diff = tp -1790std::chrono::system_clock::from_time_t(std::mktime(<ime));1791this->time.millisecond = static_cast<std::uint16_t>(1792std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());1793this->time.microsecond = static_cast<std::uint16_t>(1794std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());1795this->time.nanosecond = static_cast<std::uint16_t>(1796std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());1797}17981799TOML11_INLINE local_datetime::local_datetime(const std::time_t t)1800: local_datetime{std::chrono::system_clock::from_time_t(t)}1801{}18021803TOML11_INLINE local_datetime::operator std::chrono::system_clock::time_point() const1804{1805using internal_duration =1806typename std::chrono::system_clock::time_point::duration;18071808// Normally DST begins at A.M. 3 or 4. If we re-use conversion operator1809// of local_date and local_time independently, the conversion fails if1810// it is the day when DST begins or ends. Since local_date considers the1811// time is 00:00 A.M. and local_time does not consider DST because it1812// does not have any date information. We need to consider both date and1813// time information at the same time to convert it correctly.18141815std::tm t;1816t.tm_sec = static_cast<int>(this->time.second);1817t.tm_min = static_cast<int>(this->time.minute);1818t.tm_hour = static_cast<int>(this->time.hour);1819t.tm_mday = static_cast<int>(this->date.day);1820t.tm_mon = static_cast<int>(this->date.month);1821t.tm_year = static_cast<int>(this->date.year) - 1900;1822t.tm_wday = 0; // the value will be ignored1823t.tm_yday = 0; // the value will be ignored1824t.tm_isdst = -1;18251826// std::mktime returns date as local time zone. no conversion needed1827auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));1828dt += std::chrono::duration_cast<internal_duration>(1829std::chrono::milliseconds(this->time.millisecond) +1830std::chrono::microseconds(this->time.microsecond) +1831std::chrono::nanoseconds (this->time.nanosecond));1832return dt;1833}18341835TOML11_INLINE local_datetime::operator std::time_t() const1836{1837return std::chrono::system_clock::to_time_t(1838std::chrono::system_clock::time_point(*this));1839}18401841TOML11_INLINE bool operator==(const local_datetime& lhs, const local_datetime& rhs)1842{1843return std::make_tuple(lhs.date, lhs.time) ==1844std::make_tuple(rhs.date, rhs.time);1845}1846TOML11_INLINE bool operator!=(const local_datetime& lhs, const local_datetime& rhs)1847{1848return !(lhs == rhs);1849}1850TOML11_INLINE bool operator< (const local_datetime& lhs, const local_datetime& rhs)1851{1852return std::make_tuple(lhs.date, lhs.time) <1853std::make_tuple(rhs.date, rhs.time);1854}1855TOML11_INLINE bool operator<=(const local_datetime& lhs, const local_datetime& rhs)1856{1857return (lhs < rhs) || (lhs == rhs);1858}1859TOML11_INLINE bool operator> (const local_datetime& lhs, const local_datetime& rhs)1860{1861return !(lhs <= rhs);1862}1863TOML11_INLINE bool operator>=(const local_datetime& lhs, const local_datetime& rhs)1864{1865return !(lhs < rhs);1866}18671868TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_datetime& dt)1869{1870os << dt.date << 'T' << dt.time;1871return os;1872}18731874TOML11_INLINE std::string to_string(const local_datetime& dt)1875{1876std::ostringstream oss;1877oss.imbue(std::locale::classic());1878oss << dt;1879return oss.str();1880}18811882// -----------------------------------------------------------------------------188318841885TOML11_INLINE offset_datetime::offset_datetime(const local_datetime& ld)1886: date{ld.date}, time{ld.time}, offset{get_local_offset(nullptr)}1887// use the current local timezone offset1888{}1889TOML11_INLINE offset_datetime::offset_datetime(const std::chrono::system_clock::time_point& tp)1890: offset{0, 0} // use gmtime1891{1892const auto timet = std::chrono::system_clock::to_time_t(tp);1893const auto tm = detail::gmtime_s(&timet);1894this->date = local_date(tm);1895this->time = local_time(tm);1896}1897TOML11_INLINE offset_datetime::offset_datetime(const std::time_t& t)1898: offset{0, 0} // use gmtime1899{1900const auto tm = detail::gmtime_s(&t);1901this->date = local_date(tm);1902this->time = local_time(tm);1903}1904TOML11_INLINE offset_datetime::offset_datetime(const std::tm& t)1905: offset{0, 0} // assume gmtime1906{1907this->date = local_date(t);1908this->time = local_time(t);1909}19101911TOML11_INLINE offset_datetime::operator std::chrono::system_clock::time_point() const1912{1913// get date-time1914using internal_duration =1915typename std::chrono::system_clock::time_point::duration;19161917// first, convert it to local date-time information in the same way as1918// local_datetime does. later we will use time_t to adjust time offset.1919std::tm t;1920t.tm_sec = static_cast<int>(this->time.second);1921t.tm_min = static_cast<int>(this->time.minute);1922t.tm_hour = static_cast<int>(this->time.hour);1923t.tm_mday = static_cast<int>(this->date.day);1924t.tm_mon = static_cast<int>(this->date.month);1925t.tm_year = static_cast<int>(this->date.year) - 1900;1926t.tm_wday = 0; // the value will be ignored1927t.tm_yday = 0; // the value will be ignored1928t.tm_isdst = -1;1929const std::time_t tp_loc = std::mktime(std::addressof(t));19301931auto tp = std::chrono::system_clock::from_time_t(tp_loc);1932tp += std::chrono::duration_cast<internal_duration>(1933std::chrono::milliseconds(this->time.millisecond) +1934std::chrono::microseconds(this->time.microsecond) +1935std::chrono::nanoseconds (this->time.nanosecond));19361937// Since mktime uses local time zone, it should be corrected.1938// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if1939// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need1940// to add `+09:00` to `03:00:00Z`.1941// Here, it uses the time_t converted from date-time info to handle1942// daylight saving time.1943const auto ofs = get_local_offset(std::addressof(tp_loc));1944tp += std::chrono::hours (ofs.hour);1945tp += std::chrono::minutes(ofs.minute);19461947// We got `12:00:00Z` by correcting local timezone applied by mktime.1948// Then we will apply the offset. Let's say `12:00:00-08:00` is given.1949// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.1950// So we need to subtract the offset.1951tp -= std::chrono::minutes(this->offset);1952return tp;1953}19541955TOML11_INLINE offset_datetime::operator std::time_t() const1956{1957return std::chrono::system_clock::to_time_t(1958std::chrono::system_clock::time_point(*this));1959}19601961TOML11_INLINE time_offset offset_datetime::get_local_offset(const std::time_t* tp)1962{1963// get local timezone with the same date-time information as mktime1964const auto t = detail::localtime_s(tp);19651966std::array<char, 6> buf;1967const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\01968if(result != 5)1969{1970throw std::runtime_error("toml::offset_datetime: cannot obtain "1971"timezone information of current env");1972}1973const int ofs = std::atoi(buf.data());1974const int ofs_h = ofs / 100;1975const int ofs_m = ofs - (ofs_h * 100);1976return time_offset(ofs_h, ofs_m);1977}19781979TOML11_INLINE bool operator==(const offset_datetime& lhs, const offset_datetime& rhs)1980{1981return std::make_tuple(lhs.date, lhs.time, lhs.offset) ==1982std::make_tuple(rhs.date, rhs.time, rhs.offset);1983}1984TOML11_INLINE bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs)1985{1986return !(lhs == rhs);1987}1988TOML11_INLINE bool operator< (const offset_datetime& lhs, const offset_datetime& rhs)1989{1990return std::make_tuple(lhs.date, lhs.time, lhs.offset) <1991std::make_tuple(rhs.date, rhs.time, rhs.offset);1992}1993TOML11_INLINE bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs)1994{1995return (lhs < rhs) || (lhs == rhs);1996}1997TOML11_INLINE bool operator> (const offset_datetime& lhs, const offset_datetime& rhs)1998{1999return !(lhs <= rhs);2000}2001TOML11_INLINE bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs)2002{2003return !(lhs < rhs);2004}20052006TOML11_INLINE std::ostream& operator<<(std::ostream& os, const offset_datetime& dt)2007{2008os << dt.date << 'T' << dt.time << dt.offset;2009return os;2010}20112012TOML11_INLINE std::string to_string(const offset_datetime& dt)2013{2014std::ostringstream oss;2015oss.imbue(std::locale::classic());2016oss << dt;2017return oss.str();2018}20192020} // TOML11_INLINE_VERSION_NAMESPACE2021} // toml2022#endif // TOML11_DATETIME_IMPL_HPP2023#endif20242025#endif // TOML11_DATETIME_HPP2026#ifndef TOML11_COMPAT_HPP2027#define TOML11_COMPAT_HPP202820292030#include <algorithm>2031#include <iterator>2032#include <memory>2033#include <string>2034#include <type_traits>20352036#include <cassert>20372038#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE2039# if __has_include(<bit>)2040# include <bit>2041# endif2042#endif20432044#include <cstring>20452046// ----------------------------------------------------------------------------20472048#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2049# if __has_cpp_attribute(deprecated)2050# define TOML11_HAS_ATTR_DEPRECATED 12051# endif2052#endif20532054#if defined(TOML11_HAS_ATTR_DEPRECATED)2055# define TOML11_DEPRECATED(msg) [[deprecated(msg)]]2056#elif defined(__GNUC__)2057# define TOML11_DEPRECATED(msg) __attribute__((deprecated(msg)))2058#elif defined(_MSC_VER)2059# define TOML11_DEPRECATED(msg) __declspec(deprecated(msg))2060#else2061# define TOML11_DEPRECATED(msg)2062#endif20632064// ----------------------------------------------------------------------------20652066#if defined(__cpp_if_constexpr)2067# if __cpp_if_constexpr >= 201606L2068# define TOML11_HAS_CONSTEXPR_IF 12069# endif2070#endif20712072#if defined(TOML11_HAS_CONSTEXPR_IF)2073# define TOML11_CONSTEXPR_IF if constexpr2074#else2075# define TOML11_CONSTEXPR_IF if2076#endif20772078// ----------------------------------------------------------------------------20792080#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2081# if defined(__cpp_lib_make_unique)2082# if __cpp_lib_make_unique >= 201304L2083# define TOML11_HAS_STD_MAKE_UNIQUE 12084# endif2085# endif2086#endif20872088namespace toml2089{2090inline namespace TOML11_INLINE_VERSION_NAMESPACE2091{2092namespace cxx2093{20942095#if defined(TOML11_HAS_STD_MAKE_UNIQUE)20962097using std::make_unique;20982099#else21002101template<typename T, typename ... Ts>2102std::unique_ptr<T> make_unique(Ts&& ... args)2103{2104return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));2105}21062107#endif // TOML11_HAS_STD_MAKE_UNIQUE21082109} // cxx2110} // TOML11_INLINE_VERSION_NAMESPACE2111} // toml21122113// ---------------------------------------------------------------------------21142115#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2116# if defined(__cpp_lib_make_reverse_iterator)2117# if __cpp_lib_make_reverse_iterator >= 201402L2118# define TOML11_HAS_STD_MAKE_REVERSE_ITERATOR 12119# endif2120# endif2121#endif21222123namespace toml2124{2125inline namespace TOML11_INLINE_VERSION_NAMESPACE2126{2127namespace cxx2128{2129# if defined(TOML11_HAS_STD_MAKE_REVERSE_ITERATOR)21302131using std::make_reverse_iterator;21322133#else21342135template<typename Iterator>2136std::reverse_iterator<Iterator> make_reverse_iterator(Iterator iter)2137{2138return std::reverse_iterator<Iterator>(iter);2139}21402141#endif // TOML11_HAS_STD_MAKE_REVERSE_ITERATOR21422143} // cxx2144} // TOML11_INLINE_VERSION_NAMESPACE2145} // toml21462147// ---------------------------------------------------------------------------21482149#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE2150# if defined(__cpp_lib_clamp)2151# if __cpp_lib_clamp >= 201603L2152# define TOML11_HAS_STD_CLAMP 12153# endif2154# endif2155#endif21562157namespace toml2158{2159inline namespace TOML11_INLINE_VERSION_NAMESPACE2160{2161namespace cxx2162{2163#if defined(TOML11_HAS_STD_CLAMP)21642165using std::clamp;21662167#else21682169template<typename T>2170T clamp(const T& x, const T& low, const T& high) noexcept2171{2172assert(low <= high);2173return (std::min)((std::max)(x, low), high);2174}21752176#endif // TOML11_HAS_STD_CLAMP21772178} // cxx2179} // TOML11_INLINE_VERSION_NAMESPACE2180} // toml21812182// ---------------------------------------------------------------------------21832184#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE2185# if defined(__cpp_lib_bit_cast)2186# if __cpp_lib_bit_cast >= 201806L2187# define TOML11_HAS_STD_BIT_CAST 12188# endif2189# endif2190#endif21912192namespace toml2193{2194inline namespace TOML11_INLINE_VERSION_NAMESPACE2195{2196namespace cxx2197{2198#if defined(TOML11_HAS_STD_BIT_CAST)21992200using std::bit_cast;22012202#else22032204template<typename U, typename T>2205U bit_cast(const T& x) noexcept2206{2207static_assert(sizeof(T) == sizeof(U), "");2208static_assert(std::is_default_constructible<T>::value, "");22092210U z;2211std::memcpy(reinterpret_cast<char*>(std::addressof(z)),2212reinterpret_cast<const char*>(std::addressof(x)),2213sizeof(T));22142215return z;2216}22172218#endif // TOML11_HAS_STD_BIT_CAST22192220} // cxx2221} // TOML11_INLINE_VERSION_NAMESPACE2222} // toml22232224// ---------------------------------------------------------------------------2225// C++20 remove_cvref_t22262227#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE2228# if defined(__cpp_lib_remove_cvref)2229# if __cpp_lib_remove_cvref >= 201711L2230# define TOML11_HAS_STD_REMOVE_CVREF 12231# endif2232# endif2233#endif22342235namespace toml2236{2237inline namespace TOML11_INLINE_VERSION_NAMESPACE2238{2239namespace cxx2240{2241#if defined(TOML11_HAS_STD_REMOVE_CVREF)22422243using std::remove_cvref;2244using std::remove_cvref_t;22452246#else22472248template<typename T>2249struct remove_cvref2250{2251using type = typename std::remove_cv<2252typename std::remove_reference<T>::type>::type;2253};22542255template<typename T>2256using remove_cvref_t = typename remove_cvref<T>::type;22572258#endif // TOML11_HAS_STD_REMOVE_CVREF22592260} // cxx2261} // TOML11_INLINE_VERSION_NAMESPACE2262} // toml22632264// ---------------------------------------------------------------------------2265// C++17 and/or/not22662267#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE2268# if defined(__cpp_lib_logical_traits)2269# if __cpp_lib_logical_traits >= 201510L2270# define TOML11_HAS_STD_CONJUNCTION 12271# endif2272# endif2273#endif22742275namespace toml2276{2277inline namespace TOML11_INLINE_VERSION_NAMESPACE2278{2279namespace cxx2280{2281#if defined(TOML11_HAS_STD_CONJUNCTION)22822283using std::conjunction;2284using std::disjunction;2285using std::negation;22862287#else22882289template<typename ...> struct conjunction : std::true_type{};2290template<typename T> struct conjunction<T> : T{};2291template<typename T, typename ... Ts>2292struct conjunction<T, Ts...> :2293std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type2294{};22952296template<typename ...> struct disjunction : std::false_type{};2297template<typename T> struct disjunction<T> : T {};2298template<typename T, typename ... Ts>2299struct disjunction<T, Ts...> :2300std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type2301{};23022303template<typename T>2304struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};23052306#endif // TOML11_HAS_STD_CONJUNCTION23072308} // cxx2309} // TOML11_INLINE_VERSION_NAMESPACE2310} // toml23112312// ---------------------------------------------------------------------------2313// C++14 index_sequence23142315#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2316# if defined(__cpp_lib_integer_sequence)2317# if __cpp_lib_integer_sequence >= 201304L2318# define TOML11_HAS_STD_INTEGER_SEQUENCE 12319# endif2320# endif2321#endif23222323namespace toml2324{2325inline namespace TOML11_INLINE_VERSION_NAMESPACE2326{2327namespace cxx2328{2329#if defined(TOML11_HAS_STD_INTEGER_SEQUENCE)23302331using std::index_sequence;2332using std::make_index_sequence;23332334#else23352336template<std::size_t ... Ns> struct index_sequence{};23372338template<bool B, std::size_t N, typename T>2339struct double_index_sequence;23402341template<std::size_t N, std::size_t ... Is>2342struct double_index_sequence<true, N, index_sequence<Is...>>2343{2344using type = index_sequence<Is..., (Is+N)..., N*2>;2345};2346template<std::size_t N, std::size_t ... Is>2347struct double_index_sequence<false, N, index_sequence<Is...>>2348{2349using type = index_sequence<Is..., (Is+N)...>;2350};23512352template<std::size_t N>2353struct index_sequence_maker2354{2355using type = typename double_index_sequence<2356N % 2 == 1, N/2, typename index_sequence_maker<N/2>::type2357>::type;2358};2359template<>2360struct index_sequence_maker<0>2361{2362using type = index_sequence<>;2363};23642365template<std::size_t N>2366using make_index_sequence = typename index_sequence_maker<N>::type;23672368#endif // TOML11_HAS_STD_INTEGER_SEQUENCE23692370} // cxx2371} // TOML11_INLINE_VERSION_NAMESPACE2372} // toml23732374// ---------------------------------------------------------------------------2375// C++14 enable_if_t23762377#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2378# if defined(__cpp_lib_transformation_trait_aliases)2379# if __cpp_lib_transformation_trait_aliases >= 201304L2380# define TOML11_HAS_STD_ENABLE_IF_T 12381# endif2382# endif2383#endif23842385namespace toml2386{2387inline namespace TOML11_INLINE_VERSION_NAMESPACE2388{2389namespace cxx2390{2391#if defined(TOML11_HAS_STD_ENABLE_IF_T)23922393using std::enable_if_t;23942395#else23962397template<bool B, typename T>2398using enable_if_t = typename std::enable_if<B, T>::type;23992400#endif // TOML11_HAS_STD_ENABLE_IF_T24012402} // cxx2403} // TOML11_INLINE_VERSION_NAMESPACE2404} // toml24052406// ---------------------------------------------------------------------------2407// return_type_of_t24082409#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE2410# if defined(__cpp_lib_is_invocable)2411# if __cpp_lib_is_invocable >= 2017032412# define TOML11_HAS_STD_INVOKE_RESULT 12413# endif2414# endif2415#endif24162417namespace toml2418{2419inline namespace TOML11_INLINE_VERSION_NAMESPACE2420{2421namespace cxx2422{2423#if defined(TOML11_HAS_STD_INVOKE_RESULT)24242425template<typename F, typename ... Args>2426using return_type_of_t = std::invoke_result_t<F, Args...>;24272428#else24292430// result_of is deprecated after C++172431template<typename F, typename ... Args>2432using return_type_of_t = typename std::result_of<F(Args...)>::type;24332434#endif // TOML11_HAS_STD_INVOKE_RESULT24352436} // cxx2437} // TOML11_INLINE_VERSION_NAMESPACE2438} // toml24392440// ---------------------------------------------------------------------------2441// C++17 void_t24422443#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE2444# if defined(__cpp_lib_void_t)2445# if __cpp_lib_void_t >= 201411L2446# define TOML11_HAS_STD_VOID_T 12447# endif2448# endif2449#endif24502451namespace toml2452{2453inline namespace TOML11_INLINE_VERSION_NAMESPACE2454{2455namespace cxx2456{2457#if defined(TOML11_HAS_STD_VOID_T)24582459using std::void_t;24602461#else24622463template<typename ...>2464using void_t = void;24652466#endif // TOML11_HAS_STD_VOID_T24672468} // cxx2469} // TOML11_INLINE_VERSION_NAMESPACE2470} // toml24712472// ----------------------------------------------------------------------------2473// (subset of) source_location24742475#if ! defined(TOML11_DISABLE_SOURCE_LOCATION) && TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L2476# if __has_include(<source_location>)2477# define TOML11_HAS_STD_SOURCE_LOCATION2478# endif // has_include2479#endif // c++2024802481#if ! defined(TOML11_DISABLE_SOURCE_LOCATION) && ! defined(TOML11_HAS_STD_SOURCE_LOCATION)2482# if defined(__GNUC__) && ! defined(__clang__)2483# if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE2484# if __has_include(<experimental/source_location>)2485# define TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION2486# endif2487# endif2488# endif // GNU g++2489#endif // not TOML11_HAS_STD_SOURCE_LOCATION24902491#if ! defined(TOML11_DISABLE_SOURCE_LOCATION) && ! defined(TOML11_HAS_STD_SOURCE_LOCATION) && ! defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION)2492# if defined(__GNUC__) && ! defined(__clang__)2493# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))2494# define TOML11_HAS_BUILTIN_FILE_LINE 12495# define TOML11_BUILTIN_LINE_TYPE int2496# endif2497# elif defined(__clang__) // clang 9.0.0 implements builtin_FILE/LINE2498# if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE)2499# define TOML11_HAS_BUILTIN_FILE_LINE 12500# define TOML11_BUILTIN_LINE_TYPE unsigned int2501# endif2502# elif defined(_MSVC_LANG) && defined(_MSC_VER)2503# if _MSC_VER > 19262504# define TOML11_HAS_BUILTIN_FILE_LINE 12505# define TOML11_BUILTIN_LINE_TYPE int2506# endif2507# endif2508#endif25092510#if defined(TOML11_HAS_STD_SOURCE_LOCATION)2511#include <source_location>2512namespace toml2513{2514inline namespace TOML11_INLINE_VERSION_NAMESPACE2515{2516namespace cxx2517{2518using source_location = std::source_location;25192520inline std::string to_string(const source_location& loc)2521{2522const char* fname = loc.file_name();2523if(fname)2524{2525return std::string(" at line ") + std::to_string(loc.line()) +2526std::string(" in file ") + std::string(fname);2527}2528else2529{2530return std::string(" at line ") + std::to_string(loc.line()) +2531std::string(" in unknown file");2532}2533}25342535} // cxx2536} // TOML11_INLINE_VERSION_NAMESPACE2537} // toml2538#elif defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION)2539#include <experimental/source_location>2540namespace toml2541{2542inline namespace TOML11_INLINE_VERSION_NAMESPACE2543{2544namespace cxx2545{2546using source_location = std::experimental::source_location;25472548inline std::string to_string(const source_location& loc)2549{2550const char* fname = loc.file_name();2551if(fname)2552{2553return std::string(" at line ") + std::to_string(loc.line()) +2554std::string(" in file ") + std::string(fname);2555}2556else2557{2558return std::string(" at line ") + std::to_string(loc.line()) +2559std::string(" in unknown file");2560}2561}25622563} // cxx2564} // TOML11_INLINE_VERSION_NAMESPACE2565} // toml2566#elif defined(TOML11_HAS_BUILTIN_FILE_LINE)2567namespace toml2568{2569inline namespace TOML11_INLINE_VERSION_NAMESPACE2570{2571namespace cxx2572{2573struct source_location2574{2575using line_type = TOML11_BUILTIN_LINE_TYPE;2576static source_location current(const line_type line = __builtin_LINE(),2577const char* file = __builtin_FILE())2578{2579return source_location(line, file);2580}25812582source_location(const line_type line, const char* file)2583: line_(line), file_name_(file)2584{}25852586line_type line() const noexcept {return line_;}2587const char* file_name() const noexcept {return file_name_;}25882589private:25902591line_type line_;2592const char* file_name_;2593};25942595inline std::string to_string(const source_location& loc)2596{2597const char* fname = loc.file_name();2598if(fname)2599{2600return std::string(" at line ") + std::to_string(loc.line()) +2601std::string(" in file ") + std::string(fname);2602}2603else2604{2605return std::string(" at line ") + std::to_string(loc.line()) +2606std::string(" in unknown file");2607}2608}26092610} // cxx2611} // TOML11_INLINE_VERSION_NAMESPACE2612} // toml2613#else // no builtin2614namespace toml2615{2616inline namespace TOML11_INLINE_VERSION_NAMESPACE2617{2618namespace cxx2619{2620struct source_location2621{2622static source_location current() { return source_location{}; }2623};26242625inline std::string to_string(const source_location&)2626{2627return std::string("");2628}2629} // cxx2630} // TOML11_INLINE_VERSION_NAMESPACE2631} // toml2632#endif // TOML11_HAS_STD_SOURCE_LOCATION26332634// ----------------------------------------------------------------------------2635// (subset of) optional26362637#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE2638# if __has_include(<optional>)2639# include <optional>2640# endif // has_include(optional)2641#endif // C++1726422643#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE2644# if defined(__cpp_lib_optional)2645# if __cpp_lib_optional >= 201606L2646# define TOML11_HAS_STD_OPTIONAL 12647# endif2648# endif2649#endif26502651#if defined(TOML11_HAS_STD_OPTIONAL)26522653namespace toml2654{2655inline namespace TOML11_INLINE_VERSION_NAMESPACE2656{2657namespace cxx2658{2659using std::optional;26602661inline std::nullopt_t make_nullopt() {return std::nullopt;}26622663template<typename charT, typename traitsT>2664std::basic_ostream<charT, traitsT>&2665operator<<(std::basic_ostream<charT, traitsT>& os, const std::nullopt_t&)2666{2667os << "nullopt";2668return os;2669}26702671} // cxx2672} // TOML11_INLINE_VERSION_NAMESPACE2673} // toml26742675#else // TOML11_HAS_STD_OPTIONAL26762677namespace toml2678{2679inline namespace TOML11_INLINE_VERSION_NAMESPACE2680{2681namespace cxx2682{26832684struct nullopt_t{};2685inline nullopt_t make_nullopt() {return nullopt_t{};}26862687inline bool operator==(const nullopt_t&, const nullopt_t&) noexcept {return true;}2688inline bool operator!=(const nullopt_t&, const nullopt_t&) noexcept {return false;}2689inline bool operator< (const nullopt_t&, const nullopt_t&) noexcept {return false;}2690inline bool operator<=(const nullopt_t&, const nullopt_t&) noexcept {return true;}2691inline bool operator> (const nullopt_t&, const nullopt_t&) noexcept {return false;}2692inline bool operator>=(const nullopt_t&, const nullopt_t&) noexcept {return true;}26932694template<typename charT, typename traitsT>2695std::basic_ostream<charT, traitsT>&2696operator<<(std::basic_ostream<charT, traitsT>& os, const nullopt_t&)2697{2698os << "nullopt";2699return os;2700}27012702template<typename T>2703class optional2704{2705public:27062707using value_type = T;27082709public:27102711optional() noexcept : has_value_(false), null_('\0') {}2712optional(nullopt_t) noexcept : has_value_(false), null_('\0') {}27132714optional(const T& x): has_value_(true), value_(x) {}2715optional(T&& x): has_value_(true), value_(std::move(x)) {}27162717template<typename U, enable_if_t<std::is_constructible<T, U>::value, std::nullptr_t> = nullptr>2718explicit optional(U&& x): has_value_(true), value_(std::forward<U>(x)) {}27192720optional(const optional& rhs): has_value_(rhs.has_value_)2721{2722if(rhs.has_value_)2723{2724this->assigner(rhs.value_);2725}2726}2727optional(optional&& rhs): has_value_(rhs.has_value_)2728{2729if(this->has_value_)2730{2731this->assigner(std::move(rhs.value_));2732}2733}27342735optional& operator=(const optional& rhs)2736{2737if(this == std::addressof(rhs)) {return *this;}27382739this->cleanup();2740this->has_value_ = rhs.has_value_;2741if(this->has_value_)2742{2743this->assigner(rhs.value_);2744}2745return *this;2746}2747optional& operator=(optional&& rhs)2748{2749if(this == std::addressof(rhs)) {return *this;}27502751this->cleanup();2752this->has_value_ = rhs.has_value_;2753if(this->has_value_)2754{2755this->assigner(std::move(rhs.value_));2756}2757return *this;2758}27592760template<typename U, enable_if_t<conjunction<2761negation<std::is_same<T, U>>, std::is_constructible<T, U>2762>::value, std::nullptr_t> = nullptr>2763explicit optional(const optional<U>& rhs): has_value_(rhs.has_value_), null_('\0')2764{2765if(rhs.has_value_)2766{2767this->assigner(rhs.value_);2768}2769}2770template<typename U, enable_if_t<conjunction<2771negation<std::is_same<T, U>>, std::is_constructible<T, U>2772>::value, std::nullptr_t> = nullptr>2773explicit optional(optional<U>&& rhs): has_value_(rhs.has_value_), null_('\0')2774{2775if(this->has_value_)2776{2777this->assigner(std::move(rhs.value_));2778}2779}27802781template<typename U, enable_if_t<conjunction<2782negation<std::is_same<T, U>>, std::is_constructible<T, U>2783>::value, std::nullptr_t> = nullptr>2784optional& operator=(const optional<U>& rhs)2785{2786if(this == std::addressof(rhs)) {return *this;}27872788this->cleanup();2789this->has_value_ = rhs.has_value_;2790if(this->has_value_)2791{2792this->assigner(rhs.value_);2793}2794return *this;2795}27962797template<typename U, enable_if_t<conjunction<2798negation<std::is_same<T, U>>, std::is_constructible<T, U>2799>::value, std::nullptr_t> = nullptr>2800optional& operator=(optional<U>&& rhs)2801{2802if(this == std::addressof(rhs)) {return *this;}28032804this->cleanup();2805this->has_value_ = rhs.has_value_;2806if(this->has_value_)2807{2808this->assigner(std::move(rhs.value_));2809}2810return *this;2811}2812~optional() noexcept2813{2814this->cleanup();2815}28162817explicit operator bool() const noexcept2818{2819return has_value_;2820}28212822bool has_value() const noexcept {return has_value_;}28232824value_type const& value(source_location loc = source_location::current()) const2825{2826if( ! this->has_value_)2827{2828throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc));2829}2830return this->value_;2831}2832value_type& value(source_location loc = source_location::current())2833{2834if( ! this->has_value_)2835{2836throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc));2837}2838return this->value_;2839}28402841value_type const& value_or(const value_type& opt) const2842{2843if(this->has_value_) {return this->value_;} else {return opt;}2844}2845value_type& value_or(value_type& opt)2846{2847if(this->has_value_) {return this->value_;} else {return opt;}2848}28492850private:28512852void cleanup() noexcept2853{2854if(this->has_value_)2855{2856value_.~T();2857}2858}28592860template<typename U>2861void assigner(U&& x)2862{2863const auto tmp = ::new(std::addressof(this->value_)) value_type(std::forward<U>(x));2864assert(tmp == std::addressof(this->value_));2865(void)tmp;2866}28672868private:28692870bool has_value_;2871union2872{2873char null_;2874T value_;2875};2876};2877} // cxx2878} // TOML11_INLINE_VERSION_NAMESPACE2879} // toml2880#endif // TOML11_HAS_STD_OPTIONAL28812882#endif // TOML11_COMPAT_HPP2883#ifndef TOML11_VALUE_T_HPP2884#define TOML11_VALUE_T_HPP28852886#ifndef TOML11_VALUE_T_FWD_HPP2887#define TOML11_VALUE_T_FWD_HPP288828892890#include <iosfwd>2891#include <string>2892#include <type_traits>28932894#include <cstdint>28952896namespace toml2897{2898inline namespace TOML11_INLINE_VERSION_NAMESPACE2899{29002901// forward decl2902template<typename TypeConfig>2903class basic_value;29042905// ----------------------------------------------------------------------------2906// enum representing toml types29072908enum class value_t : std::uint8_t2909{2910empty = 0,2911boolean = 1,2912integer = 2,2913floating = 3,2914string = 4,2915offset_datetime = 5,2916local_datetime = 6,2917local_date = 7,2918local_time = 8,2919array = 9,2920table = 102921};29222923std::ostream& operator<<(std::ostream& os, value_t t);2924std::string to_string(value_t t);292529262927// ----------------------------------------------------------------------------2928// meta functions for internal use29292930namespace detail2931{29322933template<value_t V>2934using value_t_constant = std::integral_constant<value_t, V>;29352936template<typename T, typename Value>2937struct type_to_enum : value_t_constant<value_t::empty> {};29382939template<typename V> struct type_to_enum<typename V::boolean_type , V> : value_t_constant<value_t::boolean > {};2940template<typename V> struct type_to_enum<typename V::integer_type , V> : value_t_constant<value_t::integer > {};2941template<typename V> struct type_to_enum<typename V::floating_type , V> : value_t_constant<value_t::floating > {};2942template<typename V> struct type_to_enum<typename V::string_type , V> : value_t_constant<value_t::string > {};2943template<typename V> struct type_to_enum<typename V::offset_datetime_type, V> : value_t_constant<value_t::offset_datetime> {};2944template<typename V> struct type_to_enum<typename V::local_datetime_type , V> : value_t_constant<value_t::local_datetime > {};2945template<typename V> struct type_to_enum<typename V::local_date_type , V> : value_t_constant<value_t::local_date > {};2946template<typename V> struct type_to_enum<typename V::local_time_type , V> : value_t_constant<value_t::local_time > {};2947template<typename V> struct type_to_enum<typename V::array_type , V> : value_t_constant<value_t::array > {};2948template<typename V> struct type_to_enum<typename V::table_type , V> : value_t_constant<value_t::table > {};29492950template<value_t V, typename Value>2951struct enum_to_type { using type = void; };29522953template<typename V> struct enum_to_type<value_t::boolean , V> { using type = typename V::boolean_type ; };2954template<typename V> struct enum_to_type<value_t::integer , V> { using type = typename V::integer_type ; };2955template<typename V> struct enum_to_type<value_t::floating , V> { using type = typename V::floating_type ; };2956template<typename V> struct enum_to_type<value_t::string , V> { using type = typename V::string_type ; };2957template<typename V> struct enum_to_type<value_t::offset_datetime, V> { using type = typename V::offset_datetime_type; };2958template<typename V> struct enum_to_type<value_t::local_datetime , V> { using type = typename V::local_datetime_type ; };2959template<typename V> struct enum_to_type<value_t::local_date , V> { using type = typename V::local_date_type ; };2960template<typename V> struct enum_to_type<value_t::local_time , V> { using type = typename V::local_time_type ; };2961template<typename V> struct enum_to_type<value_t::array , V> { using type = typename V::array_type ; };2962template<typename V> struct enum_to_type<value_t::table , V> { using type = typename V::table_type ; };29632964template<value_t V, typename Value>2965using enum_to_type_t = typename enum_to_type<V, Value>::type;29662967template<value_t V>2968struct enum_to_fmt_type { using type = void; };29692970template<> struct enum_to_fmt_type<value_t::boolean > { using type = boolean_format_info ; };2971template<> struct enum_to_fmt_type<value_t::integer > { using type = integer_format_info ; };2972template<> struct enum_to_fmt_type<value_t::floating > { using type = floating_format_info ; };2973template<> struct enum_to_fmt_type<value_t::string > { using type = string_format_info ; };2974template<> struct enum_to_fmt_type<value_t::offset_datetime> { using type = offset_datetime_format_info; };2975template<> struct enum_to_fmt_type<value_t::local_datetime > { using type = local_datetime_format_info ; };2976template<> struct enum_to_fmt_type<value_t::local_date > { using type = local_date_format_info ; };2977template<> struct enum_to_fmt_type<value_t::local_time > { using type = local_time_format_info ; };2978template<> struct enum_to_fmt_type<value_t::array > { using type = array_format_info ; };2979template<> struct enum_to_fmt_type<value_t::table > { using type = table_format_info ; };29802981template<value_t V>2982using enum_to_fmt_type_t = typename enum_to_fmt_type<V>::type;29832984template<typename T, typename Value>2985struct is_exact_toml_type0 : cxx::disjunction<2986std::is_same<T, typename Value::boolean_type >,2987std::is_same<T, typename Value::integer_type >,2988std::is_same<T, typename Value::floating_type >,2989std::is_same<T, typename Value::string_type >,2990std::is_same<T, typename Value::offset_datetime_type>,2991std::is_same<T, typename Value::local_datetime_type >,2992std::is_same<T, typename Value::local_date_type >,2993std::is_same<T, typename Value::local_time_type >,2994std::is_same<T, typename Value::array_type >,2995std::is_same<T, typename Value::table_type >2996>{};2997template<typename T, typename V> struct is_exact_toml_type: is_exact_toml_type0<cxx::remove_cvref_t<T>, V> {};2998template<typename T, typename V> struct is_not_toml_type : cxx::negation<is_exact_toml_type<T, V>> {};29993000} // namespace detail3001} // TOML11_INLINE_VERSION_NAMESPACE3002} // namespace toml3003#endif // TOML11_VALUE_T_FWD_HPP30043005#if ! defined(TOML11_COMPILE_SOURCES)3006#ifndef TOML11_VALUE_T_IMPL_HPP3007#define TOML11_VALUE_T_IMPL_HPP300830093010#include <ostream>3011#include <sstream>3012#include <string>30133014namespace toml3015{3016inline namespace TOML11_INLINE_VERSION_NAMESPACE3017{30183019TOML11_INLINE std::ostream& operator<<(std::ostream& os, value_t t)3020{3021switch(t)3022{3023case value_t::boolean : os << "boolean"; return os;3024case value_t::integer : os << "integer"; return os;3025case value_t::floating : os << "floating"; return os;3026case value_t::string : os << "string"; return os;3027case value_t::offset_datetime : os << "offset_datetime"; return os;3028case value_t::local_datetime : os << "local_datetime"; return os;3029case value_t::local_date : os << "local_date"; return os;3030case value_t::local_time : os << "local_time"; return os;3031case value_t::array : os << "array"; return os;3032case value_t::table : os << "table"; return os;3033case value_t::empty : os << "empty"; return os;3034default : os << "unknown"; return os;3035}3036}30373038TOML11_INLINE std::string to_string(value_t t)3039{3040std::ostringstream oss;3041oss << t;3042return oss.str();3043}30443045} //TOML11_INLINE_VERSION_NAMESPACE3046} // namespace toml3047#endif // TOML11_VALUE_T_IMPL_HPP3048#endif30493050#endif // TOML11_VALUE_T_HPP3051#ifndef TOML11_TRAITS_HPP3052#define TOML11_TRAITS_HPP305330543055#include <array>3056#include <chrono>3057#include <forward_list>3058#include <string>3059#include <tuple>3060#include <type_traits>3061#include <unordered_set>3062#include <utility>30633064#if defined(TOML11_HAS_STRING_VIEW)3065#include <string_view>3066#endif30673068#if defined(TOML11_HAS_OPTIONAL)3069#include <optional>3070#endif30713072namespace toml3073{3074inline namespace TOML11_INLINE_VERSION_NAMESPACE3075{3076template<typename TypeConcig>3077class basic_value;30783079namespace detail3080{3081// ---------------------------------------------------------------------------3082// check whether type T is a kind of container/map class30833084struct has_iterator_impl3085{3086template<typename T> static std::true_type check(typename T::iterator*);3087template<typename T> static std::false_type check(...);3088};3089struct has_value_type_impl3090{3091template<typename T> static std::true_type check(typename T::value_type*);3092template<typename T> static std::false_type check(...);3093};3094struct has_key_type_impl3095{3096template<typename T> static std::true_type check(typename T::key_type*);3097template<typename T> static std::false_type check(...);3098};3099struct has_mapped_type_impl3100{3101template<typename T> static std::true_type check(typename T::mapped_type*);3102template<typename T> static std::false_type check(...);3103};3104struct has_reserve_method_impl3105{3106template<typename T> static std::false_type check(...);3107template<typename T> static std::true_type check(3108decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);3109};3110struct has_push_back_method_impl3111{3112template<typename T> static std::false_type check(...);3113template<typename T> static std::true_type check(3114decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);3115};3116struct is_comparable_impl3117{3118template<typename T> static std::false_type check(...);3119template<typename T> static std::true_type check(3120decltype(std::declval<T>() < std::declval<T>())*);3121};31223123struct has_from_toml_method_impl3124{3125template<typename T, typename TC>3126static std::true_type check(3127decltype(std::declval<T>().from_toml(std::declval<::toml::basic_value<TC>>()))*);31283129template<typename T, typename TC>3130static std::false_type check(...);3131};3132struct has_into_toml_method_impl3133{3134template<typename T>3135static std::true_type check(decltype(std::declval<T>().into_toml())*);3136template<typename T>3137static std::false_type check(...);3138};31393140struct has_template_into_toml_method_impl3141{3142template<typename T, typename TypeConfig>3143static std::true_type check(decltype(std::declval<T>().template into_toml<TypeConfig>())*);3144template<typename T, typename TypeConfig>3145static std::false_type check(...);3146};31473148struct has_specialized_from_impl3149{3150template<typename T>3151static std::false_type check(...);3152template<typename T, std::size_t S = sizeof(::toml::from<T>)>3153static std::true_type check(::toml::from<T>*);3154};3155struct has_specialized_into_impl3156{3157template<typename T>3158static std::false_type check(...);3159template<typename T, std::size_t S = sizeof(::toml::into<T>)>3160static std::true_type check(::toml::into<T>*);3161};316231633164/// Intel C++ compiler can not use decltype in parent class declaration, here3165/// is a hack to work around it. https://stackoverflow.com/a/23953090/46920763166#ifdef __INTEL_COMPILER3167#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type3168#endif31693170template<typename T>3171struct has_iterator: decltype(has_iterator_impl::check<T>(nullptr)){};3172template<typename T>3173struct has_value_type: decltype(has_value_type_impl::check<T>(nullptr)){};3174template<typename T>3175struct has_key_type: decltype(has_key_type_impl::check<T>(nullptr)){};3176template<typename T>3177struct has_mapped_type: decltype(has_mapped_type_impl::check<T>(nullptr)){};3178template<typename T>3179struct has_reserve_method: decltype(has_reserve_method_impl::check<T>(nullptr)){};3180template<typename T>3181struct has_push_back_method: decltype(has_push_back_method_impl::check<T>(nullptr)){};3182template<typename T>3183struct is_comparable: decltype(is_comparable_impl::check<T>(nullptr)){};31843185template<typename T, typename TC>3186struct has_from_toml_method: decltype(has_from_toml_method_impl::check<T, TC>(nullptr)){};31873188template<typename T>3189struct has_into_toml_method: decltype(has_into_toml_method_impl::check<T>(nullptr)){};31903191template<typename T, typename TypeConfig>3192struct has_template_into_toml_method: decltype(has_template_into_toml_method_impl::check<T, TypeConfig>(nullptr)){};31933194template<typename T>3195struct has_specialized_from: decltype(has_specialized_from_impl::check<T>(nullptr)){};3196template<typename T>3197struct has_specialized_into: decltype(has_specialized_into_impl::check<T>(nullptr)){};31983199#ifdef __INTEL_COMPILER3200#undef decltype3201#endif32023203// ---------------------------------------------------------------------------3204// type checkers32053206template<typename T> struct is_std_pair_impl : std::false_type{};3207template<typename T1, typename T2>3208struct is_std_pair_impl<std::pair<T1, T2>> : std::true_type{};3209template<typename T>3210using is_std_pair = is_std_pair_impl<cxx::remove_cvref_t<T>>;32113212template<typename T> struct is_std_tuple_impl : std::false_type{};3213template<typename ... Ts>3214struct is_std_tuple_impl<std::tuple<Ts...>> : std::true_type{};3215template<typename T>3216using is_std_tuple = is_std_tuple_impl<cxx::remove_cvref_t<T>>;32173218template<typename T> struct is_unordered_set_impl : std::false_type {};3219template<typename T>3220struct is_unordered_set_impl<std::unordered_set<T>> : std::true_type {};3221template<typename T>3222using is_unordered_set = is_unordered_set_impl<cxx::remove_cvref_t<T>>;32233224#if defined(TOML11_HAS_OPTIONAL)3225template<typename T> struct is_std_optional_impl : std::false_type{};3226template<typename T>3227struct is_std_optional_impl<std::optional<T>> : std::true_type{};3228template<typename T>3229using is_std_optional = is_std_optional_impl<cxx::remove_cvref_t<T>>;3230#else3231template<typename T> struct is_std_optional : std::false_type{};3232#endif // > C++1732333234template<typename T> struct is_std_array_impl : std::false_type{};3235template<typename T, std::size_t N>3236struct is_std_array_impl<std::array<T, N>> : std::true_type{};3237template<typename T>3238using is_std_array = is_std_array_impl<cxx::remove_cvref_t<T>>;32393240template<typename T> struct is_std_forward_list_impl : std::false_type{};3241template<typename T>3242struct is_std_forward_list_impl<std::forward_list<T>> : std::true_type{};3243template<typename T>3244using is_std_forward_list = is_std_forward_list_impl<cxx::remove_cvref_t<T>>;32453246template<typename T> struct is_std_basic_string_impl : std::false_type{};3247template<typename C, typename T, typename A>3248struct is_std_basic_string_impl<std::basic_string<C, T, A>> : std::true_type{};3249template<typename T>3250using is_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;32513252template<typename T> struct is_1byte_std_basic_string_impl : std::false_type{};3253template<typename C, typename T, typename A>3254struct is_1byte_std_basic_string_impl<std::basic_string<C, T, A>>3255: std::integral_constant<bool, sizeof(C) == sizeof(char)> {};3256template<typename T>3257using is_1byte_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;32583259#if defined(TOML11_HAS_STRING_VIEW)3260template<typename T> struct is_std_basic_string_view_impl : std::false_type{};3261template<typename C, typename T>3262struct is_std_basic_string_view_impl<std::basic_string_view<C, T>> : std::true_type{};3263template<typename T>3264using is_std_basic_string_view = is_std_basic_string_view_impl<cxx::remove_cvref_t<T>>;32653266template<typename V, typename S>3267struct is_string_view_of : std::false_type {};3268template<typename C, typename T>3269struct is_string_view_of<std::basic_string_view<C, T>, std::basic_string<C, T>> : std::true_type {};3270#else3271template<typename T>3272struct is_std_basic_string_view : std::false_type {};3273template<typename V, typename S>3274struct is_string_view_of : std::false_type {};3275#endif32763277template<typename T> struct is_chrono_duration_impl: std::false_type{};3278template<typename Rep, typename Period>3279struct is_chrono_duration_impl<std::chrono::duration<Rep, Period>>: std::true_type{};3280template<typename T>3281using is_chrono_duration = is_chrono_duration_impl<cxx::remove_cvref_t<T>>;32823283template<typename T>3284struct is_map_impl : cxx::conjunction< // map satisfies all the following conditions3285has_iterator<T>, // has T::iterator3286has_value_type<T>, // has T::value_type3287has_key_type<T>, // has T::key_type3288has_mapped_type<T> // has T::mapped_type3289>{};3290template<typename T>3291using is_map = is_map_impl<cxx::remove_cvref_t<T>>;32923293template<typename T>3294struct is_container_impl : cxx::conjunction<3295cxx::negation<is_map<T>>, // not a map3296cxx::negation<std::is_same<T, std::string>>, // not a std::string3297#ifdef TOML11_HAS_STRING_VIEW3298cxx::negation<std::is_same<T, std::string_view>>, // not a std::string_view3299#endif3300has_iterator<T>, // has T::iterator3301has_value_type<T> // has T::value_type3302>{};3303template<typename T>3304using is_container = is_container_impl<cxx::remove_cvref_t<T>>;33053306template<typename T>3307struct is_basic_value_impl: std::false_type{};3308template<typename TC>3309struct is_basic_value_impl<::toml::basic_value<TC>>: std::true_type{};3310template<typename T>3311using is_basic_value = is_basic_value_impl<cxx::remove_cvref_t<T>>;33123313}// detail3314} // TOML11_INLINE_VERSION_NAMESPACE3315} // toml3316#endif // TOML11_TRAITS_HPP3317#ifndef TOML11_STORAGE_HPP3318#define TOML11_STORAGE_HPP331933203321namespace toml3322{3323inline namespace TOML11_INLINE_VERSION_NAMESPACE3324{3325namespace detail3326{33273328// It owns a pointer to T. It does deep-copy when copied.3329// This struct is introduced to implement a recursive type.3330//3331// `toml::value` contains `std::vector<toml::value>` to represent a toml array.3332// But, in the definition of `toml::value`, `toml::value` is still incomplete.3333// `std::vector` of an incomplete type is not allowed in C++11 (it is allowed3334// after C++17). To avoid this, we need to use a pointer to `toml::value`, like3335// `std::vector<std::unique_ptr<toml::value>>`. Although `std::unique_ptr` is3336// noncopyable, we want to make `toml::value` copyable. `storage` is introduced3337// to resolve those problems.3338template<typename T>3339struct storage3340{3341using value_type = T;33423343explicit storage(value_type v): ptr_(cxx::make_unique<T>(std::move(v))) {}3344~storage() = default;33453346storage(const storage& rhs): ptr_(cxx::make_unique<T>(*rhs.ptr_)) {}3347storage& operator=(const storage& rhs)3348{3349this->ptr_ = cxx::make_unique<T>(*rhs.ptr_);3350return *this;3351}33523353storage(storage&&) = default;3354storage& operator=(storage&&) = default;33553356bool is_ok() const noexcept {return static_cast<bool>(ptr_);}33573358value_type& get() const noexcept {return *ptr_;}33593360private:3361std::unique_ptr<value_type> ptr_;3362};33633364} // detail3365} // TOML11_INLINE_VERSION_NAMESPACE3366} // toml3367#endif // TOML11_STORAGE_HPP3368#ifndef TOML11_RESULT_HPP3369#define TOML11_RESULT_HPP337033713372#include <ostream>3373#include <string>3374#include <type_traits>3375#include <utility>33763377#include <cassert>33783379namespace toml3380{3381inline namespace TOML11_INLINE_VERSION_NAMESPACE3382{33833384struct bad_result_access final : public ::toml::exception3385{3386public:3387explicit bad_result_access(std::string what_arg)3388: what_(std::move(what_arg))3389{}3390~bad_result_access() noexcept override = default;3391const char* what() const noexcept override {return what_.c_str();}33923393private:3394std::string what_;3395};33963397// -----------------------------------------------------------------------------33983399template<typename T>3400struct success3401{3402static_assert( ! std::is_void<T>::value, "");34033404using value_type = T;34053406explicit success(value_type v)3407noexcept(std::is_nothrow_move_constructible<value_type>::value)3408: value(std::move(v))3409{}34103411template<typename U, cxx::enable_if_t<3412std::is_convertible<cxx::remove_cvref_t<U>, T>::value,3413std::nullptr_t> = nullptr>3414explicit success(U&& v): value(std::forward<U>(v)) {}34153416template<typename U>3417explicit success(success<U> v): value(std::move(v.value)) {}34183419~success() = default;3420success(const success&) = default;3421success(success&&) = default;3422success& operator=(const success&) = default;3423success& operator=(success&&) = default;34243425value_type& get() noexcept {return value;}3426value_type const& get() const noexcept {return value;}34273428private:34293430value_type value;3431};34323433template<typename T>3434struct success<std::reference_wrapper<T>>3435{3436static_assert( ! std::is_void<T>::value, "");34373438using value_type = T;34393440explicit success(std::reference_wrapper<value_type> v) noexcept3441: value(std::move(v))3442{}34433444~success() = default;3445success(const success&) = default;3446success(success&&) = default;3447success& operator=(const success&) = default;3448success& operator=(success&&) = default;34493450value_type& get() noexcept {return value.get();}3451value_type const& get() const noexcept {return value.get();}34523453private:34543455std::reference_wrapper<value_type> value;3456};34573458template<typename T>3459success<typename std::decay<T>::type> ok(T&& v)3460{3461return success<typename std::decay<T>::type>(std::forward<T>(v));3462}3463template<std::size_t N>3464success<std::string> ok(const char (&literal)[N])3465{3466return success<std::string>(std::string(literal));3467}34683469// -----------------------------------------------------------------------------34703471template<typename T>3472struct failure3473{3474using value_type = T;34753476explicit failure(value_type v)3477noexcept(std::is_nothrow_move_constructible<value_type>::value)3478: value(std::move(v))3479{}34803481template<typename U, cxx::enable_if_t<3482std::is_convertible<cxx::remove_cvref_t<U>, T>::value,3483std::nullptr_t> = nullptr>3484explicit failure(U&& v): value(std::forward<U>(v)) {}34853486template<typename U>3487explicit failure(failure<U> v): value(std::move(v.value)) {}34883489~failure() = default;3490failure(const failure&) = default;3491failure(failure&&) = default;3492failure& operator=(const failure&) = default;3493failure& operator=(failure&&) = default;34943495value_type& get() noexcept {return value;}3496value_type const& get() const noexcept {return value;}34973498private:34993500value_type value;3501};35023503template<typename T>3504struct failure<std::reference_wrapper<T>>3505{3506using value_type = T;35073508explicit failure(std::reference_wrapper<value_type> v) noexcept3509: value(std::move(v))3510{}35113512~failure() = default;3513failure(const failure&) = default;3514failure(failure&&) = default;3515failure& operator=(const failure&) = default;3516failure& operator=(failure&&) = default;35173518value_type& get() noexcept {return value.get();}3519value_type const& get() const noexcept {return value.get();}35203521private:35223523std::reference_wrapper<value_type> value;3524};35253526template<typename T>3527failure<typename std::decay<T>::type> err(T&& v)3528{3529return failure<typename std::decay<T>::type>(std::forward<T>(v));3530}35313532template<std::size_t N>3533failure<std::string> err(const char (&literal)[N])3534{3535return failure<std::string>(std::string(literal));3536}35373538/* ============================================================================3539* _ _3540* _ _ ___ ____ _| | |_3541* | '_/ -_|_-< || | | _|3542* |_| \___/__/\_,_|_|\__|3543*/35443545template<typename T, typename E>3546struct result3547{3548using success_type = success<T>;3549using failure_type = failure<E>;3550using value_type = typename success_type::value_type;3551using error_type = typename failure_type::value_type;35523553result(success_type s): is_ok_(true), succ_(std::move(s)) {}3554result(failure_type f): is_ok_(false), fail_(std::move(f)) {}35553556template<typename U, cxx::enable_if_t<cxx::conjunction<3557cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,3558std::is_convertible<cxx::remove_cvref_t<U>, value_type>3559>::value, std::nullptr_t> = nullptr>3560result(success<U> s): is_ok_(true), succ_(std::move(s.value)) {}35613562template<typename U, cxx::enable_if_t<cxx::conjunction<3563cxx::negation<std::is_same<cxx::remove_cvref_t<U>, error_type>>,3564std::is_convertible<cxx::remove_cvref_t<U>, error_type>3565>::value, std::nullptr_t> = nullptr>3566result(failure<U> f): is_ok_(false), fail_(std::move(f.value)) {}35673568result& operator=(success_type s)3569{3570this->cleanup();3571this->is_ok_ = true;3572auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(s));3573assert(tmp == std::addressof(this->succ_));3574(void)tmp;3575return *this;3576}3577result& operator=(failure_type f)3578{3579this->cleanup();3580this->is_ok_ = false;3581auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(f));3582assert(tmp == std::addressof(this->fail_));3583(void)tmp;3584return *this;3585}35863587template<typename U>3588result& operator=(success<U> s)3589{3590this->cleanup();3591this->is_ok_ = true;3592auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(s.value));3593assert(tmp == std::addressof(this->succ_));3594(void)tmp;3595return *this;3596}3597template<typename U>3598result& operator=(failure<U> f)3599{3600this->cleanup();3601this->is_ok_ = false;3602auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(f.value));3603assert(tmp == std::addressof(this->fail_));3604(void)tmp;3605return *this;3606}36073608~result() noexcept {this->cleanup();}36093610result(const result& other): is_ok_(other.is_ok())3611{3612if(other.is_ok())3613{3614auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);3615assert(tmp == std::addressof(this->succ_));3616(void)tmp;3617}3618else3619{3620auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_);3621assert(tmp == std::addressof(this->fail_));3622(void)tmp;3623}3624}3625result(result&& other): is_ok_(other.is_ok())3626{3627if(other.is_ok())3628{3629auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));3630assert(tmp == std::addressof(this->succ_));3631(void)tmp;3632}3633else3634{3635auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_));3636assert(tmp == std::addressof(this->fail_));3637(void)tmp;3638}3639}36403641result& operator=(const result& other)3642{3643this->cleanup();3644if(other.is_ok())3645{3646auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_);3647assert(tmp == std::addressof(this->succ_));3648(void)tmp;3649}3650else3651{3652auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_);3653assert(tmp == std::addressof(this->fail_));3654(void)tmp;3655}3656is_ok_ = other.is_ok();3657return *this;3658}3659result& operator=(result&& other)3660{3661this->cleanup();3662if(other.is_ok())3663{3664auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_));3665assert(tmp == std::addressof(this->succ_));3666(void)tmp;3667}3668else3669{3670auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_));3671assert(tmp == std::addressof(this->fail_));3672(void)tmp;3673}3674is_ok_ = other.is_ok();3675return *this;3676}36773678template<typename U, typename F, cxx::enable_if_t<cxx::conjunction<3679cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,3680cxx::negation<std::is_same<cxx::remove_cvref_t<F>, error_type>>,3681std::is_convertible<cxx::remove_cvref_t<U>, value_type>,3682std::is_convertible<cxx::remove_cvref_t<F>, error_type>3683>::value, std::nullptr_t> = nullptr>3684result(result<U, F> other): is_ok_(other.is_ok())3685{3686if(other.is_ok())3687{3688auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok()));3689assert(tmp == std::addressof(this->succ_));3690(void)tmp;3691}3692else3693{3694auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));3695assert(tmp == std::addressof(this->fail_));3696(void)tmp;3697}3698}36993700template<typename U, typename F, cxx::enable_if_t<cxx::conjunction<3701cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,3702cxx::negation<std::is_same<cxx::remove_cvref_t<F>, error_type>>,3703std::is_convertible<cxx::remove_cvref_t<U>, value_type>,3704std::is_convertible<cxx::remove_cvref_t<F>, error_type>3705>::value, std::nullptr_t> = nullptr>3706result& operator=(result<U, F> other)3707{3708this->cleanup();3709if(other.is_ok())3710{3711auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok()));3712assert(tmp == std::addressof(this->succ_));3713(void)tmp;3714}3715else3716{3717auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err()));3718assert(tmp == std::addressof(this->fail_));3719(void)tmp;3720}3721is_ok_ = other.is_ok();3722return *this;3723}37243725bool is_ok() const noexcept {return is_ok_;}3726bool is_err() const noexcept {return !is_ok_;}37273728explicit operator bool() const noexcept {return is_ok_;}37293730value_type& unwrap(cxx::source_location loc = cxx::source_location::current())3731{3732if(this->is_err())3733{3734throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc));3735}3736return this->succ_.get();3737}3738value_type const& unwrap(cxx::source_location loc = cxx::source_location::current()) const3739{3740if(this->is_err())3741{3742throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc));3743}3744return this->succ_.get();3745}37463747value_type& unwrap_or(value_type& opt) noexcept3748{3749if(this->is_err()) {return opt;}3750return this->succ_.get();3751}3752value_type const& unwrap_or(value_type const& opt) const noexcept3753{3754if(this->is_err()) {return opt;}3755return this->succ_.get();3756}37573758error_type& unwrap_err(cxx::source_location loc = cxx::source_location::current())3759{3760if(this->is_ok())3761{3762throw bad_result_access("toml::result: bad unwrap_err" + cxx::to_string(loc));3763}3764return this->fail_.get();3765}3766error_type const& unwrap_err(cxx::source_location loc = cxx::source_location::current()) const3767{3768if(this->is_ok())3769{3770throw bad_result_access("toml::result: bad unwrap_err" + cxx::to_string(loc));3771}3772return this->fail_.get();3773}37743775value_type& as_ok() noexcept3776{3777assert(this->is_ok());3778return this->succ_.get();3779}3780value_type const& as_ok() const noexcept3781{3782assert(this->is_ok());3783return this->succ_.get();3784}37853786error_type& as_err() noexcept3787{3788assert(this->is_err());3789return this->fail_.get();3790}3791error_type const& as_err() const noexcept3792{3793assert(this->is_err());3794return this->fail_.get();3795}37963797private:37983799void cleanup() noexcept3800{3801#if defined(__GNUC__) && ! defined(__clang__)3802#pragma GCC diagnostic push3803#pragma GCC diagnostic ignored "-Wduplicated-branches"3804#endif38053806if(this->is_ok_) {this->succ_.~success_type();}3807else {this->fail_.~failure_type();}38083809#if defined(__GNUC__) && ! defined(__clang__)3810#pragma GCC diagnostic pop3811#endif3812return;3813}38143815private:38163817bool is_ok_;3818union3819{3820success_type succ_;3821failure_type fail_;3822};3823};38243825// ----------------------------------------------------------------------------38263827namespace detail3828{3829struct none_t {};3830inline bool operator==(const none_t&, const none_t&) noexcept {return true;}3831inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}3832inline bool operator< (const none_t&, const none_t&) noexcept {return false;}3833inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}3834inline bool operator> (const none_t&, const none_t&) noexcept {return false;}3835inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}3836inline std::ostream& operator<<(std::ostream& os, const none_t&)3837{3838os << "none";3839return os;3840}3841} // detail38423843inline success<detail::none_t> ok() noexcept3844{3845return success<detail::none_t>(detail::none_t{});3846}3847inline failure<detail::none_t> err() noexcept3848{3849return failure<detail::none_t>(detail::none_t{});3850}38513852} // TOML11_INLINE_VERSION_NAMESPACE3853} // toml3854#endif // TOML11_RESULT_HPP3855#ifndef TOML11_UTILITY_HPP3856#define TOML11_UTILITY_HPP385738583859#include <array>3860#include <sstream>38613862#include <cassert>3863#include <cctype>3864#include <cstring>38653866namespace toml3867{3868inline namespace TOML11_INLINE_VERSION_NAMESPACE3869{3870namespace detail3871{38723873// to output character in an error message.3874inline std::string show_char(const int c)3875{3876using char_type = unsigned char;3877if(std::isgraph(c))3878{3879return std::string(1, static_cast<char>(c));3880}3881else3882{3883std::array<char, 5> buf;3884buf.fill('\0');3885const auto r = std::snprintf(buf.data(), buf.size(), "0x%02x", c & 0xFF);3886assert(r == static_cast<int>(buf.size()) - 1);3887(void) r; // Unused variable warning3888auto in_hex = std::string(buf.data());3889switch(c)3890{3891case char_type('\0'): {in_hex += "(NUL)"; break;}3892case char_type(' ') : {in_hex += "(SPACE)"; break;}3893case char_type('\n'): {in_hex += "(LINE FEED)"; break;}3894case char_type('\r'): {in_hex += "(CARRIAGE RETURN)"; break;}3895case char_type('\t'): {in_hex += "(TAB)"; break;}3896case char_type('\v'): {in_hex += "(VERTICAL TAB)"; break;}3897case char_type('\f'): {in_hex += "(FORM FEED)"; break;}3898case char_type('\x1B'): {in_hex += "(ESCAPE)"; break;}3899default: break;3900}3901return in_hex;3902}3903}39043905// ---------------------------------------------------------------------------39063907template<typename Container>3908void try_reserve_impl(Container& container, std::size_t N, std::true_type)3909{3910container.reserve(N);3911return;3912}3913template<typename Container>3914void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept3915{3916return;3917}39183919template<typename Container>3920void try_reserve(Container& container, std::size_t N)3921{3922try_reserve_impl(container, N, has_reserve_method<Container>{});3923return;3924}39253926// ---------------------------------------------------------------------------39273928template<typename T>3929result<T, none_t> from_string(const std::string& str)3930{3931T v;3932std::istringstream iss(str);3933iss >> v;3934if(iss.fail())3935{3936return err();3937}3938return ok(v);3939}39403941// ---------------------------------------------------------------------------39423943// helper function to avoid std::string(0, 'c') or std::string(iter, iter)3944template<typename Iterator>3945std::string make_string(Iterator first, Iterator last)3946{3947if(first == last) {return "";}3948return std::string(first, last);3949}3950inline std::string make_string(std::size_t len, char c)3951{3952if(len == 0) {return "";}3953return std::string(len, c);3954}39553956// ---------------------------------------------------------------------------39573958template<typename Char, typename Traits, typename Alloc,3959typename Char2, typename Traits2, typename Alloc2>3960struct string_conv_impl3961{3962static_assert(sizeof(Char) == sizeof(char), "");3963static_assert(sizeof(Char2) == sizeof(char), "");39643965static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char2, Traits2, Alloc2> s)3966{3967std::basic_string<Char, Traits, Alloc> retval;3968std::transform(s.begin(), s.end(), std::back_inserter(retval),3969[](const Char2 c) {return static_cast<Char>(c);});3970return retval;3971}3972template<std::size_t N>3973static std::basic_string<Char, Traits, Alloc> invoke(const Char2 (&s)[N])3974{3975std::basic_string<Char, Traits, Alloc> retval;3976// "string literal" has null-char at the end. to skip it, we use prev.3977std::transform(std::begin(s), std::prev(std::end(s)), std::back_inserter(retval),3978[](const Char2 c) {return static_cast<Char>(c);});3979return retval;3980}3981};39823983template<typename Char, typename Traits, typename Alloc>3984struct string_conv_impl<Char, Traits, Alloc, Char, Traits, Alloc>3985{3986static_assert(sizeof(Char) == sizeof(char), "");39873988static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char, Traits, Alloc> s)3989{3990return s;3991}3992template<std::size_t N>3993static std::basic_string<Char, Traits, Alloc> invoke(const Char (&s)[N])3994{3995return std::basic_string<Char, Traits, Alloc>(s);3996}3997};39983999template<typename S, typename Char2, typename Traits2, typename Alloc2>4000cxx::enable_if_t<is_std_basic_string<S>::value, S>4001string_conv(std::basic_string<Char2, Traits2, Alloc2> s)4002{4003using C = typename S::value_type;4004using T = typename S::traits_type;4005using A = typename S::allocator_type;4006return string_conv_impl<C, T, A, Char2, Traits2, Alloc2>::invoke(std::move(s));4007}4008template<typename S, std::size_t N>4009cxx::enable_if_t<is_std_basic_string<S>::value, S>4010string_conv(const char (&s)[N])4011{4012using C = typename S::value_type;4013using T = typename S::traits_type;4014using A = typename S::allocator_type;4015using C2 = char;4016using T2 = std::char_traits<C2>;4017using A2 = std::allocator<C2>;40184019return string_conv_impl<C, T, A, C2, T2, A2>::template invoke<N>(s);4020}40214022} // namespace detail4023} // TOML11_INLINE_VERSION_NAMESPACE4024} // namespace toml4025#endif // TOML11_UTILITY_HPP4026#ifndef TOML11_LOCATION_HPP4027#define TOML11_LOCATION_HPP40284029#ifndef TOML11_LOCATION_FWD_HPP4030#define TOML11_LOCATION_FWD_HPP403140324033#include <memory>4034#include <string>4035#include <vector>40364037namespace toml4038{4039inline namespace TOML11_INLINE_VERSION_NAMESPACE4040{4041namespace detail4042{40434044class region; // fwd decl40454046//4047// To represent where we are reading in the parse functions.4048// Since it "points" somewhere in the input stream, the length is always 1.4049//4050class location4051{4052public:40534054using char_type = unsigned char; // must be unsigned4055using container_type = std::vector<char_type>;4056using difference_type = typename container_type::difference_type; // to suppress sign-conversion warning4057using source_ptr = std::shared_ptr<const container_type>;40584059public:40604061location(source_ptr src, std::string src_name)4062: source_(std::move(src)), source_name_(std::move(src_name)),4063location_(0), line_number_(1), column_number_(1)4064{}40654066location(const location&) = default;4067location(location&&) = default;4068location& operator=(const location&) = default;4069location& operator=(location&&) = default;4070~location() = default;40714072void advance(std::size_t n = 1) noexcept;4073void retrace() noexcept;40744075bool is_ok() const noexcept { return static_cast<bool>(this->source_); }40764077bool eof() const noexcept;4078char_type current() const;40794080char_type peek();40814082std::size_t get_location() const noexcept4083{4084return this->location_;4085}40864087std::size_t line_number() const noexcept4088{4089return this->line_number_;4090}4091std::size_t column_number() const noexcept4092{4093return this->column_number_;4094}4095std::string get_line() const;40964097source_ptr const& source() const noexcept {return this->source_;}4098std::string const& source_name() const noexcept {return this->source_name_;}40994100private:41014102void advance_impl(const std::size_t n);4103void retrace_impl();4104std::size_t calc_column_number() const noexcept;41054106private:41074108friend region;41094110private:41114112source_ptr source_;4113std::string source_name_;4114std::size_t location_; // std::vector<>::difference_type is signed4115std::size_t line_number_;4116std::size_t column_number_;4117};41184119bool operator==(const location& lhs, const location& rhs) noexcept;4120bool operator!=(const location& lhs, const location& rhs);41214122location prev(const location& loc);4123location next(const location& loc);4124location make_temporary_location(const std::string& str) noexcept;41254126template<typename F>4127result<location, none_t>4128find_if(const location& first, const location& last, const F& func) noexcept4129{4130if(first.source() != last.source()) { return err(); }4131if(first.get_location() >= last.get_location()) { return err(); }41324133auto loc = first;4134while(loc.get_location() != last.get_location())4135{4136if(func(loc.current()))4137{4138return ok(loc);4139}4140loc.advance();4141}4142return err();4143}41444145template<typename F>4146result<location, none_t>4147rfind_if(location first, const location& last, const F& func)4148{4149if(first.source() != last.source()) { return err(); }4150if(first.get_location() >= last.get_location()) { return err(); }41514152auto loc = last;4153while(loc.get_location() != first.get_location())4154{4155if(func(loc.current()))4156{4157return ok(loc);4158}4159loc.retrace();4160}4161if(func(first.current()))4162{4163return ok(first);4164}4165return err();4166}41674168result<location, none_t> find(const location& first, const location& last,4169const location::char_type val);4170result<location, none_t> rfind(const location& first, const location& last,4171const location::char_type val);41724173std::size_t count(const location& first, const location& last,4174const location::char_type& c);41754176} // detail4177} // TOML11_INLINE_VERSION_NAMESPACE4178} // toml4179#endif // TOML11_LOCATION_FWD_HPP41804181#if ! defined(TOML11_COMPILE_SOURCES)4182#ifndef TOML11_LOCATION_IMPL_HPP4183#define TOML11_LOCATION_IMPL_HPP418441854186namespace toml4187{4188inline namespace TOML11_INLINE_VERSION_NAMESPACE4189{4190namespace detail4191{41924193TOML11_INLINE void location::advance(std::size_t n) noexcept4194{4195assert(this->is_ok());4196if(this->location_ + n < this->source_->size())4197{4198this->advance_impl(n);4199}4200else4201{4202this->advance_impl(this->source_->size() - this->location_);42034204assert(this->location_ == this->source_->size());4205}4206}4207TOML11_INLINE void location::retrace(/*restricted to n=1*/) noexcept4208{4209assert(this->is_ok());4210if(this->location_ == 0)4211{4212this->location_ = 0;4213this->line_number_ = 1;4214this->column_number_ = 1;4215}4216else4217{4218this->retrace_impl();4219}4220}42214222TOML11_INLINE bool location::eof() const noexcept4223{4224assert(this->is_ok());4225return this->location_ >= this->source_->size();4226}4227TOML11_INLINE location::char_type location::current() const4228{4229assert(this->is_ok());4230if(this->eof()) {return '\0';}42314232assert(this->location_ < this->source_->size());4233return this->source_->at(this->location_);4234}42354236TOML11_INLINE location::char_type location::peek()4237{4238assert(this->is_ok());4239if(this->location_ >= this->source_->size())4240{4241return '\0';4242}4243else4244{4245return this->source_->at(this->location_ + 1);4246}4247}42484249TOML11_INLINE std::string location::get_line() const4250{4251assert(this->is_ok());4252const auto iter = std::next(this->source_->cbegin(), static_cast<difference_type>(this->location_));4253const auto riter = cxx::make_reverse_iterator(iter);42544255const auto prev = std::find(riter, this->source_->crend(), char_type('\n'));4256const auto next = std::find(iter, this->source_->cend(), char_type('\n'));42574258return make_string(std::next(prev.base()), next);4259}42604261TOML11_INLINE std::size_t location::calc_column_number() const noexcept4262{4263assert(this->is_ok());4264const auto iter = std::next(this->source_->cbegin(), static_cast<difference_type>(this->location_));4265const auto riter = cxx::make_reverse_iterator(iter);4266const auto prev = std::find(riter, this->source_->crend(), char_type('\n'));42674268assert(prev.base() <= iter);4269return static_cast<std::size_t>(std::distance(prev.base(), iter) + 1); // 1-origin4270}42714272TOML11_INLINE void location::advance_impl(const std::size_t n)4273{4274assert(this->is_ok());4275assert(this->location_ + n <= this->source_->size());42764277auto iter = this->source_->cbegin();4278std::advance(iter, static_cast<difference_type>(this->location_));42794280for(std::size_t i=0; i<n; ++i)4281{4282const auto c = *iter;4283if(c == char_type('\n'))4284{4285this->line_number_ += 1;4286this->column_number_ = 1;4287}4288else4289{4290this->column_number_ += 1;4291}4292iter++;4293}4294this->location_ += n;4295return;4296}4297TOML11_INLINE void location::retrace_impl(/*n == 1*/)4298{4299assert(this->is_ok());4300assert(this->location_ != 0);43014302this->location_ -= 1;43034304auto iter = this->source_->cbegin();4305std::advance(iter, static_cast<difference_type>(this->location_));4306if(*iter == '\n')4307{4308this->line_number_ -= 1;4309this->column_number_ = this->calc_column_number();4310}4311return;4312}43134314TOML11_INLINE bool operator==(const location& lhs, const location& rhs) noexcept4315{4316if( ! lhs.is_ok() || ! rhs.is_ok())4317{4318return (!lhs.is_ok()) && (!rhs.is_ok());4319}4320return lhs.source() == rhs.source() &&4321lhs.source_name() == rhs.source_name() &&4322lhs.get_location() == rhs.get_location();4323}4324TOML11_INLINE bool operator!=(const location& lhs, const location& rhs)4325{4326return !(lhs == rhs);4327}43284329TOML11_INLINE location prev(const location& loc)4330{4331location p(loc);4332p.retrace();4333return p;4334}4335TOML11_INLINE location next(const location& loc)4336{4337location p(loc);4338p.advance(1);4339return p;4340}43414342TOML11_INLINE location make_temporary_location(const std::string& str) noexcept4343{4344location::container_type cont(str.size());4345std::transform(str.begin(), str.end(), cont.begin(),4346[](const std::string::value_type& c) {4347return cxx::bit_cast<location::char_type>(c);4348});4349return location(std::make_shared<const location::container_type>(4350std::move(cont)), "internal temporary");4351}43524353TOML11_INLINE result<location, none_t>4354find(const location& first, const location& last, const location::char_type val)4355{4356return find_if(first, last, [val](const location::char_type c) {4357return c == val;4358});4359}4360TOML11_INLINE result<location, none_t>4361rfind(const location& first, const location& last, const location::char_type val)4362{4363return rfind_if(first, last, [val](const location::char_type c) {4364return c == val;4365});4366}43674368TOML11_INLINE std::size_t4369count(const location& first, const location& last, const location::char_type& c)4370{4371if(first.source() != last.source()) { return 0; }4372if(first.get_location() >= last.get_location()) { return 0; }43734374auto loc = first;4375std::size_t num = 0;4376while(loc.get_location() != last.get_location())4377{4378if(loc.current() == c)4379{4380num += 1;4381}4382loc.advance();4383}4384return num;4385}43864387} // detail4388} // TOML11_INLINE_VERSION_NAMESPACE4389} // toml4390#endif // TOML11_LOCATION_HPP4391#endif43924393#endif // TOML11_LOCATION_HPP4394#ifndef TOML11_REGION_HPP4395#define TOML11_REGION_HPP43964397#ifndef TOML11_REGION_FWD_HPP4398#define TOML11_REGION_FWD_HPP439944004401#include <string>4402#include <vector>44034404#include <cassert>44054406namespace toml4407{4408inline namespace TOML11_INLINE_VERSION_NAMESPACE4409{4410namespace detail4411{44124413//4414// To represent where is a toml::value defined, or where does an error occur.4415// Stored in toml::value. source_location will be constructed based on this.4416//4417class region4418{4419public:44204421using char_type = location::char_type;4422using container_type = location::container_type;4423using difference_type = location::difference_type;4424using source_ptr = location::source_ptr;44254426using iterator = typename container_type::iterator;4427using const_iterator = typename container_type::const_iterator;44284429public:44304431// a value that is constructed manually does not have input stream info4432region()4433: source_(nullptr), source_name_(""), length_(0),4434first_(0), first_line_(0), first_column_(0), last_(0), last_line_(0),4435last_column_(0)4436{}44374438// a value defined in [first, last).4439// Those source must be the same. Instread, `region` does not make sense.4440region(const location& first, const location& last);44414442// shorthand of [loc, loc+1)4443explicit region(const location& loc);44444445~region() = default;4446region(const region&) = default;4447region(region&&) = default;4448region& operator=(const region&) = default;4449region& operator=(region&&) = default;44504451bool is_ok() const noexcept { return static_cast<bool>(this->source_); }44524453operator bool() const noexcept { return this->is_ok(); }44544455std::size_t length() const noexcept {return this->length_;}44564457std::size_t first_line_number() const noexcept4458{4459return this->first_line_;4460}4461std::size_t first_column_number() const noexcept4462{4463return this->first_column_;4464}4465std::size_t last_line_number() const noexcept4466{4467return this->last_line_;4468}4469std::size_t last_column_number() const noexcept4470{4471return this->last_column_;4472}44734474char_type at(std::size_t i) const;44754476const_iterator begin() const noexcept;4477const_iterator end() const noexcept;4478const_iterator cbegin() const noexcept;4479const_iterator cend() const noexcept;44804481std::string as_string() const;4482std::vector<std::pair<std::string, std::size_t>> as_lines() const;44834484source_ptr const& source() const noexcept {return this->source_;}4485std::string const& source_name() const noexcept {return this->source_name_;}44864487private:44884489std::pair<std::string, std::size_t>4490take_line(const_iterator begin, const_iterator end) const;44914492private:44934494source_ptr source_;4495std::string source_name_;4496std::size_t length_;4497std::size_t first_;4498std::size_t first_line_;4499std::size_t first_column_;4500std::size_t last_;4501std::size_t last_line_;4502std::size_t last_column_;4503};45044505} // namespace detail4506} // TOML11_INLINE_VERSION_NAMESPACE4507} // namespace toml4508#endif // TOML11_REGION_FWD_HPP45094510#if ! defined(TOML11_COMPILE_SOURCES)4511#ifndef TOML11_REGION_IMPL_HPP4512#define TOML11_REGION_IMPL_HPP451345144515#include <algorithm>4516#include <iterator>4517#include <string>4518#include <sstream>4519#include <vector>4520#include <cassert>45214522namespace toml4523{4524inline namespace TOML11_INLINE_VERSION_NAMESPACE4525{4526namespace detail4527{45284529// a value defined in [first, last).4530// Those source must be the same. Instread, `region` does not make sense.4531TOML11_INLINE region::region(const location& first, const location& last)4532: source_(first.source()), source_name_(first.source_name()),4533length_(last.get_location() - first.get_location()),4534first_(first.get_location()),4535first_line_(first.line_number()),4536first_column_(first.column_number()),4537last_(last.get_location()),4538last_line_(last.line_number()),4539last_column_(last.column_number())4540{4541assert(first.source() == last.source());4542assert(first.source_name() == last.source_name());4543}45444545// shorthand of [loc, loc+1)4546TOML11_INLINE region::region(const location& loc)4547: source_(loc.source()), source_name_(loc.source_name()), length_(0),4548first_line_(0), first_column_(0), last_line_(0), last_column_(0)4549{4550// if the file ends with LF, the resulting region points no char.4551if(loc.eof())4552{4553if(loc.get_location() == 0)4554{4555this->length_ = 0;4556this->first_ = 0;4557this->first_line_ = 0;4558this->first_column_ = 0;4559this->last_ = 0;4560this->last_line_ = 0;4561this->last_column_ = 0;4562}4563else4564{4565const auto first = prev(loc);4566this->first_ = first.get_location();4567this->first_line_ = first.line_number();4568this->first_column_ = first.column_number();4569this->last_ = loc.get_location();4570this->last_line_ = loc.line_number();4571this->last_column_ = loc.column_number();4572this->length_ = 1;4573}4574}4575else4576{4577this->first_ = loc.get_location();4578this->first_line_ = loc.line_number();4579this->first_column_ = loc.column_number();4580this->last_ = loc.get_location() + 1;4581this->last_line_ = loc.line_number();4582this->last_column_ = loc.column_number() + 1;4583this->length_ = 1;4584}4585}45864587TOML11_INLINE region::char_type region::at(std::size_t i) const4588{4589if(this->last_ <= this->first_ + i)4590{4591throw std::out_of_range("range::at: index " + std::to_string(i) +4592" exceeds length " + std::to_string(this->length_));4593}4594const auto iter = std::next(this->source_->cbegin(),4595static_cast<difference_type>(this->first_ + i));4596return *iter;4597}45984599TOML11_INLINE region::const_iterator region::begin() const noexcept4600{4601return std::next(this->source_->cbegin(),4602static_cast<difference_type>(this->first_));4603}4604TOML11_INLINE region::const_iterator region::end() const noexcept4605{4606return std::next(this->source_->cbegin(),4607static_cast<difference_type>(this->last_));4608}4609TOML11_INLINE region::const_iterator region::cbegin() const noexcept4610{4611return std::next(this->source_->cbegin(),4612static_cast<difference_type>(this->first_));4613}4614TOML11_INLINE region::const_iterator region::cend() const noexcept4615{4616return std::next(this->source_->cbegin(),4617static_cast<difference_type>(this->last_));4618}46194620TOML11_INLINE std::string region::as_string() const4621{4622if(this->is_ok())4623{4624const auto begin = std::next(this->source_->cbegin(), static_cast<difference_type>(this->first_));4625const auto end = std::next(this->source_->cbegin(), static_cast<difference_type>(this->last_ ));4626return ::toml::detail::make_string(begin, end);4627}4628else4629{4630return std::string("");4631}4632}46334634TOML11_INLINE std::pair<std::string, std::size_t>4635region::take_line(const_iterator begin, const_iterator end) const4636{4637// To omit long line, we cap region by before/after 30 chars4638const auto dist_before = std::distance(source_->cbegin(), begin);4639const auto dist_after = std::distance(end, source_->cend());46404641const const_iterator capped_begin = (dist_before <= 30) ? source_->cbegin() : std::prev(begin, 30);4642const const_iterator capped_end = (dist_after <= 30) ? source_->cend() : std::next(end, 30);46434644const auto lf = char_type('\n');4645const auto lf_before = std::find(cxx::make_reverse_iterator(begin),4646cxx::make_reverse_iterator(capped_begin), lf);4647const auto lf_after = std::find(end, capped_end, lf);46484649auto offset = static_cast<std::size_t>(std::distance(lf_before.base(), begin));46504651std::string retval = make_string(lf_before.base(), lf_after);46524653if(lf_before.base() != source_->cbegin() && *lf_before != lf)4654{4655retval = "... " + retval;4656offset += 4;4657}46584659if(lf_after != source_->cend() && *lf_after != lf)4660{4661retval = retval + " ...";4662}46634664return std::make_pair(retval, offset);4665}46664667TOML11_INLINE std::vector<std::pair<std::string, std::size_t>> region::as_lines() const4668{4669assert(this->is_ok());4670if(this->length_ == 0)4671{4672return std::vector<std::pair<std::string, std::size_t>>{4673std::make_pair("", std::size_t(0))4674};4675}46764677// Consider the following toml file4678// ```4679// array = [4680// 1, 2, 3,4681// ] # comment4682// ```4683// and the region represnets4684// ```4685// [4686// 1, 2, 3,4687// ]4688// ```4689// but we want to show the following.4690// ```4691// array = [4692// 1, 2, 3,4693// ] # comment4694// ```4695// So we need to find LFs before `begin` and after `end`.4696//4697// But, if region ends with LF, it should not include the next line.4698// ```4699// a = 424700// ^^^- with the last LF4701// ```4702// So we start from `end-1` when looking for LF.47034704const auto begin_idx = static_cast<difference_type>(this->first_);4705const auto end_idx = static_cast<difference_type>(this->last_) - 1;47064707// length_ != 0, so begin < end. then begin <= end-14708assert(begin_idx <= end_idx);47094710const auto begin = std::next(this->source_->cbegin(), begin_idx);4711const auto end = std::next(this->source_->cbegin(), end_idx);47124713assert(this->first_line_number() <= this->last_line_number());47144715if(this->first_line_number() == this->last_line_number())4716{4717return std::vector<std::pair<std::string, std::size_t>>{4718this->take_line(begin, end)4719};4720}47214722// we have multiple lines. `begin` and `end` points different lines.4723// that means that there is at least one `LF` between `begin` and `end`.47244725const auto after_begin = std::distance(begin, this->source_->cend());4726const auto before_end = std::distance(this->source_->cbegin(), end);47274728const_iterator capped_file_end = this->source_->cend();4729const_iterator capped_file_begin = this->source_->cbegin();4730if(60 < after_begin) {capped_file_end = std::next(begin, 50);}4731if(60 < before_end) {capped_file_begin = std::prev(end, 50);}47324733const auto lf = char_type('\n');4734const auto first_line_end = std::find(begin, capped_file_end, lf);4735const auto last_line_begin = std::find(capped_file_begin, end, lf);47364737const auto first_line = this->take_line(begin, first_line_end);4738const auto last_line = this->take_line(last_line_begin, end);47394740if(this->first_line_number() + 1 == this->last_line_number())4741{4742return std::vector<std::pair<std::string, std::size_t>>{4743first_line, last_line4744};4745}4746else4747{4748return std::vector<std::pair<std::string, std::size_t>>{4749first_line, std::make_pair("...", 0), last_line4750};4751}4752}47534754} // namespace detail4755} // TOML11_INLINE_VERSION_NAMESPACE4756} // namespace toml4757#endif // TOML11_REGION_IMPL_HPP4758#endif47594760#endif // TOML11_REGION_HPP4761#ifndef TOML11_SCANNER_HPP4762#define TOML11_SCANNER_HPP47634764#ifndef TOML11_SCANNER_FWD_HPP4765#define TOML11_SCANNER_FWD_HPP476647674768#include <memory>4769#include <string>4770#include <utility>4771#include <vector>47724773#include <cassert>4774#include <cstdio>4775#include <cctype>47764777namespace toml4778{4779inline namespace TOML11_INLINE_VERSION_NAMESPACE4780{4781namespace detail4782{47834784class scanner_base4785{4786public:4787virtual ~scanner_base() = default;4788virtual region scan(location& loc) const = 0;4789virtual scanner_base* clone() const = 0;47904791// returns expected character or set of characters or literal.4792// to show the error location, it changes loc (in `sequence`, especially).4793virtual std::string expected_chars(location& loc) const = 0;4794virtual std::string name() const = 0;4795};47964797// make `scanner*` copyable4798struct scanner_storage4799{4800template<typename Scanner, cxx::enable_if_t<4801std::is_base_of<scanner_base, cxx::remove_cvref_t<Scanner>>::value,4802std::nullptr_t> = nullptr>4803explicit scanner_storage(Scanner&& s)4804: scanner_(cxx::make_unique<cxx::remove_cvref_t<Scanner>>(std::forward<Scanner>(s)))4805{}4806~scanner_storage() = default;48074808scanner_storage(const scanner_storage& other);4809scanner_storage& operator=(const scanner_storage& other);4810scanner_storage(scanner_storage&&) = default;4811scanner_storage& operator=(scanner_storage&&) = default;48124813bool is_ok() const noexcept {return static_cast<bool>(scanner_);}48144815region scan(location& loc) const;48164817std::string expected_chars(location& loc) const;48184819scanner_base& get() const noexcept;48204821std::string name() const;48224823private:48244825std::unique_ptr<scanner_base> scanner_;4826};48274828// ----------------------------------------------------------------------------48294830class character final : public scanner_base4831{4832public:48334834using char_type = location::char_type;48354836public:48374838explicit character(const char_type c) noexcept4839: value_(c)4840{}4841~character() override = default;48424843region scan(location& loc) const override;48444845std::string expected_chars(location&) const override;48464847scanner_base* clone() const override;48484849std::string name() const override;48504851private:4852char_type value_;4853};48544855// ----------------------------------------------------------------------------48564857class character_either final : public scanner_base4858{4859public:48604861using char_type = location::char_type;48624863public:48644865template<std::size_t N>4866explicit character_either(const char (&cs)[N]) noexcept4867: value_(cs), size_(N-1) // remove null character at the end4868{}4869~character_either() override = default;48704871region scan(location& loc) const override;48724873std::string expected_chars(location&) const override;48744875scanner_base* clone() const override;48764877std::string name() const override;48784879private:4880const char* value_;4881std::size_t size_;4882};48834884// ----------------------------------------------------------------------------48854886class character_in_range final : public scanner_base4887{4888public:48894890using char_type = location::char_type;48914892public:48934894explicit character_in_range(const char_type from, const char_type to) noexcept4895: from_(from), to_(to)4896{}4897~character_in_range() override = default;48984899region scan(location& loc) const override;49004901std::string expected_chars(location&) const override;49024903scanner_base* clone() const override;49044905std::string name() const override;49064907private:4908char_type from_;4909char_type to_;4910};49114912// ----------------------------------------------------------------------------49134914class literal final : public scanner_base4915{4916public:49174918using char_type = location::char_type;49194920public:49214922template<std::size_t N>4923explicit literal(const char (&cs)[N]) noexcept4924: value_(cs), size_(N-1) // remove null character at the end4925{}4926~literal() override = default;49274928region scan(location& loc) const override;49294930std::string expected_chars(location&) const override;49314932scanner_base* clone() const override;49334934std::string name() const override;49354936private:4937const char* value_;4938std::size_t size_;4939};49404941// ----------------------------------------------------------------------------49424943class sequence final: public scanner_base4944{4945public:4946using char_type = location::char_type;49474948public:49494950template<typename ... Ts>4951explicit sequence(Ts&& ... args)4952{4953push_back_all(std::forward<Ts>(args)...);4954}4955sequence(const sequence&) = default;4956sequence(sequence&&) = default;4957sequence& operator=(const sequence&) = default;4958sequence& operator=(sequence&&) = default;4959~sequence() override = default;49604961region scan(location& loc) const override;49624963std::string expected_chars(location& loc) const override;49644965scanner_base* clone() const override;49664967std::string name() const override;49684969private:49704971void push_back_all()4972{4973return;4974}4975template<typename T, typename ... Ts>4976void push_back_all(T&& head, Ts&& ... args)4977{4978others_.emplace_back(std::forward<T>(head));4979push_back_all(std::forward<Ts>(args)...);4980return;4981}49824983private:4984std::vector<scanner_storage> others_;4985};49864987// ----------------------------------------------------------------------------49884989class either final: public scanner_base4990{4991public:4992using char_type = location::char_type;49934994public:49954996template<typename ... Ts>4997explicit either(Ts&& ... args)4998{4999push_back_all(std::forward<Ts>(args)...);5000}5001either(const either&) = default;5002either(either&&) = default;5003either& operator=(const either&) = default;5004either& operator=(either&&) = default;5005~either() override = default;50065007region scan(location& loc) const override;50085009std::string expected_chars(location& loc) const override;50105011scanner_base* clone() const override;50125013std::string name() const override;50145015private:50165017void push_back_all()5018{5019return;5020}5021template<typename T, typename ... Ts>5022void push_back_all(T&& head, Ts&& ... args)5023{5024others_.emplace_back(std::forward<T>(head));5025push_back_all(std::forward<Ts>(args)...);5026return;5027}50285029private:5030std::vector<scanner_storage> others_;5031};50325033// ----------------------------------------------------------------------------50345035class repeat_exact final: public scanner_base5036{5037public:5038using char_type = location::char_type;50395040public:50415042template<typename Scanner>5043repeat_exact(const std::size_t length, Scanner&& other)5044: length_(length), other_(std::forward<Scanner>(other))5045{}5046repeat_exact(const repeat_exact&) = default;5047repeat_exact(repeat_exact&&) = default;5048repeat_exact& operator=(const repeat_exact&) = default;5049repeat_exact& operator=(repeat_exact&&) = default;5050~repeat_exact() override = default;50515052region scan(location& loc) const override;50535054std::string expected_chars(location& loc) const override;50555056scanner_base* clone() const override;50575058std::string name() const override;50595060private:5061std::size_t length_;5062scanner_storage other_;5063};50645065// ----------------------------------------------------------------------------50665067class repeat_at_least final: public scanner_base5068{5069public:5070using char_type = location::char_type;50715072public:50735074template<typename Scanner>5075repeat_at_least(const std::size_t length, Scanner&& s)5076: length_(length), other_(std::forward<Scanner>(s))5077{}5078repeat_at_least(const repeat_at_least&) = default;5079repeat_at_least(repeat_at_least&&) = default;5080repeat_at_least& operator=(const repeat_at_least&) = default;5081repeat_at_least& operator=(repeat_at_least&&) = default;5082~repeat_at_least() override = default;50835084region scan(location& loc) const override;50855086std::string expected_chars(location& loc) const override;50875088scanner_base* clone() const override;50895090std::string name() const override;50915092private:5093std::size_t length_;5094scanner_storage other_;5095};50965097// ----------------------------------------------------------------------------50985099class maybe final: public scanner_base5100{5101public:5102using char_type = location::char_type;51035104public:51055106template<typename Scanner>5107explicit maybe(Scanner&& s)5108: other_(std::forward<Scanner>(s))5109{}5110maybe(const maybe&) = default;5111maybe(maybe&&) = default;5112maybe& operator=(const maybe&) = default;5113maybe& operator=(maybe&&) = default;5114~maybe() override = default;51155116region scan(location& loc) const override;51175118std::string expected_chars(location&) const override;51195120scanner_base* clone() const override;51215122std::string name() const override;51235124private:5125scanner_storage other_;5126};51275128} // detail5129} // TOML11_INLINE_VERSION_NAMESPACE5130} // toml5131#endif // TOML11_SCANNER_FWD_HPP51325133#if ! defined(TOML11_COMPILE_SOURCES)5134#ifndef TOML11_SCANNER_IMPL_HPP5135#define TOML11_SCANNER_IMPL_HPP513651375138namespace toml5139{5140inline namespace TOML11_INLINE_VERSION_NAMESPACE5141{5142namespace detail5143{51445145TOML11_INLINE scanner_storage::scanner_storage(const scanner_storage& other)5146: scanner_(nullptr)5147{5148if(other.is_ok())5149{5150scanner_.reset(other.get().clone());5151}5152}5153TOML11_INLINE scanner_storage& scanner_storage::operator=(const scanner_storage& other)5154{5155if(this == std::addressof(other)) {return *this;}5156if(other.is_ok())5157{5158scanner_.reset(other.get().clone());5159}5160return *this;5161}51625163TOML11_INLINE region scanner_storage::scan(location& loc) const5164{5165assert(this->is_ok());5166return this->scanner_->scan(loc);5167}51685169TOML11_INLINE std::string scanner_storage::expected_chars(location& loc) const5170{5171assert(this->is_ok());5172return this->scanner_->expected_chars(loc);5173}51745175TOML11_INLINE scanner_base& scanner_storage::get() const noexcept5176{5177assert(this->is_ok());5178return *scanner_;5179}51805181TOML11_INLINE std::string scanner_storage::name() const5182{5183assert(this->is_ok());5184return this->scanner_->name();5185}51865187// ----------------------------------------------------------------------------51885189TOML11_INLINE region character::scan(location& loc) const5190{5191if(loc.eof()) {return region{};}51925193if(loc.current() == this->value_)5194{5195const auto first = loc;5196loc.advance(1);5197return region(first, loc);5198}5199return region{};5200}52015202TOML11_INLINE std::string character::expected_chars(location&) const5203{5204return show_char(value_);5205}52065207TOML11_INLINE scanner_base* character::clone() const5208{5209return new character(*this);5210}52115212TOML11_INLINE std::string character::name() const5213{5214return "character{" + show_char(value_) + "}";5215}52165217// ----------------------------------------------------------------------------52185219TOML11_INLINE region character_either::scan(location& loc) const5220{5221if(loc.eof()) {return region{};}52225223for(std::size_t i=0; i<this->size_; ++i)5224{5225const auto c = char_type(this->value_[i]);5226if(loc.current() == c)5227{5228const auto first = loc;5229loc.advance(1);5230return region(first, loc);5231}5232}5233return region{};5234}52355236TOML11_INLINE std::string character_either::expected_chars(location&) const5237{5238assert( this->value_ );5239assert( this->size_ != 0 );52405241std::string expected;5242if(this->size_ == 1)5243{5244expected += show_char(char_type(value_[0]));5245}5246else if(this->size_ == 2)5247{5248expected += show_char(char_type(value_[0])) + " or " +5249show_char(char_type(value_[1]));5250}5251else5252{5253for(std::size_t i=0; i<this->size_; ++i)5254{5255if(i != 0)5256{5257expected += ", ";5258}5259if(i + 1 == this->size_)5260{5261expected += "or ";5262}5263expected += show_char(char_type(value_[i]));5264}5265}5266return expected;5267}52685269TOML11_INLINE scanner_base* character_either::clone() const5270{5271return new character_either(*this);5272}52735274TOML11_INLINE std::string character_either::name() const5275{5276std::string n("character_either{");5277for(std::size_t i=0; i<this->size_; ++i)5278{5279const auto c = char_type(this->value_[i]);5280n += show_char(c);5281n += ", ";5282}5283if(this->size_ != 0)5284{5285n.pop_back();5286n.pop_back();5287}5288n += "}";5289return n;5290}52915292// ----------------------------------------------------------------------------5293// character_in_range52945295TOML11_INLINE region character_in_range::scan(location& loc) const5296{5297if(loc.eof()) {return region{};}52985299const auto curr = loc.current();5300if(this->from_ <= curr && curr <= this->to_)5301{5302const auto first = loc;5303loc.advance(1);5304return region(first, loc);5305}5306return region{};5307}53085309TOML11_INLINE std::string character_in_range::expected_chars(location&) const5310{5311std::string expected("from `");5312expected += show_char(from_);5313expected += "` to `";5314expected += show_char(to_);5315expected += "`";5316return expected;5317}53185319TOML11_INLINE scanner_base* character_in_range::clone() const5320{5321return new character_in_range(*this);5322}53235324TOML11_INLINE std::string character_in_range::name() const5325{5326return "character_in_range{" + show_char(from_) + "," + show_char(to_) + "}";5327}53285329// ----------------------------------------------------------------------------5330// literal53315332TOML11_INLINE region literal::scan(location& loc) const5333{5334const auto first = loc;5335for(std::size_t i=0; i<size_; ++i)5336{5337if(loc.eof() || char_type(value_[i]) != loc.current())5338{5339loc = first;5340return region{};5341}5342loc.advance(1);5343}5344return region(first, loc);5345}53465347TOML11_INLINE std::string literal::expected_chars(location&) const5348{5349return std::string(value_);5350}53515352TOML11_INLINE scanner_base* literal::clone() const5353{5354return new literal(*this);5355}53565357TOML11_INLINE std::string literal::name() const5358{5359return std::string("literal{") + std::string(value_, size_) + "}";5360}53615362// ----------------------------------------------------------------------------5363// sequence53645365TOML11_INLINE region sequence::scan(location& loc) const5366{5367const auto first = loc;5368for(const auto& other : others_)5369{5370const auto reg = other.scan(loc);5371if( ! reg.is_ok())5372{5373loc = first;5374return region{};5375}5376}5377return region(first, loc);5378}53795380TOML11_INLINE std::string sequence::expected_chars(location& loc) const5381{5382const auto first = loc;5383for(const auto& other : others_)5384{5385const auto reg = other.scan(loc);5386if( ! reg.is_ok())5387{5388return other.expected_chars(loc);5389}5390}5391assert(false);5392return ""; // XXX5393}53945395TOML11_INLINE scanner_base* sequence::clone() const5396{5397return new sequence(*this);5398}53995400TOML11_INLINE std::string sequence::name() const5401{5402std::string n("sequence{");5403for(const auto& other : others_)5404{5405n += other.name();5406n += ", ";5407}5408if( ! this->others_.empty())5409{5410n.pop_back();5411n.pop_back();5412}5413n += "}";5414return n;5415}54165417// ----------------------------------------------------------------------------5418// either54195420TOML11_INLINE region either::scan(location& loc) const5421{5422for(const auto& other : others_)5423{5424const auto reg = other.scan(loc);5425if(reg.is_ok())5426{5427return reg;5428}5429}5430return region{};5431}54325433TOML11_INLINE std::string either::expected_chars(location& loc) const5434{5435assert( ! others_.empty());54365437std::string expected = others_.at(0).expected_chars(loc);5438if(others_.size() == 2)5439{5440expected += " or ";5441expected += others_.at(1).expected_chars(loc);5442}5443else5444{5445for(std::size_t i=1; i<others_.size(); ++i)5446{5447expected += ", ";5448if(i + 1 == others_.size())5449{5450expected += "or ";5451}5452expected += others_.at(i).expected_chars(loc);5453}5454}5455return expected;5456}54575458TOML11_INLINE scanner_base* either::clone() const5459{5460return new either(*this);5461}54625463TOML11_INLINE std::string either::name() const5464{5465std::string n("either{");5466for(const auto& other : others_)5467{5468n += other.name();5469n += ", ";5470}5471if( ! this->others_.empty())5472{5473n.pop_back();5474n.pop_back();5475}5476n += "}";5477return n;5478}54795480// ----------------------------------------------------------------------------5481// repeat_exact54825483TOML11_INLINE region repeat_exact::scan(location& loc) const5484{5485const auto first = loc;5486for(std::size_t i=0; i<length_; ++i)5487{5488const auto reg = other_.scan(loc);5489if( ! reg.is_ok())5490{5491loc = first;5492return region{};5493}5494}5495return region(first, loc);5496}54975498TOML11_INLINE std::string repeat_exact::expected_chars(location& loc) const5499{5500for(std::size_t i=0; i<length_; ++i)5501{5502const auto reg = other_.scan(loc);5503if( ! reg.is_ok())5504{5505return other_.expected_chars(loc);5506}5507}5508assert(false);5509return "";5510}55115512TOML11_INLINE scanner_base* repeat_exact::clone() const5513{5514return new repeat_exact(*this);5515}55165517TOML11_INLINE std::string repeat_exact::name() const5518{5519return "repeat_exact{" + std::to_string(length_) + ", " + other_.name() + "}";5520}55215522// ----------------------------------------------------------------------------5523// repeat_at_least55245525TOML11_INLINE region repeat_at_least::scan(location& loc) const5526{5527const auto first = loc;5528for(std::size_t i=0; i<length_; ++i)5529{5530const auto reg = other_.scan(loc);5531if( ! reg.is_ok())5532{5533loc = first;5534return region{};5535}5536}5537while( ! loc.eof())5538{5539const auto checkpoint = loc;5540const auto reg = other_.scan(loc);5541if( ! reg.is_ok())5542{5543loc = checkpoint;5544return region(first, loc);5545}5546}5547return region(first, loc);5548}55495550TOML11_INLINE std::string repeat_at_least::expected_chars(location& loc) const5551{5552for(std::size_t i=0; i<length_; ++i)5553{5554const auto reg = other_.scan(loc);5555if( ! reg.is_ok())5556{5557return other_.expected_chars(loc);5558}5559}5560assert(false);5561return "";5562}55635564TOML11_INLINE scanner_base* repeat_at_least::clone() const5565{5566return new repeat_at_least(*this);5567}55685569TOML11_INLINE std::string repeat_at_least::name() const5570{5571return "repeat_at_least{" + std::to_string(length_) + ", " + other_.name() + "}";5572}55735574// ----------------------------------------------------------------------------5575// maybe55765577TOML11_INLINE region maybe::scan(location& loc) const5578{5579const auto first = loc;5580const auto reg = other_.scan(loc);5581if( ! reg.is_ok())5582{5583loc = first;5584}5585return region(first, loc);5586}55875588TOML11_INLINE std::string maybe::expected_chars(location&) const5589{5590return "";5591}55925593TOML11_INLINE scanner_base* maybe::clone() const5594{5595return new maybe(*this);5596}55975598TOML11_INLINE std::string maybe::name() const5599{5600return "maybe{" + other_.name() + "}";5601}56025603} // detail5604} // TOML11_INLINE_VERSION_NAMESPACE5605} // toml5606#endif // TOML11_SCANNER_IMPL_HPP5607#endif56085609#endif // TOML11_SCANNER_HPP5610#ifndef TOML11_SYNTAX_HPP5611#define TOML11_SYNTAX_HPP56125613#ifndef TOML11_SYNTAX_FWD_HPP5614#define TOML11_SYNTAX_FWD_HPP561556165617namespace toml5618{5619inline namespace TOML11_INLINE_VERSION_NAMESPACE5620{5621namespace detail5622{5623namespace syntax5624{56255626using char_type = location::char_type;56275628// ===========================================================================5629// UTF-856305631// avoid redundant representation and out-of-unicode sequence56325633character_in_range const& utf8_1byte (const spec&);5634sequence const& utf8_2bytes(const spec&);5635sequence const& utf8_3bytes(const spec&);5636sequence const& utf8_4bytes(const spec&);56375638class non_ascii final : public scanner_base5639{5640public:56415642using char_type = location::char_type;56435644public:56455646explicit non_ascii(const spec& s) noexcept5647: utf8_2B_(utf8_2bytes(s)),5648utf8_3B_(utf8_3bytes(s)),5649utf8_4B_(utf8_4bytes(s))5650{}5651~non_ascii() override = default;56525653region scan(location& loc) const override5654{5655{5656const auto reg = utf8_2B_.scan(loc);5657if(reg.is_ok()) {return reg;}5658}5659{5660const auto reg = utf8_3B_.scan(loc);5661if(reg.is_ok()) {return reg;}5662}5663{5664const auto reg = utf8_4B_.scan(loc);5665if(reg.is_ok()) {return reg;}5666}5667return region{};5668}56695670std::string expected_chars(location&) const override5671{5672return "non-ascii utf-8 bytes";5673}56745675scanner_base* clone() const override5676{5677return new non_ascii(*this);5678}56795680std::string name() const override5681{5682return "non_ascii";5683}56845685private:5686sequence utf8_2B_;5687sequence utf8_3B_;5688sequence utf8_4B_;5689};56905691// ===========================================================================5692// Whitespace56935694character_either const& wschar(const spec&);56955696repeat_at_least const& ws(const spec& s);56975698// ===========================================================================5699// Newline57005701either const& newline(const spec&);57025703// ===========================================================================5704// Comments57055706either const& allowed_comment_char(const spec& s);57075708// XXX Note that it does not take newline5709sequence const& comment(const spec& s);57105711// ===========================================================================5712// Boolean57135714either const& boolean(const spec&);57155716// ===========================================================================5717// Integer57185719class digit final : public scanner_base5720{5721public:57225723using char_type = location::char_type;57245725public:57265727explicit digit(const spec&) noexcept5728: scanner_(char_type('0'), char_type('9'))5729{}573057315732~digit() override = default;57335734region scan(location& loc) const override5735{5736return scanner_.scan(loc);5737}57385739std::string expected_chars(location&) const override5740{5741return "digit [0-9]";5742}57435744scanner_base* clone() const override5745{5746return new digit(*this);5747}57485749std::string name() const override5750{5751return "digit";5752}57535754private:57555756character_in_range scanner_;5757};57585759class alpha final : public scanner_base5760{5761public:57625763using char_type = location::char_type;57645765public:57665767explicit alpha(const spec&) noexcept5768: lowercase_(char_type('a'), char_type('z')),5769uppercase_(char_type('A'), char_type('Z'))5770{}5771~alpha() override = default;57725773region scan(location& loc) const override5774{5775{5776const auto reg = lowercase_.scan(loc);5777if(reg.is_ok()) {return reg;}5778}5779{5780const auto reg = uppercase_.scan(loc);5781if(reg.is_ok()) {return reg;}5782}5783return region{};5784}57855786std::string expected_chars(location&) const override5787{5788return "alpha [a-zA-Z]";5789}57905791scanner_base* clone() const override5792{5793return new alpha(*this);5794}57955796std::string name() const override5797{5798return "alpha";5799}58005801private:58025803character_in_range lowercase_;5804character_in_range uppercase_;5805};58065807class hexdig final : public scanner_base5808{5809public:58105811using char_type = location::char_type;58125813public:58145815explicit hexdig(const spec& s) noexcept5816: digit_(s),5817lowercase_(char_type('a'), char_type('f')),5818uppercase_(char_type('A'), char_type('F'))5819{}5820~hexdig() override = default;58215822region scan(location& loc) const override5823{5824{5825const auto reg = digit_.scan(loc);5826if(reg.is_ok()) {return reg;}5827}5828{5829const auto reg = lowercase_.scan(loc);5830if(reg.is_ok()) {return reg;}5831}5832{5833const auto reg = uppercase_.scan(loc);5834if(reg.is_ok()) {return reg;}5835}5836return region{};5837}58385839std::string expected_chars(location&) const override5840{5841return "hex [0-9a-fA-F]";5842}58435844scanner_base* clone() const override5845{5846return new hexdig(*this);5847}58485849std::string name() const override5850{5851return "hexdig";5852}58535854private:58555856digit digit_;5857character_in_range lowercase_;5858character_in_range uppercase_;5859};58605861sequence const& num_suffix(const spec& s);58625863sequence const& dec_int(const spec& s);5864sequence const& hex_int(const spec& s);5865sequence const& oct_int(const spec&);5866sequence const& bin_int(const spec&);5867either const& integer(const spec& s);58685869// ===========================================================================5870// Floating58715872sequence const& zero_prefixable_int(const spec& s);5873sequence const& fractional_part(const spec& s);5874sequence const& exponent_part(const spec& s);5875sequence const& hex_floating(const spec& s);5876either const& floating(const spec& s);58775878// ===========================================================================5879// Datetime58805881sequence const& local_date(const spec& s);5882sequence const& local_time(const spec& s);5883either const& time_offset(const spec& s);5884sequence const& full_time(const spec& s);5885character_either const& time_delim(const spec&);5886sequence const& local_datetime(const spec& s);5887sequence const& offset_datetime(const spec& s);58885889// ===========================================================================5890// String58915892sequence const& escaped_x2(const spec& s);5893sequence const& escaped_u4(const spec& s);5894sequence const& escaped_U8(const spec& s);58955896sequence const& escaped (const spec& s);5897either const& basic_char (const spec& s);5898sequence const& basic_string(const spec& s);58995900// ---------------------------------------------------------------------------5901// multiline string59025903sequence const& escaped_newline(const spec& s);5904sequence const& ml_basic_string(const spec& s);59055906// ---------------------------------------------------------------------------5907// literal string59085909either const& literal_char(const spec& s);5910sequence const& literal_string(const spec& s);5911sequence const& ml_literal_string(const spec& s);5912either const& string(const spec& s);59135914// ===========================================================================5915// Keys59165917// to keep `expected_chars` simple5918class non_ascii_key_char final : public scanner_base5919{5920public:59215922using char_type = location::char_type;59235924private:59255926using in_range = character_in_range; // make definition short59275928public:59295930explicit non_ascii_key_char(const spec& s) noexcept;5931~non_ascii_key_char() override = default;59325933region scan(location& loc) const override;59345935std::string expected_chars(location&) const override5936{5937return "bare key non-ASCII script";5938}59395940scanner_base* clone() const override5941{5942return new non_ascii_key_char(*this);5943}59445945std::string name() const override5946{5947return "non-ASCII bare key";5948}59495950private:59515952std::uint32_t read_utf8(location& loc) const;5953};595459555956repeat_at_least const& unquoted_key(const spec& s);5957either const& quoted_key(const spec& s);5958either const& simple_key(const spec& s);5959sequence const& dot_sep(const spec& s);5960sequence const& dotted_key(const spec& s);59615962class key final : public scanner_base5963{5964public:59655966using char_type = location::char_type;59675968public:59695970explicit key(const spec& s) noexcept5971: dotted_(dotted_key(s)),5972simple_(simple_key(s))5973{}5974~key() override = default;59755976region scan(location& loc) const override5977{5978{5979const auto reg = dotted_.scan(loc);5980if(reg.is_ok()) {return reg;}5981}5982{5983const auto reg = simple_.scan(loc);5984if(reg.is_ok()) {return reg;}5985}5986return region{};5987}59885989std::string expected_chars(location&) const override5990{5991return "basic key([a-zA-Z0-9_-]) or quoted key(\" or ')";5992}59935994scanner_base* clone() const override5995{5996return new key(*this);5997}59985999std::string name() const override6000{6001return "key";6002}60036004private:60056006sequence dotted_;6007either simple_;6008};60096010sequence const& keyval_sep(const spec& s);60116012// ===========================================================================6013// Table key60146015sequence const& std_table(const spec& s);60166017sequence const& array_table(const spec& s);60186019// ===========================================================================6020// extension: null60216022literal const& null_value(const spec&);60236024} // namespace syntax6025} // namespace detail6026} // TOML11_INLINE_VERSION_NAMESPACE6027} // namespace toml6028#endif // TOML11_SYNTAX_FWD_HPP60296030#if ! defined(TOML11_COMPILE_SOURCES)6031#ifndef TOML11_SYNTAX_IMPL_HPP6032#define TOML11_SYNTAX_IMPL_HPP603360346035namespace toml6036{6037inline namespace TOML11_INLINE_VERSION_NAMESPACE6038{6039namespace detail6040{6041namespace syntax6042{60436044using char_type = location::char_type;60456046template<typename F>6047struct syntax_cache6048{6049using value_type = cxx::return_type_of_t<F, const spec&>;6050static_assert(std::is_base_of<scanner_base, value_type>::value, "");60516052explicit syntax_cache(F f)6053: func_(std::move(f)), cache_(cxx::make_nullopt())6054{}60556056value_type const& at(const spec& s)6057{6058if( ! this->cache_.has_value() || this->cache_.value().first != s)6059{6060this->cache_ = std::make_pair(s, func_(s));6061}6062return this->cache_.value().second;6063}60646065private:6066F func_;6067cxx::optional<std::pair<spec, value_type>> cache_;6068};60696070template<typename F>6071syntax_cache<cxx::remove_cvref_t<F>> make_cache(F&& f)6072{6073return syntax_cache<cxx::remove_cvref_t<F>>(std::forward<F>(f));6074}60756076// ===========================================================================6077// UTF-860786079// avoid redundant representation and out-of-unicode sequence60806081TOML11_INLINE character_in_range const& utf8_1byte(const spec&)6082{6083static thread_local character_in_range cache(0x00, 0x7F);6084return cache;6085}60866087TOML11_INLINE sequence const& utf8_2bytes(const spec&)6088{6089static thread_local sequence cache(6090character_in_range(0xC2, 0xDF),6091character_in_range(0x80, 0xBF));6092return cache;6093}60946095TOML11_INLINE sequence const& utf8_3bytes(const spec&)6096{6097static thread_local sequence cache(/*1~2 bytes = */either(6098sequence(character (0xE0), character_in_range(0xA0, 0xBF)),6099sequence(character_in_range(0xE1, 0xEC), character_in_range(0x80, 0xBF)),6100sequence(character (0xED), character_in_range(0x80, 0x9F)),6101sequence(character_in_range(0xEE, 0xEF), character_in_range(0x80, 0xBF))6102), /*3rd byte = */ character_in_range(0x80, 0xBF));61036104return cache;6105}61066107TOML11_INLINE sequence const& utf8_4bytes(const spec&)6108{6109static thread_local sequence cache(/*1~2 bytes = */either(6110sequence(character (0xF0), character_in_range(0x90, 0xBF)),6111sequence(character_in_range(0xF1, 0xF3), character_in_range(0x80, 0xBF)),6112sequence(character (0xF4), character_in_range(0x80, 0x8F))6113), character_in_range(0x80, 0xBF), character_in_range(0x80, 0xBF));61146115return cache;6116}61176118// ===========================================================================6119// Whitespace61206121TOML11_INLINE character_either const& wschar(const spec&)6122{6123static thread_local character_either cache(" \t");6124return cache;6125}61266127TOML11_INLINE repeat_at_least const& ws(const spec& sp)6128{6129static thread_local auto cache = make_cache([](const spec& s){6130return repeat_at_least(0, wschar(s));6131});6132return cache.at(sp);6133}61346135// ===========================================================================6136// Newline61376138TOML11_INLINE either const& newline(const spec&)6139{6140static thread_local either cache(character(char_type('\n')), literal("\r\n"));6141return cache;6142}61436144// ===========================================================================6145// Comments61466147TOML11_INLINE either const& allowed_comment_char(const spec& sp)6148{6149static thread_local auto cache = make_cache([](const spec& s){6150if(s.ext_allow_control_characters_in_comments)6151{6152return either(6153character_in_range(0x01, 0x09),6154character_in_range(0x0E, 0x7F),6155non_ascii(s)6156);6157}6158else6159{6160return either(6161character(0x09),6162character_in_range(0x20, 0x7E),6163non_ascii(s)6164);6165}6166});6167return cache.at(sp);6168}61696170// XXX Note that it does not take newline6171TOML11_INLINE sequence const& comment(const spec& sp)6172{6173static thread_local auto cache = make_cache([](const spec& s){6174return sequence(character(char_type('#')),6175repeat_at_least(0, allowed_comment_char(s)));6176});6177return cache.at(sp);6178}61796180// ===========================================================================6181// Boolean61826183TOML11_INLINE either const& boolean(const spec&)6184{6185static thread_local either cache(literal("true"), literal("false"));6186return cache;6187}61886189// ===========================================================================6190// Integer61916192// non-digit-graph = ([a-zA-Z]|unicode mb char)6193// graph = ([a-zA-Z0-9]|unicode mb char)6194// suffix = _ non-digit-graph (graph | _graph)6195TOML11_INLINE sequence const& num_suffix(const spec& sp)6196{6197static thread_local auto cache = make_cache([](const spec& s) {6198const auto non_digit_graph = [&s]() {6199return either(6200alpha(s),6201non_ascii(s)6202);6203};6204const auto graph = [&s]() {6205return either(6206alpha(s),6207digit(s),6208non_ascii(s)6209);6210};62116212return sequence(6213character(char_type('_')),6214non_digit_graph(),6215repeat_at_least(0,6216either(6217sequence(character(char_type('_')), graph()),6218graph()6219)6220)6221);6222});6223return cache.at(sp);6224}62256226TOML11_INLINE sequence const& dec_int(const spec& sp)6227{6228static thread_local auto cache = make_cache([](const spec& s) {6229const auto digit19 = []() {6230return character_in_range(char_type('1'), char_type('9'));6231};6232return sequence(6233maybe(character_either("+-")),6234either(6235sequence(6236digit19(),6237repeat_at_least(1,6238either(6239digit(s),6240sequence(character(char_type('_')), digit(s))6241)6242)6243),6244digit(s)6245)6246);6247});6248return cache.at(sp);6249}62506251TOML11_INLINE sequence const& hex_int(const spec& sp)6252{6253static thread_local auto cache = make_cache([](const spec& s) {6254return sequence(6255literal("0x"),6256hexdig(s),6257repeat_at_least(0,6258either(6259hexdig(s),6260sequence(character(char_type('_')), hexdig(s))6261)6262)6263);6264});6265return cache.at(sp);6266}62676268TOML11_INLINE sequence const& oct_int(const spec& s)6269{6270static thread_local auto cache = make_cache([](const spec&) {6271const auto digit07 = []() {6272return character_in_range(char_type('0'), char_type('7'));6273};6274return sequence(6275literal("0o"),6276digit07(),6277repeat_at_least(0,6278either(6279digit07(),6280sequence(character(char_type('_')), digit07())6281)6282)6283);6284});6285return cache.at(s);6286}62876288TOML11_INLINE sequence const& bin_int(const spec& s)6289{6290static thread_local auto cache = make_cache([](const spec&) {6291const auto digit01 = []() {6292return character_either("01");6293};6294return sequence(6295literal("0b"),6296digit01(),6297repeat_at_least(0,6298either(6299digit01(),6300sequence(character(char_type('_')), digit01())6301)6302)6303);6304});6305return cache.at(s);6306}63076308TOML11_INLINE either const& integer(const spec& sp)6309{6310static thread_local auto cache = make_cache([](const spec& s) {6311return either(6312hex_int(s),6313oct_int(s),6314bin_int(s),6315dec_int(s)6316);6317});6318return cache.at(sp);6319}632063216322// ===========================================================================6323// Floating63246325TOML11_INLINE sequence const& zero_prefixable_int(const spec& sp)6326{6327static thread_local auto cache = make_cache([](const spec& s) {6328return sequence(6329digit(s),6330repeat_at_least(0,6331either(6332digit(s),6333sequence(character('_'), digit(s))6334)6335)6336);6337});6338return cache.at(sp);6339}63406341TOML11_INLINE sequence const& fractional_part(const spec& sp)6342{6343static thread_local auto cache = make_cache([](const spec& s) {6344return sequence(6345character('.'),6346zero_prefixable_int(s)6347);6348});6349return cache.at(sp);6350}63516352TOML11_INLINE sequence const& exponent_part(const spec& sp)6353{6354static thread_local auto cache = make_cache([](const spec& s) {6355return sequence(6356character_either("eE"),6357maybe(character_either("+-")),6358zero_prefixable_int(s)6359);6360});6361return cache.at(sp);6362}63636364TOML11_INLINE sequence const& hex_floating(const spec& sp)6365{6366static thread_local auto cache = make_cache([](const spec& s) {6367// C99 hexfloat (%a)6368// [+-]? 0x ( [0-9a-fA-F]*\.[0-9a-fA-F]+ | [0-9a-fA-F]+\.? ) [pP] [+-]? [0-9]+63696370// - 0x(int).(frac)p[+-](int)6371// - 0x(int).p[+-](int)6372// - 0x.(frac)p[+-](int)6373// - 0x(int)p[+-](int)63746375return sequence(6376maybe(character_either("+-")),6377character('0'),6378character_either("xX"),6379either(6380sequence(6381repeat_at_least(0, hexdig(s)),6382character('.'),6383repeat_at_least(1, hexdig(s))6384),6385sequence(6386repeat_at_least(1, hexdig(s)),6387maybe(character('.'))6388)6389),6390character_either("pP"),6391maybe(character_either("+-")),6392repeat_at_least(1, character_in_range('0', '9'))6393);6394});6395return cache.at(sp);6396}63976398TOML11_INLINE either const& floating(const spec& sp)6399{6400static thread_local auto cache = make_cache([](const spec& s) {6401return either(6402sequence(6403dec_int(s),6404either(6405exponent_part(s),6406sequence(fractional_part(s), maybe(exponent_part(s)))6407)6408),6409sequence(6410maybe(character_either("+-")),6411either(literal("inf"), literal("nan"))6412)6413);6414});6415return cache.at(sp);6416}64176418// ===========================================================================6419// Datetime64206421TOML11_INLINE sequence const& local_date(const spec& sp)6422{6423static thread_local auto cache = make_cache([](const spec& s) {6424return sequence(6425repeat_exact(4, digit(s)),6426character('-'),6427repeat_exact(2, digit(s)),6428character('-'),6429repeat_exact(2, digit(s))6430);6431});6432return cache.at(sp);6433}6434TOML11_INLINE sequence const& local_time(const spec& sp)6435{6436static thread_local auto cache = make_cache([](const spec& s) {6437if(s.v1_1_0_make_seconds_optional)6438{6439return sequence(6440repeat_exact(2, digit(s)),6441character(':'),6442repeat_exact(2, digit(s)),6443maybe(sequence(6444character(':'),6445repeat_exact(2, digit(s)),6446maybe(sequence(character('.'), repeat_at_least(1, digit(s))))6447)));6448}6449else6450{6451return sequence(6452repeat_exact(2, digit(s)),6453character(':'),6454repeat_exact(2, digit(s)),6455character(':'),6456repeat_exact(2, digit(s)),6457maybe(sequence(character('.'), repeat_at_least(1, digit(s))))6458);6459}6460});6461return cache.at(sp);6462}6463TOML11_INLINE either const& time_offset(const spec& sp)6464{6465static thread_local auto cache = make_cache([](const spec& s) {6466return either(6467character_either("zZ"),6468sequence(character_either("+-"),6469repeat_exact(2, digit(s)),6470character(':'),6471repeat_exact(2, digit(s))6472)6473);6474});6475return cache.at(sp);6476}6477TOML11_INLINE sequence const& full_time(const spec& sp)6478{6479static thread_local auto cache = make_cache([](const spec& s) {6480return sequence(local_time(s), time_offset(s));6481});6482return cache.at(sp);6483}6484TOML11_INLINE character_either const& time_delim(const spec& sp)6485{6486static thread_local auto cache = make_cache([](const spec&) {6487return character_either("Tt ");6488});6489return cache.at(sp);6490}6491TOML11_INLINE sequence const& local_datetime(const spec& sp)6492{6493static thread_local auto cache = make_cache([](const spec& s) {6494return sequence(local_date(s), time_delim(s), local_time(s));6495});6496return cache.at(sp);6497}6498TOML11_INLINE sequence const& offset_datetime(const spec& sp)6499{6500static thread_local auto cache = make_cache([](const spec& s) {6501return sequence(local_date(s), time_delim(s), full_time(s));6502});6503return cache.at(sp);6504}65056506// ===========================================================================6507// String65086509TOML11_INLINE sequence const& escaped_x2(const spec& sp)6510{6511static thread_local auto cache = make_cache([](const spec& s) {6512return sequence(character('x'), repeat_exact(2, hexdig(s)));6513});6514return cache.at(sp);6515}6516TOML11_INLINE sequence const& escaped_u4(const spec& sp)6517{6518static thread_local auto cache = make_cache([](const spec& s) {6519return sequence(character('u'), repeat_exact(4, hexdig(s)));6520});6521return cache.at(sp);6522}6523TOML11_INLINE sequence const& escaped_U8(const spec& sp)6524{6525static thread_local auto cache = make_cache([](const spec& s) {6526return sequence(character('U'), repeat_exact(8, hexdig(s)));6527});6528return cache.at(sp);6529}65306531TOML11_INLINE sequence const& escaped(const spec& sp)6532{6533static thread_local auto cache = make_cache([](const spec& s) {6534const auto escape_char = [&s] {6535if(s.v1_1_0_add_escape_sequence_e)6536{6537return character_either("\"\\bfnrte");6538}6539else6540{6541return character_either("\"\\bfnrt");6542}6543};65446545const auto escape_seq = [&s, &escape_char] {6546if(s.v1_1_0_add_escape_sequence_x)6547{6548return either(6549escape_char(),6550escaped_u4(s),6551escaped_U8(s),6552escaped_x2(s)6553);6554}6555else6556{6557return either(6558escape_char(),6559escaped_u4(s),6560escaped_U8(s)6561);6562}6563};65646565return sequence(character('\\'), escape_seq());6566});6567return cache.at(sp);6568}65696570TOML11_INLINE either const& basic_char(const spec& sp)6571{6572static thread_local auto cache = make_cache([](const spec& s) {6573const auto basic_unescaped = [&s]() {6574return either(6575wschar(s),6576character(0x21), // 22 is "6577character_in_range(0x23, 0x5B), // 5C is backslash6578character_in_range(0x5D, 0x7E), // 7F is DEL6579non_ascii(s)6580);6581};6582return either(basic_unescaped(), escaped(s));6583});6584return cache.at(sp);6585}65866587TOML11_INLINE sequence const& basic_string(const spec& sp)6588{6589static thread_local auto cache = make_cache([](const spec& s) {6590return sequence(6591character('"'),6592repeat_at_least(0, basic_char(s)),6593character('"')6594);6595});6596return cache.at(sp);6597}65986599// ---------------------------------------------------------------------------6600// multiline string66016602TOML11_INLINE sequence const& escaped_newline(const spec& sp)6603{6604static thread_local auto cache = make_cache([](const spec& s) {6605return sequence(6606character('\\'), ws(s), newline(s),6607repeat_at_least(0, either(wschar(s), newline(s)))6608);6609});6610return cache.at(sp);6611}66126613TOML11_INLINE sequence const& ml_basic_string(const spec& sp)6614{6615static thread_local auto cache = make_cache([](const spec& s) {6616const auto mlb_content = [&s]() {6617return either(basic_char(s), newline(s), escaped_newline(s));6618};6619const auto mlb_quotes = []() {6620return either(literal("\"\""), character('\"'));6621};66226623return sequence(6624literal("\"\"\""),6625maybe(newline(s)),6626repeat_at_least(0, mlb_content()),6627repeat_at_least(0,6628sequence(6629mlb_quotes(),6630repeat_at_least(1, mlb_content())6631)6632),6633// XXX """ and mlb_quotes are intentionally reordered to avoid6634// unexpected match of mlb_quotes6635literal("\"\"\""),6636maybe(mlb_quotes())6637);6638});6639return cache.at(sp);6640}66416642// ---------------------------------------------------------------------------6643// literal string66446645TOML11_INLINE either const& literal_char(const spec& sp)6646{6647static thread_local auto cache = make_cache([](const spec& s) {6648return either(6649character (0x09),6650character_in_range(0x20, 0x26),6651character_in_range(0x28, 0x7E),6652non_ascii(s)6653);6654});6655return cache.at(sp);6656}66576658TOML11_INLINE sequence const& literal_string(const spec& sp)6659{6660static thread_local auto cache = make_cache([](const spec& s) {6661return sequence(6662character('\''),6663repeat_at_least(0, literal_char(s)),6664character('\'')6665);6666});6667return cache.at(sp);6668}66696670TOML11_INLINE sequence const& ml_literal_string(const spec& sp)6671{6672static thread_local auto cache = make_cache([](const spec& s) {6673const auto mll_quotes = []() {6674return either(literal("''"), character('\''));6675};6676const auto mll_content = [&s]() {6677return either(literal_char(s), newline(s));6678};66796680return sequence(6681literal("'''"),6682maybe(newline(s)),6683repeat_at_least(0, mll_content()),6684repeat_at_least(0, sequence(6685mll_quotes(),6686repeat_at_least(1, mll_content())6687)6688),6689literal("'''"),6690maybe(mll_quotes())6691// XXX ''' and mll_quotes are intentionally reordered to avoid6692// unexpected match of mll_quotes6693);6694});6695return cache.at(sp);6696}66976698TOML11_INLINE either const& string(const spec& sp)6699{6700static thread_local auto cache = make_cache([](const spec& s) {6701return either(6702ml_basic_string(s),6703ml_literal_string(s),6704basic_string(s),6705literal_string(s)6706);6707});6708return cache.at(sp);6709}67106711// ===========================================================================6712// Keys67136714// to keep `expected_chars` simple6715TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept6716{6717assert(s.ext_allow_non_english_in_bare_keys);6718(void)s; // for NDEBUG6719}67206721TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const6722{6723// U+0000 ... U+0079 ; 0xxx_xxxx6724// U+0080 ... U+07FF ; 110y_yyyx 10xx_xxxx;6725// U+0800 ... U+FFFF ; 1110_yyyy 10yx_xxxx 10xx_xxxx6726// U+010000 ... U+10FFFF; 1111_0yyy 10yy_xxxx 10xx_xxxx 10xx_xxxx67276728const unsigned char b1 = loc.current(); loc.advance(1);6729if(b1 < 0x80)6730{6731return static_cast<std::uint32_t>(b1);6732}6733else if((b1 >> 5) == 6) // 0b110 == 66734{6735const auto b2 = loc.current(); loc.advance(1);67366737const std::uint32_t c1 = b1 & ((1 << 5) - 1);6738const std::uint32_t c2 = b2 & ((1 << 6) - 1);6739const std::uint32_t codep = (c1 << 6) + c2;67406741if(codep < 0x80)6742{6743return 0xFFFFFFFF;6744}6745return codep;6746}6747else if((b1 >> 4) == 14) // 0b1110 == 146748{6749const auto b2 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;}6750const auto b3 = loc.current(); loc.advance(1);67516752const std::uint32_t c1 = b1 & ((1 << 4) - 1);6753const std::uint32_t c2 = b2 & ((1 << 6) - 1);6754const std::uint32_t c3 = b3 & ((1 << 6) - 1);67556756const std::uint32_t codep = (c1 << 12) + (c2 << 6) + c3;6757if(codep < 0x800)6758{6759return 0xFFFFFFFF;6760}6761return codep;6762}6763else if((b1 >> 3) == 30) // 0b11110 == 306764{6765const auto b2 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;}6766const auto b3 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;}6767const auto b4 = loc.current(); loc.advance(1);67686769const std::uint32_t c1 = b1 & ((1 << 3) - 1);6770const std::uint32_t c2 = b2 & ((1 << 6) - 1);6771const std::uint32_t c3 = b3 & ((1 << 6) - 1);6772const std::uint32_t c4 = b4 & ((1 << 6) - 1);6773const std::uint32_t codep = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4;67746775if(codep < 0x10000)6776{6777return 0xFFFFFFFF;6778}6779return codep;6780}6781else // not a Unicode codepoint in UTF-86782{6783return 0xFFFFFFFF;6784}6785}67866787TOML11_INLINE region non_ascii_key_char::scan(location& loc) const6788{6789if(loc.eof()) {return region{};}67906791const auto first = loc;67926793const auto cp = read_utf8(loc);67946795if(cp == 0xFFFFFFFF)6796{6797return region{};6798}67996800// ALPHA / DIGIT / %x2D / %x5F ; a-z A-Z 0-9 - _6801// / %xB2 / %xB3 / %xB9 / %xBC-BE ; superscript digits, fractions6802// / %xC0-D6 / %xD8-F6 / %xF8-37D ; non-symbol chars in Latin block6803// / %x37F-1FFF ; exclude GREEK QUESTION MARK, which is basically a semi-colon6804// / %x200C-200D / %x203F-2040 ; from General Punctuation Block, include the two tie symbols and ZWNJ, ZWJ6805// / %x2070-218F / %x2460-24FF ; include super-/subscripts, letterlike/numberlike forms, enclosed alphanumerics6806// / %x2C00-2FEF / %x3001-D7FF ; skip arrows, math, box drawing etc, skip 2FF0-3000 ideographic up/down markers and spaces6807// / %xF900-FDCF / %xFDF0-FFFD ; skip D800-DFFF surrogate block, E000-F8FF Private Use area, FDD0-FDEF intended for process-internal use (unicode)6808// / %x10000-EFFFF ; all chars outside BMP range, excluding Private Use planes (F0000-10FFFF)68096810if(cp == 0xB2 || cp == 0xB3 || cp == 0xB9 || (0xBC <= cp && cp <= 0xBE) ||6811(0xC0 <= cp && cp <= 0xD6 ) || (0xD8 <= cp && cp <= 0xF6) || (0xF8 <= cp && cp <= 0x37D) ||6812(0x37F <= cp && cp <= 0x1FFF) ||6813(0x200C <= cp && cp <= 0x200D) || (0x203F <= cp && cp <= 0x2040) ||6814(0x2070 <= cp && cp <= 0x218F) || (0x2460 <= cp && cp <= 0x24FF) ||6815(0x2C00 <= cp && cp <= 0x2FEF) || (0x3001 <= cp && cp <= 0xD7FF) ||6816(0xF900 <= cp && cp <= 0xFDCF) || (0xFDF0 <= cp && cp <= 0xFFFD) ||6817(0x10000 <= cp && cp <= 0xEFFFF) )6818{6819return region(first, loc);6820}6821loc = first;6822return region{};6823}68246825TOML11_INLINE repeat_at_least const& unquoted_key(const spec& sp)6826{6827static thread_local auto cache = make_cache([](const spec& s) {6828const auto keychar = [&s] {6829if(s.ext_allow_non_english_in_bare_keys)6830{6831return either(alpha(s), digit(s), character{0x2D}, character{0x5F},6832non_ascii_key_char(s));6833}6834else6835{6836return either(alpha(s), digit(s), character{0x2D}, character{0x5F});6837}6838};6839return repeat_at_least(1, keychar());6840});6841return cache.at(sp);6842}68436844TOML11_INLINE either const& quoted_key(const spec& sp)6845{6846static thread_local auto cache = make_cache([](const spec& s) {6847return either(basic_string(s), literal_string(s));6848});6849return cache.at(sp);6850}68516852TOML11_INLINE either const& simple_key(const spec& sp)6853{6854static thread_local auto cache = make_cache([](const spec& s) {6855return either(unquoted_key(s), quoted_key(s));6856});6857return cache.at(sp);6858}68596860TOML11_INLINE sequence const& dot_sep(const spec& sp)6861{6862static thread_local auto cache = make_cache([](const spec& s) {6863return sequence(ws(s), character('.'), ws(s));6864});6865return cache.at(sp);6866}68676868TOML11_INLINE sequence const& dotted_key(const spec& sp)6869{6870static thread_local auto cache = make_cache([](const spec& s) {6871return sequence(6872simple_key(s),6873repeat_at_least(1, sequence(dot_sep(s), simple_key(s)))6874);6875});6876return cache.at(sp);6877}68786879TOML11_INLINE sequence const& keyval_sep(const spec& sp)6880{6881static thread_local auto cache = make_cache([](const spec& s) {6882return sequence(ws(s), character('='), ws(s));6883});6884return cache.at(sp);6885}68866887// ===========================================================================6888// Table key68896890TOML11_INLINE sequence const& std_table(const spec& sp)6891{6892static thread_local auto cache = make_cache([](const spec& s) {6893return sequence(character('['), ws(s), key(s), ws(s), character(']'));6894});6895return cache.at(sp);6896}68976898TOML11_INLINE sequence const& array_table(const spec& sp)6899{6900static thread_local auto cache = make_cache([](const spec& s) {6901return sequence(literal("[["), ws(s), key(s), ws(s), literal("]]"));6902});6903return cache.at(sp);6904}69056906// ===========================================================================6907// extension: null69086909TOML11_INLINE literal const& null_value(const spec&)6910{6911static thread_local literal cache("null");6912return cache;6913}69146915} // namespace syntax6916} // namespace detail6917} // TOML11_INLINE_VERSION_NAMESPACE6918} // namespace toml6919#endif // TOML11_SYNTAX_IMPL_HPP6920#endif69216922#endif// TOML11_SYNTAX_HPP6923#ifndef TOML11_COMMENTS_HPP6924#define TOML11_COMMENTS_HPP69256926#ifndef TOML11_COMMENTS_FWD_HPP6927#define TOML11_COMMENTS_FWD_HPP69286929// to use __has_builtin69306931#include <exception>6932#include <initializer_list>6933#include <iterator>6934#include <stdexcept>6935#include <string>6936#include <type_traits>6937#include <utility>6938#include <vector>6939#include <ostream>69406941// This file provides mainly two classes, `preserve_comments` and `discard_comments`.6942// Those two are a container that have the same interface as `std::vector<std::string>`6943// but bahaves in the opposite way. `preserve_comments` is just the same as6944// `std::vector<std::string>` and each `std::string` corresponds to a comment line.6945// Conversely, `discard_comments` discards all the strings and ignores everything6946// assigned in it. `discard_comments` is always empty and you will encounter an6947// error whenever you access to the element.6948namespace toml6949{6950inline namespace TOML11_INLINE_VERSION_NAMESPACE6951{6952class discard_comments; // forward decl69536954class preserve_comments6955{6956public:6957// `container_type` is not provided in discard_comments.6958// do not use this inner-type in a generic code.6959using container_type = std::vector<std::string>;69606961using size_type = container_type::size_type;6962using difference_type = container_type::difference_type;6963using value_type = container_type::value_type;6964using reference = container_type::reference;6965using const_reference = container_type::const_reference;6966using pointer = container_type::pointer;6967using const_pointer = container_type::const_pointer;6968using iterator = container_type::iterator;6969using const_iterator = container_type::const_iterator;6970using reverse_iterator = container_type::reverse_iterator;6971using const_reverse_iterator = container_type::const_reverse_iterator;69726973public:69746975preserve_comments() = default;6976~preserve_comments() = default;6977preserve_comments(preserve_comments const&) = default;6978preserve_comments(preserve_comments &&) = default;6979preserve_comments& operator=(preserve_comments const&) = default;6980preserve_comments& operator=(preserve_comments &&) = default;69816982explicit preserve_comments(const std::vector<std::string>& c): comments(c){}6983explicit preserve_comments(std::vector<std::string>&& c)6984: comments(std::move(c))6985{}6986preserve_comments& operator=(const std::vector<std::string>& c)6987{6988comments = c;6989return *this;6990}6991preserve_comments& operator=(std::vector<std::string>&& c)6992{6993comments = std::move(c);6994return *this;6995}69966997explicit preserve_comments(const discard_comments&) {}69986999explicit preserve_comments(size_type n): comments(n) {}7000preserve_comments(size_type n, const std::string& x): comments(n, x) {}7001preserve_comments(std::initializer_list<std::string> x): comments(x) {}7002template<typename InputIterator>7003preserve_comments(InputIterator first, InputIterator last)7004: comments(first, last)7005{}70067007template<typename InputIterator>7008void assign(InputIterator first, InputIterator last) {comments.assign(first, last);}7009void assign(std::initializer_list<std::string> ini) {comments.assign(ini);}7010void assign(size_type n, const std::string& val) {comments.assign(n, val);}70117012// Related to the issue #97.7013//7014// `std::vector::insert` and `std::vector::erase` in the STL implementation7015// included in GCC 4.8.5 takes `std::vector::iterator` instead of7016// `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5.7017#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)7018# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 408057019# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION7020# endif7021#endif70227023#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION7024iterator insert(iterator p, const std::string& x)7025{7026return comments.insert(p, x);7027}7028iterator insert(iterator p, std::string&& x)7029{7030return comments.insert(p, std::move(x));7031}7032void insert(iterator p, size_type n, const std::string& x)7033{7034return comments.insert(p, n, x);7035}7036template<typename InputIterator>7037void insert(iterator p, InputIterator first, InputIterator last)7038{7039return comments.insert(p, first, last);7040}7041void insert(iterator p, std::initializer_list<std::string> ini)7042{7043return comments.insert(p, ini);7044}70457046template<typename ... Ts>7047iterator emplace(iterator p, Ts&& ... args)7048{7049return comments.emplace(p, std::forward<Ts>(args)...);7050}70517052iterator erase(iterator pos) {return comments.erase(pos);}7053iterator erase(iterator first, iterator last)7054{7055return comments.erase(first, last);7056}7057#else7058iterator insert(const_iterator p, const std::string& x)7059{7060return comments.insert(p, x);7061}7062iterator insert(const_iterator p, std::string&& x)7063{7064return comments.insert(p, std::move(x));7065}7066iterator insert(const_iterator p, size_type n, const std::string& x)7067{7068return comments.insert(p, n, x);7069}7070template<typename InputIterator>7071iterator insert(const_iterator p, InputIterator first, InputIterator last)7072{7073return comments.insert(p, first, last);7074}7075iterator insert(const_iterator p, std::initializer_list<std::string> ini)7076{7077return comments.insert(p, ini);7078}70797080template<typename ... Ts>7081iterator emplace(const_iterator p, Ts&& ... args)7082{7083return comments.emplace(p, std::forward<Ts>(args)...);7084}70857086iterator erase(const_iterator pos) {return comments.erase(pos);}7087iterator erase(const_iterator first, const_iterator last)7088{7089return comments.erase(first, last);7090}7091#endif70927093void swap(preserve_comments& other) {comments.swap(other.comments);}70947095void push_back(const std::string& v) {comments.push_back(v);}7096void push_back(std::string&& v) {comments.push_back(std::move(v));}7097void pop_back() {comments.pop_back();}70987099template<typename ... Ts>7100void emplace_back(Ts&& ... args) {comments.emplace_back(std::forward<Ts>(args)...);}71017102void clear() {comments.clear();}71037104size_type size() const noexcept {return comments.size();}7105size_type max_size() const noexcept {return comments.max_size();}7106size_type capacity() const noexcept {return comments.capacity();}7107bool empty() const noexcept {return comments.empty();}71087109void reserve(size_type n) {comments.reserve(n);}7110void resize(size_type n) {comments.resize(n);}7111void resize(size_type n, const std::string& c) {comments.resize(n, c);}7112void shrink_to_fit() {comments.shrink_to_fit();}71137114reference operator[](const size_type n) noexcept {return comments[n];}7115const_reference operator[](const size_type n) const noexcept {return comments[n];}7116reference at(const size_type n) {return comments.at(n);}7117const_reference at(const size_type n) const {return comments.at(n);}7118reference front() noexcept {return comments.front();}7119const_reference front() const noexcept {return comments.front();}7120reference back() noexcept {return comments.back();}7121const_reference back() const noexcept {return comments.back();}71227123pointer data() noexcept {return comments.data();}7124const_pointer data() const noexcept {return comments.data();}71257126iterator begin() noexcept {return comments.begin();}7127iterator end() noexcept {return comments.end();}7128const_iterator begin() const noexcept {return comments.begin();}7129const_iterator end() const noexcept {return comments.end();}7130const_iterator cbegin() const noexcept {return comments.cbegin();}7131const_iterator cend() const noexcept {return comments.cend();}71327133reverse_iterator rbegin() noexcept {return comments.rbegin();}7134reverse_iterator rend() noexcept {return comments.rend();}7135const_reverse_iterator rbegin() const noexcept {return comments.rbegin();}7136const_reverse_iterator rend() const noexcept {return comments.rend();}7137const_reverse_iterator crbegin() const noexcept {return comments.crbegin();}7138const_reverse_iterator crend() const noexcept {return comments.crend();}71397140friend bool operator==(const preserve_comments&, const preserve_comments&);7141friend bool operator!=(const preserve_comments&, const preserve_comments&);7142friend bool operator< (const preserve_comments&, const preserve_comments&);7143friend bool operator<=(const preserve_comments&, const preserve_comments&);7144friend bool operator> (const preserve_comments&, const preserve_comments&);7145friend bool operator>=(const preserve_comments&, const preserve_comments&);71467147friend void swap(preserve_comments&, std::vector<std::string>&);7148friend void swap(std::vector<std::string>&, preserve_comments&);71497150private:71517152container_type comments;7153};71547155bool operator==(const preserve_comments& lhs, const preserve_comments& rhs);7156bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs);7157bool operator< (const preserve_comments& lhs, const preserve_comments& rhs);7158bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs);7159bool operator> (const preserve_comments& lhs, const preserve_comments& rhs);7160bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs);71617162void swap(preserve_comments& lhs, preserve_comments& rhs);7163void swap(preserve_comments& lhs, std::vector<std::string>& rhs);7164void swap(std::vector<std::string>& lhs, preserve_comments& rhs);71657166std::ostream& operator<<(std::ostream& os, const preserve_comments& com);71677168namespace detail7169{71707171// To provide the same interface with `preserve_comments`, `discard_comments`7172// should have an iterator. But it does not contain anything, so we need to7173// add an iterator that points nothing.7174//7175// It always points null, so DO NOT unwrap this iterator. It always crashes7176// your program.7177template<typename T, bool is_const>7178struct empty_iterator7179{7180using value_type = T;7181using reference_type = typename std::conditional<is_const, T const&, T&>::type;7182using pointer_type = typename std::conditional<is_const, T const*, T*>::type;7183using difference_type = std::ptrdiff_t;7184using iterator_category = std::random_access_iterator_tag;71857186empty_iterator() = default;7187~empty_iterator() = default;7188empty_iterator(empty_iterator const&) = default;7189empty_iterator(empty_iterator &&) = default;7190empty_iterator& operator=(empty_iterator const&) = default;7191empty_iterator& operator=(empty_iterator &&) = default;71927193// DO NOT call these operators.7194reference_type operator*() const noexcept {std::terminate();}7195pointer_type operator->() const noexcept {return nullptr;}7196reference_type operator[](difference_type) const noexcept {return this->operator*();}71977198// These operators do nothing.7199empty_iterator& operator++() noexcept {return *this;}7200empty_iterator operator++(int) noexcept {return *this;}7201empty_iterator& operator--() noexcept {return *this;}7202empty_iterator operator--(int) noexcept {return *this;}72037204empty_iterator& operator+=(difference_type) noexcept {return *this;}7205empty_iterator& operator-=(difference_type) noexcept {return *this;}72067207empty_iterator operator+(difference_type) const noexcept {return *this;}7208empty_iterator operator-(difference_type) const noexcept {return *this;}7209};72107211template<typename T, bool C>7212bool operator==(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}7213template<typename T, bool C>7214bool operator!=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}7215template<typename T, bool C>7216bool operator< (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}7217template<typename T, bool C>7218bool operator<=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}7219template<typename T, bool C>7220bool operator> (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}7221template<typename T, bool C>7222bool operator>=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}72237224template<typename T, bool C>7225typename empty_iterator<T, C>::difference_type7226operator-(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return 0;}72277228template<typename T, bool C>7229empty_iterator<T, C>7230operator+(typename empty_iterator<T, C>::difference_type, const empty_iterator<T, C>& rhs) noexcept {return rhs;}7231template<typename T, bool C>7232empty_iterator<T, C>7233operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::difference_type) noexcept {return lhs;}72347235} // detail72367237// The default comment type. It discards all the comments. It requires only one7238// byte to contain, so the memory footprint is smaller than preserve_comments.7239//7240// It just ignores `push_back`, `insert`, `erase`, and any other modifications.7241// IT always returns size() == 0, the iterator taken by `begin()` is always the7242// same as that of `end()`, and accessing through `operator[]` or iterators7243// always causes a segmentation fault. DO NOT access to the element of this.7244//7245// Why this is chose as the default type is because the last version (2.x.y)7246// does not contain any comments in a value. To minimize the impact on the7247// efficiency, this is chosen as a default.7248//7249// To reduce the memory footprint, later we can try empty base optimization (EBO).7250class discard_comments7251{7252public:7253using size_type = std::size_t;7254using difference_type = std::ptrdiff_t;7255using value_type = std::string;7256using reference = std::string&;7257using const_reference = std::string const&;7258using pointer = std::string*;7259using const_pointer = std::string const*;7260using iterator = detail::empty_iterator<std::string, false>;7261using const_iterator = detail::empty_iterator<std::string, true>;7262using reverse_iterator = detail::empty_iterator<std::string, false>;7263using const_reverse_iterator = detail::empty_iterator<std::string, true>;72647265public:7266discard_comments() = default;7267~discard_comments() = default;7268discard_comments(discard_comments const&) = default;7269discard_comments(discard_comments &&) = default;7270discard_comments& operator=(discard_comments const&) = default;7271discard_comments& operator=(discard_comments &&) = default;72727273explicit discard_comments(const std::vector<std::string>&) noexcept {}7274explicit discard_comments(std::vector<std::string>&&) noexcept {}7275discard_comments& operator=(const std::vector<std::string>&) noexcept {return *this;}7276discard_comments& operator=(std::vector<std::string>&&) noexcept {return *this;}72777278explicit discard_comments(const preserve_comments&) noexcept {}72797280explicit discard_comments(size_type) noexcept {}7281discard_comments(size_type, const std::string&) noexcept {}7282discard_comments(std::initializer_list<std::string>) noexcept {}7283template<typename InputIterator>7284discard_comments(InputIterator, InputIterator) noexcept {}72857286template<typename InputIterator>7287void assign(InputIterator, InputIterator) noexcept {}7288void assign(std::initializer_list<std::string>) noexcept {}7289void assign(size_type, const std::string&) noexcept {}72907291iterator insert(const_iterator, const std::string&) {return iterator{};}7292iterator insert(const_iterator, std::string&&) {return iterator{};}7293iterator insert(const_iterator, size_type, const std::string&) {return iterator{};}7294template<typename InputIterator>7295iterator insert(const_iterator, InputIterator, InputIterator) {return iterator{};}7296iterator insert(const_iterator, std::initializer_list<std::string>) {return iterator{};}72977298template<typename ... Ts>7299iterator emplace(const_iterator, Ts&& ...) {return iterator{};}7300iterator erase(const_iterator) {return iterator{};}7301iterator erase(const_iterator, const_iterator) {return iterator{};}73027303void swap(discard_comments&) {return;}73047305void push_back(const std::string&) {return;}7306void push_back(std::string&& ) {return;}7307void pop_back() {return;}73087309template<typename ... Ts>7310void emplace_back(Ts&& ...) {return;}73117312void clear() {return;}73137314size_type size() const noexcept {return 0;}7315size_type max_size() const noexcept {return 0;}7316size_type capacity() const noexcept {return 0;}7317bool empty() const noexcept {return true;}73187319void reserve(size_type) {return;}7320void resize(size_type) {return;}7321void resize(size_type, const std::string&) {return;}7322void shrink_to_fit() {return;}73237324// DO NOT access to the element of this container. This container is always7325// empty, so accessing through operator[], front/back, data causes address7326// error.73277328reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}7329const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}7330reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}7331const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}7332reference front() noexcept {never_call("toml::discard_comment::front");}7333const_reference front() const noexcept {never_call("toml::discard_comment::front");}7334reference back() noexcept {never_call("toml::discard_comment::back");}7335const_reference back() const noexcept {never_call("toml::discard_comment::back");}73367337pointer data() noexcept {return nullptr;}7338const_pointer data() const noexcept {return nullptr;}73397340iterator begin() noexcept {return iterator{};}7341iterator end() noexcept {return iterator{};}7342const_iterator begin() const noexcept {return const_iterator{};}7343const_iterator end() const noexcept {return const_iterator{};}7344const_iterator cbegin() const noexcept {return const_iterator{};}7345const_iterator cend() const noexcept {return const_iterator{};}73467347reverse_iterator rbegin() noexcept {return iterator{};}7348reverse_iterator rend() noexcept {return iterator{};}7349const_reverse_iterator rbegin() const noexcept {return const_iterator{};}7350const_reverse_iterator rend() const noexcept {return const_iterator{};}7351const_reverse_iterator crbegin() const noexcept {return const_iterator{};}7352const_reverse_iterator crend() const noexcept {return const_iterator{};}73537354private:73557356[[noreturn]] static void never_call(const char *const this_function)7357{7358#if __has_builtin(__builtin_unreachable)7359__builtin_unreachable();7360#endif7361throw std::logic_error{this_function};7362}7363};73647365inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}7366inline bool operator!=(const discard_comments&, const discard_comments&) noexcept {return false;}7367inline bool operator< (const discard_comments&, const discard_comments&) noexcept {return false;}7368inline bool operator<=(const discard_comments&, const discard_comments&) noexcept {return true;}7369inline bool operator> (const discard_comments&, const discard_comments&) noexcept {return false;}7370inline bool operator>=(const discard_comments&, const discard_comments&) noexcept {return true;}73717372inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}73737374inline std::ostream& operator<<(std::ostream& os, const discard_comments&) {return os;}73757376} // TOML11_INLINE_VERSION_NAMESPACE7377} // toml117378#endif // TOML11_COMMENTS_FWD_HPP73797380#if ! defined(TOML11_COMPILE_SOURCES)7381#ifndef TOML11_COMMENTS_IMPL_HPP7382#define TOML11_COMMENTS_IMPL_HPP738373847385namespace toml7386{7387inline namespace TOML11_INLINE_VERSION_NAMESPACE7388{73897390TOML11_INLINE bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;}7391TOML11_INLINE bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;}7392TOML11_INLINE bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;}7393TOML11_INLINE bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;}7394TOML11_INLINE bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;}7395TOML11_INLINE bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;}73967397TOML11_INLINE void swap(preserve_comments& lhs, preserve_comments& rhs)7398{7399lhs.swap(rhs);7400return;7401}7402TOML11_INLINE void swap(preserve_comments& lhs, std::vector<std::string>& rhs)7403{7404lhs.comments.swap(rhs);7405return;7406}7407TOML11_INLINE void swap(std::vector<std::string>& lhs, preserve_comments& rhs)7408{7409lhs.swap(rhs.comments);7410return;7411}74127413TOML11_INLINE std::ostream& operator<<(std::ostream& os, const preserve_comments& com)7414{7415for(const auto& c : com)7416{7417if(c.front() != '#')7418{7419os << '#';7420}7421os << c << '\n';7422}7423return os;7424}74257426} // TOML11_INLINE_VERSION_NAMESPACE7427} // toml117428#endif // TOML11_COMMENTS_IMPL_HPP7429#endif74307431#endif // TOML11_COMMENTS_HPP7432#ifndef TOML11_COLOR_HPP7433#define TOML11_COLOR_HPP74347435#ifndef TOML11_COLOR_FWD_HPP7436#define TOML11_COLOR_FWD_HPP74377438#include <iosfwd>743974407441#ifdef TOML11_COLORIZE_ERROR_MESSAGE7442#define TOML11_ERROR_MESSAGE_COLORIZED true7443#else7444#define TOML11_ERROR_MESSAGE_COLORIZED false7445#endif74467447#ifdef TOML11_USE_THREAD_LOCAL_COLORIZATION7448#define TOML11_THREAD_LOCAL_COLORIZATION thread_local7449#else7450#define TOML11_THREAD_LOCAL_COLORIZATION7451#endif74527453namespace toml7454{7455inline namespace TOML11_INLINE_VERSION_NAMESPACE7456{7457namespace color7458{7459// put ANSI escape sequence to ostream7460inline namespace ansi7461{7462namespace detail7463{74647465// Control color mode globally7466class color_mode7467{7468public:74697470void enable() noexcept7471{7472should_color_ = true;7473}7474void disable() noexcept7475{7476should_color_ = false;7477}7478bool should_color() const noexcept7479{7480return should_color_;7481}74827483private:74847485bool should_color_ = TOML11_ERROR_MESSAGE_COLORIZED;7486};74877488inline color_mode& color_status() noexcept7489{7490static TOML11_THREAD_LOCAL_COLORIZATION color_mode status;7491return status;7492}74937494} // detail74957496std::ostream& reset (std::ostream& os);7497std::ostream& bold (std::ostream& os);7498std::ostream& grey (std::ostream& os);7499std::ostream& gray (std::ostream& os);7500std::ostream& red (std::ostream& os);7501std::ostream& green (std::ostream& os);7502std::ostream& yellow (std::ostream& os);7503std::ostream& blue (std::ostream& os);7504std::ostream& magenta(std::ostream& os);7505std::ostream& cyan (std::ostream& os);7506std::ostream& white (std::ostream& os);75077508} // ansi75097510inline void enable()7511{7512return detail::color_status().enable();7513}7514inline void disable()7515{7516return detail::color_status().disable();7517}7518inline bool should_color()7519{7520return detail::color_status().should_color();7521}75227523} // color7524} // TOML11_INLINE_VERSION_NAMESPACE7525} // toml7526#endif // TOML11_COLOR_FWD_HPP75277528#if ! defined(TOML11_COMPILE_SOURCES)7529#ifndef TOML11_COLOR_IMPL_HPP7530#define TOML11_COLOR_IMPL_HPP753175327533#include <ostream>75347535namespace toml7536{7537inline namespace TOML11_INLINE_VERSION_NAMESPACE7538{7539namespace color7540{7541// put ANSI escape sequence to ostream7542inline namespace ansi7543{75447545TOML11_INLINE std::ostream& reset(std::ostream& os)7546{7547if(detail::color_status().should_color()) {os << "\033[00m";}7548return os;7549}7550TOML11_INLINE std::ostream& bold(std::ostream& os)7551{7552if(detail::color_status().should_color()) {os << "\033[01m";}7553return os;7554}7555TOML11_INLINE std::ostream& grey(std::ostream& os)7556{7557if(detail::color_status().should_color()) {os << "\033[30m";}7558return os;7559}7560TOML11_INLINE std::ostream& gray(std::ostream& os)7561{7562if(detail::color_status().should_color()) {os << "\033[30m";}7563return os;7564}7565TOML11_INLINE std::ostream& red(std::ostream& os)7566{7567if(detail::color_status().should_color()) {os << "\033[31m";}7568return os;7569}7570TOML11_INLINE std::ostream& green(std::ostream& os)7571{7572if(detail::color_status().should_color()) {os << "\033[32m";}7573return os;7574}7575TOML11_INLINE std::ostream& yellow(std::ostream& os)7576{7577if(detail::color_status().should_color()) {os << "\033[33m";}7578return os;7579}7580TOML11_INLINE std::ostream& blue(std::ostream& os)7581{7582if(detail::color_status().should_color()) {os << "\033[34m";}7583return os;7584}7585TOML11_INLINE std::ostream& magenta(std::ostream& os)7586{7587if(detail::color_status().should_color()) {os << "\033[35m";}7588return os;7589}7590TOML11_INLINE std::ostream& cyan (std::ostream& os)7591{7592if(detail::color_status().should_color()) {os << "\033[36m";}7593return os;7594}7595TOML11_INLINE std::ostream& white (std::ostream& os)7596{7597if(detail::color_status().should_color()) {os << "\033[37m";}7598return os;7599}76007601} // ansi7602} // color7603} // TOML11_INLINE_VERSION_NAMESPACE7604} // toml7605#endif // TOML11_COLOR_IMPL_HPP7606#endif76077608#endif // TOML11_COLOR_HPP7609#ifndef TOML11_SOURCE_LOCATION_HPP7610#define TOML11_SOURCE_LOCATION_HPP76117612#ifndef TOML11_SOURCE_LOCATION_FWD_HPP7613#define TOML11_SOURCE_LOCATION_FWD_HPP761476157616#include <sstream>7617#include <string>7618#include <vector>76197620namespace toml7621{7622inline namespace TOML11_INLINE_VERSION_NAMESPACE7623{76247625//7626// A struct to contain location in a toml file.7627//7628// To reduce memory consumption, it omits unrelated parts of long lines. like:7629//7630// 1. one long line, short region7631// ```7632// |7633// 1 | ... "foo", "bar", baz, "qux", "foobar", ...7634// | ^-- unknown value7635// ```7636// 2. long region7637// ```7638// |7639// 1 | array = [ "foo", ... "bar" ]7640// | ^^^^^^^^^^^^^^^^^^^^- in this array7641// ```7642// 3. many lines7643// |7644// 1 | array = [ "foo",7645// | ^^^^^^^^7646// | ...7647// | ^^^7648// |7649// 10 | , "bar"]7650// | ^^^^^^^^- in this array7651// ```7652//7653struct source_location7654{7655public:76567657explicit source_location(const detail::region& r);7658~source_location() = default;7659source_location(source_location const&) = default;7660source_location(source_location &&) = default;7661source_location& operator=(source_location const&) = default;7662source_location& operator=(source_location &&) = default;76637664bool is_ok() const noexcept {return this->is_ok_;}7665std::size_t length() const noexcept {return this->length_;}76667667std::size_t first_line_number() const noexcept {return this->first_line_;}7668std::size_t first_column_number() const noexcept {return this->first_column_;}7669std::size_t last_line_number() const noexcept {return this->last_line_;}7670std::size_t last_column_number() const noexcept {return this->last_column_;}76717672std::string const& file_name() const noexcept {return this->file_name_;}76737674std::size_t num_lines() const noexcept {return this->line_str_.size();}76757676std::string const& first_line() const;7677std::string const& last_line() const;76787679std::vector<std::string> const& lines() const noexcept {return line_str_;}76807681// for internal use7682std::size_t first_column_offset() const noexcept {return this->first_offset_;}7683std::size_t last_column_offset() const noexcept {return this->last_offset_;}76847685private:76867687bool is_ok_;7688std::size_t first_line_;7689std::size_t first_column_; // column num in the actual file7690std::size_t first_offset_; // column num in the shown line7691std::size_t last_line_;7692std::size_t last_column_; // column num in the actual file7693std::size_t last_offset_; // column num in the shown line7694std::size_t length_;7695std::string file_name_;7696std::vector<std::string> line_str_;7697};76987699namespace detail7700{77017702std::size_t integer_width_base10(std::size_t i) noexcept;77037704inline std::size_t line_width() noexcept {return 0;}77057706template<typename ... Ts>7707std::size_t line_width(const source_location& loc, const std::string& /*msg*/,7708const Ts& ... tail) noexcept7709{7710return (std::max)(7711integer_width_base10(loc.last_line_number()), line_width(tail...));7712}77137714std::ostringstream&7715format_filename(std::ostringstream& oss, const source_location& loc);77167717std::ostringstream&7718format_empty_line(std::ostringstream& oss, const std::size_t lnw);77197720std::ostringstream& format_line(std::ostringstream& oss,7721const std::size_t lnw, const std::size_t linenum, const std::string& line);77227723std::ostringstream& format_underline(std::ostringstream& oss,7724const std::size_t lnw, const std::size_t col, const std::size_t len,7725const std::string& msg);77267727std::string format_location_impl(const std::size_t lnw,7728const std::string& prev_fname,7729const source_location& loc, const std::string& msg);77307731inline std::string format_location_rec(const std::size_t, const std::string&)7732{7733return "";7734}77357736template<typename ... Ts>7737std::string format_location_rec(const std::size_t lnw,7738const std::string& prev_fname,7739const source_location& loc, const std::string& msg,7740const Ts& ... tail)7741{7742return format_location_impl(lnw, prev_fname, loc, msg) +7743format_location_rec(lnw, loc.file_name(), tail...);7744}77457746} // namespace detail77477748// format a location info without title7749template<typename ... Ts>7750std::string format_location(7751const source_location& loc, const std::string& msg, const Ts& ... tail)7752{7753const auto lnw = detail::line_width(loc, msg, tail...);77547755const std::string f(""); // at the 1st iteration, no prev_filename is given7756return detail::format_location_rec(lnw, f, loc, msg, tail...);7757}77587759} // TOML11_INLINE_VERSION_NAMESPACE7760} // toml7761#endif // TOML11_SOURCE_LOCATION_FWD_HPP77627763#if ! defined(TOML11_COMPILE_SOURCES)7764#ifndef TOML11_SOURCE_LOCATION_IMPL_HPP7765#define TOML11_SOURCE_LOCATION_IMPL_HPP7766776777687769#include <iomanip>7770#include <sstream>7771#include <string>7772#include <vector>77737774#include <cctype>77757776namespace toml7777{7778inline namespace TOML11_INLINE_VERSION_NAMESPACE7779{77807781TOML11_INLINE source_location::source_location(const detail::region& r)7782: is_ok_(false),7783first_line_(1),7784first_column_(1),7785first_offset_(1),7786last_line_(1),7787last_column_(1),7788last_offset_(1),7789length_(0),7790file_name_("unknown file")7791{7792if(r.is_ok())7793{7794this->is_ok_ = true;7795this->file_name_ = r.source_name();7796this->first_line_ = r.first_line_number();7797this->first_column_ = r.first_column_number();7798this->last_line_ = r.last_line_number();7799this->last_column_ = r.last_column_number();7800this->length_ = r.length();78017802const auto lines = r.as_lines();7803assert( ! lines.empty());78047805for(const auto& l : lines)7806{7807this->line_str_.push_back(l.first);7808}78097810this->first_offset_ = lines.at( 0).second + 1; // to 1-origin7811this->last_offset_ = lines.at(lines.size()-1).second + 1;7812}7813}78147815TOML11_INLINE std::string const& source_location::first_line() const7816{7817if(this->line_str_.size() == 0)7818{7819throw std::out_of_range("toml::source_location::first_line: `lines` is empty");7820}7821return this->line_str_.front();7822}7823TOML11_INLINE std::string const& source_location::last_line() const7824{7825if(this->line_str_.size() == 0)7826{7827throw std::out_of_range("toml::source_location::first_line: `lines` is empty");7828}7829return this->line_str_.back();7830}78317832namespace detail7833{78347835TOML11_INLINE std::size_t integer_width_base10(std::size_t i) noexcept7836{7837std::size_t width = 0;7838while(i != 0)7839{7840i /= 10;7841width += 1;7842}7843return width;7844}78457846TOML11_INLINE std::ostringstream&7847format_filename(std::ostringstream& oss, const source_location& loc)7848{7849// --> example.toml7850oss << color::bold << color::blue << " --> " << color::reset7851<< color::bold << loc.file_name() << '\n' << color::reset;7852return oss;7853}78547855TOML11_INLINE std::ostringstream& format_empty_line(std::ostringstream& oss,7856const std::size_t lnw)7857{7858// |7859oss << detail::make_string(lnw + 1, ' ')7860<< color::bold << color::blue << " |\n" << color::reset;7861return oss;7862}78637864TOML11_INLINE std::ostringstream& format_line(std::ostringstream& oss,7865const std::size_t lnw, const std::size_t linenum, const std::string& line)7866{7867// 10 | key = "value"7868oss << ' ' << color::bold << color::blue7869<< std::setw(static_cast<int>(lnw))7870<< std::right << linenum << " | " << color::reset;7871for(const char c : line)7872{7873if(std::isgraph(c) || c == ' ')7874{7875oss << c;7876}7877else7878{7879oss << show_char(c);7880}7881}7882oss << '\n';7883return oss;7884}7885TOML11_INLINE std::ostringstream& format_underline(std::ostringstream& oss,7886const std::size_t lnw, const std::size_t col, const std::size_t len,7887const std::string& msg)7888{7889// | ^^^^^^^-- this part7890oss << make_string(lnw + 1, ' ')7891<< color::bold << color::blue << " | " << color::reset;78927893// in case col is 0, so we don't create a string with size_t max length7894const std::size_t sanitized_col = col == 0 ? 0 : col - 1 /*1-origin*/;7895oss << make_string(sanitized_col, ' ')7896<< color::bold << color::red7897<< make_string(len, '^') << "-- "7898<< color::reset << msg << '\n';78997900return oss;7901}79027903TOML11_INLINE std::string format_location_impl(const std::size_t lnw,7904const std::string& prev_fname,7905const source_location& loc, const std::string& msg)7906{7907std::ostringstream oss;79087909if(loc.file_name() != prev_fname)7910{7911format_filename(oss, loc);7912if( ! loc.lines().empty())7913{7914format_empty_line(oss, lnw);7915}7916}79177918if(loc.lines().size() == 1)7919{7920// when column points LF, it exceeds the size of the first line.7921std::size_t underline_limit = 1;7922if(loc.first_line().size() < loc.first_column_offset())7923{7924underline_limit = 1;7925}7926else7927{7928underline_limit = loc.first_line().size() - loc.first_column_offset() + 1;7929}7930const auto underline_len = (std::min)(underline_limit, loc.length());79317932format_line(oss, lnw, loc.first_line_number(), loc.first_line());7933format_underline(oss, lnw, loc.first_column_offset(), underline_len, msg);7934}7935else if(loc.lines().size() == 2)7936{7937const auto first_underline_len =7938loc.first_line().size() - loc.first_column_offset() + 1;7939format_line(oss, lnw, loc.first_line_number(), loc.first_line());7940format_underline(oss, lnw, loc.first_column_offset(),7941first_underline_len, "");79427943format_line(oss, lnw, loc.last_line_number(), loc.last_line());7944format_underline(oss, lnw, 1, loc.last_column_offset(), msg);7945}7946else if(loc.lines().size() > 2)7947{7948const auto first_underline_len =7949loc.first_line().size() - loc.first_column_offset() + 1;7950format_line(oss, lnw, loc.first_line_number(), loc.first_line());7951format_underline(oss, lnw, loc.first_column_offset(),7952first_underline_len, "and");79537954if(loc.lines().size() == 3)7955{7956format_line(oss, lnw, loc.first_line_number()+1, loc.lines().at(1));7957format_underline(oss, lnw, 1, loc.lines().at(1).size(), "and");7958}7959else7960{7961format_line(oss, lnw, loc.first_line_number()+1, " ...");7962format_empty_line(oss, lnw);7963}7964format_line(oss, lnw, loc.last_line_number(), loc.last_line());7965format_underline(oss, lnw, 1, loc.last_column_offset(), msg);7966}7967// if loc is empty, do nothing.7968return oss.str();7969}79707971} // namespace detail7972} // TOML11_INLINE_VERSION_NAMESPACE7973} // toml7974#endif // TOML11_SOURCE_LOCATION_IMPL_HPP7975#endif79767977#endif // TOML11_SOURCE_LOCATION_HPP7978#ifndef TOML11_ERROR_INFO_HPP7979#define TOML11_ERROR_INFO_HPP79807981#ifndef TOML11_ERROR_INFO_FWD_HPP7982#define TOML11_ERROR_INFO_FWD_HPP798379847985namespace toml7986{7987inline namespace TOML11_INLINE_VERSION_NAMESPACE7988{79897990// error info returned from parser.7991struct error_info7992{7993error_info(std::string t, source_location l, std::string m, std::string s = "")7994: title_(std::move(t)), locations_{std::make_pair(std::move(l), std::move(m))},7995suffix_(std::move(s))7996{}79977998error_info(std::string t, std::vector<std::pair<source_location, std::string>> l,7999std::string s = "")8000: title_(std::move(t)), locations_(std::move(l)), suffix_(std::move(s))8001{}80028003std::string const& title() const noexcept {return title_;}8004std::string & title() noexcept {return title_;}80058006std::vector<std::pair<source_location, std::string>> const&8007locations() const noexcept {return locations_;}80088009void add_locations(source_location loc, std::string msg) noexcept8010{8011locations_.emplace_back(std::move(loc), std::move(msg));8012}80138014std::string const& suffix() const noexcept {return suffix_;}8015std::string & suffix() noexcept {return suffix_;}80168017private:80188019std::string title_;8020std::vector<std::pair<source_location, std::string>> locations_;8021std::string suffix_; // hint or something like that8022};80238024// forward decl8025template<typename TypeConfig>8026class basic_value;80278028namespace detail8029{8030inline error_info make_error_info_rec(error_info e)8031{8032return e;8033}8034inline error_info make_error_info_rec(error_info e, std::string s)8035{8036e.suffix() = s;8037return e;8038}80398040template<typename TC, typename ... Ts>8041error_info make_error_info_rec(error_info e,8042const basic_value<TC>& v, std::string msg, Ts&& ... tail);80438044template<typename ... Ts>8045error_info make_error_info_rec(error_info e,8046source_location loc, std::string msg, Ts&& ... tail)8047{8048e.add_locations(std::move(loc), std::move(msg));8049return make_error_info_rec(std::move(e), std::forward<Ts>(tail)...);8050}80518052} // detail80538054template<typename ... Ts>8055error_info make_error_info(8056std::string title, source_location loc, std::string msg, Ts&& ... tail)8057{8058error_info ei(std::move(title), std::move(loc), std::move(msg));8059return detail::make_error_info_rec(ei, std::forward<Ts>(tail) ... );8060}80618062std::string format_error(const std::string& errkind, const error_info& err);8063std::string format_error(const error_info& err);80648065// for custom error message8066template<typename ... Ts>8067std::string format_error(std::string title,8068source_location loc, std::string msg, Ts&& ... tail)8069{8070return format_error("", make_error_info(std::move(title),8071std::move(loc), std::move(msg), std::forward<Ts>(tail)...));8072}80738074std::ostream& operator<<(std::ostream& os, const error_info& e);80758076} // TOML11_INLINE_VERSION_NAMESPACE8077} // toml8078#endif // TOML11_ERROR_INFO_FWD_HPP80798080#if ! defined(TOML11_COMPILE_SOURCES)8081#ifndef TOML11_ERROR_INFO_IMPL_HPP8082#define TOML11_ERROR_INFO_IMPL_HPP808380848085#include <sstream>80868087namespace toml8088{8089inline namespace TOML11_INLINE_VERSION_NAMESPACE8090{80918092TOML11_INLINE std::string format_error(const std::string& errkind, const error_info& err)8093{8094std::string errmsg;8095if( ! errkind.empty())8096{8097errmsg = errkind;8098errmsg += ' ';8099}8100errmsg += err.title();8101errmsg += '\n';81028103const auto lnw = [&err]() {8104std::size_t width = 0;8105for(const auto& l : err.locations())8106{8107width = (std::max)(detail::integer_width_base10(l.first.last_line_number()), width);8108}8109return width;8110}();81118112bool first = true;8113std::string prev_fname;8114for(const auto& lm : err.locations())8115{8116if( ! first)8117{8118std::ostringstream oss;8119oss << detail::make_string(lnw + 1, ' ')8120<< color::bold << color::blue << " |" << color::reset8121<< color::bold << " ...\n" << color::reset;8122oss << detail::make_string(lnw + 1, ' ')8123<< color::bold << color::blue << " |\n" << color::reset;8124errmsg += oss.str();8125}81268127const auto& l = lm.first;8128const auto& m = lm.second;81298130errmsg += detail::format_location_impl(lnw, prev_fname, l, m);81318132prev_fname = l.file_name();8133first = false;8134}81358136errmsg += err.suffix();81378138return errmsg;8139}81408141TOML11_INLINE std::string format_error(const error_info& err)8142{8143std::ostringstream oss;8144oss << color::red << color::bold << "[error]" << color::reset;8145return format_error(oss.str(), err);8146}81478148TOML11_INLINE std::ostream& operator<<(std::ostream& os, const error_info& e)8149{8150os << format_error(e);8151return os;8152}81538154} // TOML11_INLINE_VERSION_NAMESPACE8155} // toml8156#endif // TOML11_ERROR_INFO_IMPL_HPP8157#endif81588159#endif // TOML11_ERROR_INFO_HPP8160#ifndef TOML11_VALUE_HPP8161#define TOML11_VALUE_HPP816281638164#ifdef TOML11_HAS_STRING_VIEW8165#include <string_view>8166#endif81678168#ifdef TOML11_ENABLE_ACCESS_CHECK8169#include <atomic>8170#endif81718172#include <cassert>81738174namespace toml8175{8176inline namespace TOML11_INLINE_VERSION_NAMESPACE8177{8178template<typename TypeConfig>8179class basic_value;81808181struct type_error final : public ::toml::exception8182{8183public:8184type_error(std::string what_arg, source_location loc)8185: what_(std::move(what_arg)), loc_(std::move(loc))8186{}8187~type_error() noexcept override = default;81888189const char* what() const noexcept override {return what_.c_str();}81908191source_location const& location() const noexcept {return loc_;}81928193private:8194std::string what_;8195source_location loc_;8196};81978198// only for internal use8199namespace detail8200{8201template<typename TC>8202error_info make_type_error(const basic_value<TC>&, const std::string&, const value_t);82038204template<typename TC>8205error_info make_not_found_error(const basic_value<TC>&, const std::string&, const typename basic_value<TC>::key_type&);82068207template<typename TC>8208void change_region_of_value(basic_value<TC>&, const basic_value<TC>&);82098210template<typename TC, value_t V>8211struct getter;82128213#ifdef TOML11_ENABLE_ACCESS_CHECK8214template<typename TC>8215void unset_access_flag(basic_value<TC>&);8216#endif8217} // detail82188219template<typename TypeConfig>8220class basic_value8221{8222public:82238224using config_type = TypeConfig;8225using key_type = typename config_type::string_type;8226using value_type = basic_value<config_type>;8227using boolean_type = typename config_type::boolean_type;8228using integer_type = typename config_type::integer_type;8229using floating_type = typename config_type::floating_type;8230using string_type = typename config_type::string_type;8231using local_time_type = ::toml::local_time;8232using local_date_type = ::toml::local_date;8233using local_datetime_type = ::toml::local_datetime;8234using offset_datetime_type = ::toml::offset_datetime;8235using array_type = typename config_type::template array_type<value_type>;8236using table_type = typename config_type::template table_type<key_type, value_type>;8237using comment_type = typename config_type::comment_type;8238using char_type = typename string_type::value_type;82398240private:82418242using region_type = detail::region;82438244public:82458246basic_value() noexcept8247: type_(value_t::empty), empty_('\0'), region_{}, comments_{}8248#ifdef TOML11_ENABLE_ACCESS_CHECK8249, accessed_{false}8250#endif8251{}8252~basic_value() noexcept {this->cleanup();}82538254// copy/move constructor/assigner ===================================== {{{82558256basic_value(const basic_value& v)8257: type_(v.type_), region_(v.region_), comments_(v.comments_)8258#ifdef TOML11_ENABLE_ACCESS_CHECK8259, accessed_{v.accessed()}8260#endif8261{8262switch(this->type_)8263{8264case value_t::boolean : assigner(boolean_ , v.boolean_ ); break;8265case value_t::integer : assigner(integer_ , v.integer_ ); break;8266case value_t::floating : assigner(floating_ , v.floating_ ); break;8267case value_t::string : assigner(string_ , v.string_ ); break;8268case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;8269case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;8270case value_t::local_date : assigner(local_date_ , v.local_date_ ); break;8271case value_t::local_time : assigner(local_time_ , v.local_time_ ); break;8272case value_t::array : assigner(array_ , v.array_ ); break;8273case value_t::table : assigner(table_ , v.table_ ); break;8274default : assigner(empty_ , '\0' ); break;8275}8276}8277basic_value(basic_value&& v)8278: type_(v.type()), region_(std::move(v.region_)),8279comments_(std::move(v.comments_))8280#ifdef TOML11_ENABLE_ACCESS_CHECK8281, accessed_{v.accessed()}8282#endif8283{8284switch(this->type_)8285{8286case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break;8287case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break;8288case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break;8289case value_t::string : assigner(string_ , std::move(v.string_ )); break;8290case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;8291case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;8292case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break;8293case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break;8294case value_t::array : assigner(array_ , std::move(v.array_ )); break;8295case value_t::table : assigner(table_ , std::move(v.table_ )); break;8296default : assigner(empty_ , '\0' ); break;8297}8298}82998300basic_value& operator=(const basic_value& v)8301{8302if(this == std::addressof(v)) {return *this;}83038304this->cleanup();8305this->type_ = v.type_;8306this->region_ = v.region_;8307this->comments_ = v.comments_;8308#ifdef TOML11_ENABLE_ACCESS_CHECK8309this->accessed_ = v.accessed();8310#endif8311switch(this->type_)8312{8313case value_t::boolean : assigner(boolean_ , v.boolean_ ); break;8314case value_t::integer : assigner(integer_ , v.integer_ ); break;8315case value_t::floating : assigner(floating_ , v.floating_ ); break;8316case value_t::string : assigner(string_ , v.string_ ); break;8317case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;8318case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;8319case value_t::local_date : assigner(local_date_ , v.local_date_ ); break;8320case value_t::local_time : assigner(local_time_ , v.local_time_ ); break;8321case value_t::array : assigner(array_ , v.array_ ); break;8322case value_t::table : assigner(table_ , v.table_ ); break;8323default : assigner(empty_ , '\0' ); break;8324}8325return *this;8326}8327basic_value& operator=(basic_value&& v)8328{8329if(this == std::addressof(v)) {return *this;}83308331this->cleanup();8332this->type_ = v.type_;8333this->region_ = std::move(v.region_);8334this->comments_ = std::move(v.comments_);8335#ifdef TOML11_ENABLE_ACCESS_CHECK8336this->accessed_ = v.accessed();8337#endif8338switch(this->type_)8339{8340case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break;8341case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break;8342case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break;8343case value_t::string : assigner(string_ , std::move(v.string_ )); break;8344case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;8345case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;8346case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break;8347case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break;8348case value_t::array : assigner(array_ , std::move(v.array_ )); break;8349case value_t::table : assigner(table_ , std::move(v.table_ )); break;8350default : assigner(empty_ , '\0' ); break;8351}8352return *this;8353}8354// }}}83558356// constructor to overwrite commnets ================================== {{{83578358basic_value(basic_value v, std::vector<std::string> com)8359: type_(v.type()), region_(std::move(v.region_)),8360comments_(std::move(com))8361#ifdef TOML11_ENABLE_ACCESS_CHECK8362, accessed_{v.accessed()}8363#endif8364{8365switch(this->type_)8366{8367case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break;8368case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break;8369case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break;8370case value_t::string : assigner(string_ , std::move(v.string_ )); break;8371case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;8372case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;8373case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break;8374case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break;8375case value_t::array : assigner(array_ , std::move(v.array_ )); break;8376case value_t::table : assigner(table_ , std::move(v.table_ )); break;8377default : assigner(empty_ , '\0' ); break;8378}8379}8380// }}}83818382// conversion between different basic_values ========================== {{{83838384template<typename TI>8385basic_value(basic_value<TI> other)8386: type_(other.type_),8387region_(std::move(other.region_)),8388comments_(std::move(other.comments_))8389#ifdef TOML11_ENABLE_ACCESS_CHECK8390, accessed_{other.accessed()}8391#endif8392{8393switch(other.type_)8394{8395// use auto-convert in constructor8396case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break;8397case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break;8398case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break;8399case value_t::string : assigner(string_ , std::move(other.string_ )); break;8400case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break;8401case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break;8402case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break;8403case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break;84048405// may have different container type8406case value_t::array :8407{8408array_type tmp(8409std::make_move_iterator(other.array_.value.get().begin()),8410std::make_move_iterator(other.array_.value.get().end()));8411assigner(array_, array_storage(8412detail::storage<array_type>(std::move(tmp)),8413other.array_.format8414));8415break;8416}8417case value_t::table :8418{8419table_type tmp(8420std::make_move_iterator(other.table_.value.get().begin()),8421std::make_move_iterator(other.table_.value.get().end()));8422assigner(table_, table_storage(8423detail::storage<table_type>(std::move(tmp)),8424other.table_.format8425));8426break;8427}8428default: break;8429}8430}84318432template<typename TI>8433basic_value(basic_value<TI> other, std::vector<std::string> com)8434: type_(other.type_),8435region_(std::move(other.region_)),8436comments_(std::move(com))8437#ifdef TOML11_ENABLE_ACCESS_CHECK8438, accessed_{other.accessed()}8439#endif8440{8441switch(other.type_)8442{8443// use auto-convert in constructor8444case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break;8445case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break;8446case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break;8447case value_t::string : assigner(string_ , std::move(other.string_ )); break;8448case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break;8449case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break;8450case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break;8451case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break;84528453// may have different container type8454case value_t::array :8455{8456array_type tmp(8457std::make_move_iterator(other.array_.value.get().begin()),8458std::make_move_iterator(other.array_.value.get().end()));8459assigner(array_, array_storage(8460detail::storage<array_type>(std::move(tmp)),8461other.array_.format8462));8463break;8464}8465case value_t::table :8466{8467table_type tmp(8468std::make_move_iterator(other.table_.value.get().begin()),8469std::make_move_iterator(other.table_.value.get().end()));8470assigner(table_, table_storage(8471detail::storage<table_type>(std::move(tmp)),8472other.table_.format8473));8474break;8475}8476default: break;8477}8478}8479template<typename TI>8480basic_value& operator=(basic_value<TI> other)8481{8482this->cleanup();8483this->region_ = other.region_;8484this->comments_ = comment_type(other.comments_);8485this->type_ = other.type_;8486#ifdef TOML11_ENABLE_ACCESS_CHECK8487this->accessed_ = other.accessed();8488#endif84898490switch(other.type_)8491{8492// use auto-convert in constructor8493case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break;8494case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break;8495case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break;8496case value_t::string : assigner(string_ , std::move(other.string_ )); break;8497case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break;8498case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break;8499case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break;8500case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break;85018502// may have different container type8503case value_t::array :8504{8505array_type tmp(8506std::make_move_iterator(other.array_.value.get().begin()),8507std::make_move_iterator(other.array_.value.get().end()));8508assigner(array_, array_storage(8509detail::storage<array_type>(std::move(tmp)),8510other.array_.format8511));8512break;8513}8514case value_t::table :8515{8516table_type tmp(8517std::make_move_iterator(other.table_.value.get().begin()),8518std::make_move_iterator(other.table_.value.get().end()));8519assigner(table_, table_storage(8520detail::storage<table_type>(std::move(tmp)),8521other.table_.format8522));8523break;8524}8525default: break;8526}8527return *this;8528}8529// }}}85308531// constructor (boolean) ============================================== {{{85328533basic_value(boolean_type x)8534: basic_value(x, boolean_format_info{}, std::vector<std::string>{}, region_type{})8535{}8536basic_value(boolean_type x, boolean_format_info fmt)8537: basic_value(x, fmt, std::vector<std::string>{}, region_type{})8538{}8539basic_value(boolean_type x, std::vector<std::string> com)8540: basic_value(x, boolean_format_info{}, std::move(com), region_type{})8541{}8542basic_value(boolean_type x, boolean_format_info fmt, std::vector<std::string> com)8543: basic_value(x, fmt, std::move(com), region_type{})8544{}8545basic_value(boolean_type x, boolean_format_info fmt,8546std::vector<std::string> com, region_type reg)8547: type_(value_t::boolean), boolean_(boolean_storage(x, fmt)),8548region_(std::move(reg)), comments_(std::move(com))8549#ifdef TOML11_ENABLE_ACCESS_CHECK8550, accessed_{false}8551#endif8552{}8553basic_value& operator=(boolean_type x)8554{8555boolean_format_info fmt;8556if(this->is_boolean())8557{8558fmt = this->as_boolean_fmt();8559}8560this->cleanup();8561this->type_ = value_t::boolean;8562this->region_ = region_type{};8563#ifdef TOML11_ENABLE_ACCESS_CHECK8564this->accessed_ = false;8565#endif8566assigner(this->boolean_, boolean_storage(x, fmt));8567return *this;8568}85698570// }}}85718572// constructor (integer) ============================================== {{{85738574basic_value(integer_type x)8575: basic_value(std::move(x), integer_format_info{}, std::vector<std::string>{}, region_type{})8576{}8577basic_value(integer_type x, integer_format_info fmt)8578: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})8579{}8580basic_value(integer_type x, std::vector<std::string> com)8581: basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{})8582{}8583basic_value(integer_type x, integer_format_info fmt, std::vector<std::string> com)8584: basic_value(std::move(x), std::move(fmt), std::move(com), region_type{})8585{}8586basic_value(integer_type x, integer_format_info fmt, std::vector<std::string> com, region_type reg)8587: type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))),8588region_(std::move(reg)), comments_(std::move(com))8589#ifdef TOML11_ENABLE_ACCESS_CHECK8590, accessed_{false}8591#endif8592{}8593basic_value& operator=(integer_type x)8594{8595integer_format_info fmt;8596if(this->is_integer())8597{8598fmt = this->as_integer_fmt();8599}8600this->cleanup();8601this->type_ = value_t::integer;8602this->region_ = region_type{};8603#ifdef TOML11_ENABLE_ACCESS_CHECK8604this->accessed_ = false;8605#endif8606assigner(this->integer_, integer_storage(std::move(x), std::move(fmt)));8607return *this;8608}86098610private:86118612template<typename T>8613using enable_if_integer_like_t = cxx::enable_if_t<cxx::conjunction<8614cxx::negation<std::is_same<cxx::remove_cvref_t<T>, boolean_type>>,8615cxx::negation<std::is_same<cxx::remove_cvref_t<T>, integer_type>>,8616std::is_integral<cxx::remove_cvref_t<T>>8617>::value, std::nullptr_t>;86188619public:86208621template<typename T, enable_if_integer_like_t<T> = nullptr>8622basic_value(T x)8623: basic_value(std::move(x), integer_format_info{}, std::vector<std::string>{}, region_type{})8624{}8625template<typename T, enable_if_integer_like_t<T> = nullptr>8626basic_value(T x, integer_format_info fmt)8627: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})8628{}8629template<typename T, enable_if_integer_like_t<T> = nullptr>8630basic_value(T x, std::vector<std::string> com)8631: basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{})8632{}8633template<typename T, enable_if_integer_like_t<T> = nullptr>8634basic_value(T x, integer_format_info fmt, std::vector<std::string> com)8635: basic_value(std::move(x), std::move(fmt), std::move(com), region_type{})8636{}8637template<typename T, enable_if_integer_like_t<T> = nullptr>8638basic_value(T x, integer_format_info fmt, std::vector<std::string> com, region_type reg)8639: type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))),8640region_(std::move(reg)), comments_(std::move(com))8641#ifdef TOML11_ENABLE_ACCESS_CHECK8642, accessed_{false}8643#endif8644{}8645template<typename T, enable_if_integer_like_t<T> = nullptr>8646basic_value& operator=(T x)8647{8648integer_format_info fmt;8649if(this->is_integer())8650{8651fmt = this->as_integer_fmt();8652}8653this->cleanup();8654this->type_ = value_t::integer;8655this->region_ = region_type{};8656#ifdef TOML11_ENABLE_ACCESS_CHECK8657this->accessed_ = false;8658#endif8659assigner(this->integer_, integer_storage(x, std::move(fmt)));8660return *this;8661}86628663// }}}86648665// constructor (floating) ============================================= {{{86668667basic_value(floating_type x)8668: basic_value(std::move(x), floating_format_info{}, std::vector<std::string>{}, region_type{})8669{}8670basic_value(floating_type x, floating_format_info fmt)8671: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})8672{}8673basic_value(floating_type x, std::vector<std::string> com)8674: basic_value(std::move(x), floating_format_info{}, std::move(com), region_type{})8675{}8676basic_value(floating_type x, floating_format_info fmt, std::vector<std::string> com)8677: basic_value(std::move(x), std::move(fmt), std::move(com), region_type{})8678{}8679basic_value(floating_type x, floating_format_info fmt, std::vector<std::string> com, region_type reg)8680: type_(value_t::floating), floating_(floating_storage(std::move(x), std::move(fmt))),8681region_(std::move(reg)), comments_(std::move(com))8682#ifdef TOML11_ENABLE_ACCESS_CHECK8683, accessed_{false}8684#endif8685{}8686basic_value& operator=(floating_type x)8687{8688floating_format_info fmt;8689if(this->is_floating())8690{8691fmt = this->as_floating_fmt();8692}8693this->cleanup();8694this->type_ = value_t::floating;8695this->region_ = region_type{};8696#ifdef TOML11_ENABLE_ACCESS_CHECK8697this->accessed_ = false;8698#endif8699assigner(this->floating_, floating_storage(std::move(x), std::move(fmt)));8700return *this;8701}87028703private:87048705template<typename T>8706using enable_if_floating_like_t = cxx::enable_if_t<cxx::conjunction<8707cxx::negation<std::is_same<cxx::remove_cvref_t<T>, floating_type>>,8708std::is_floating_point<cxx::remove_cvref_t<T>>8709>::value, std::nullptr_t>;87108711public:87128713template<typename T, enable_if_floating_like_t<T> = nullptr>8714basic_value(T x)8715: basic_value(x, floating_format_info{}, std::vector<std::string>{}, region_type{})8716{}87178718template<typename T, enable_if_floating_like_t<T> = nullptr>8719basic_value(T x, floating_format_info fmt)8720: basic_value(x, std::move(fmt), std::vector<std::string>{}, region_type{})8721{}87228723template<typename T, enable_if_floating_like_t<T> = nullptr>8724basic_value(T x, std::vector<std::string> com)8725: basic_value(x, floating_format_info{}, std::move(com), region_type{})8726{}87278728template<typename T, enable_if_floating_like_t<T> = nullptr>8729basic_value(T x, floating_format_info fmt, std::vector<std::string> com)8730: basic_value(x, std::move(fmt), std::move(com), region_type{})8731{}87328733template<typename T, enable_if_floating_like_t<T> = nullptr>8734basic_value(T x, floating_format_info fmt, std::vector<std::string> com, region_type reg)8735: type_(value_t::floating), floating_(floating_storage(x, std::move(fmt))),8736region_(std::move(reg)), comments_(std::move(com))8737#ifdef TOML11_ENABLE_ACCESS_CHECK8738, accessed_{false}8739#endif8740{}87418742template<typename T, enable_if_floating_like_t<T> = nullptr>8743basic_value& operator=(T x)8744{8745floating_format_info fmt;8746if(this->is_floating())8747{8748fmt = this->as_floating_fmt();8749}8750this->cleanup();8751this->type_ = value_t::floating;8752this->region_ = region_type{};8753#ifdef TOML11_ENABLE_ACCESS_CHECK8754this->accessed_ = false;8755#endif8756assigner(this->floating_, floating_storage(x, std::move(fmt)));8757return *this;8758}87598760// }}}87618762// constructor (string) =============================================== {{{87638764basic_value(string_type x)8765: basic_value(std::move(x), string_format_info{}, std::vector<std::string>{}, region_type{})8766{}8767basic_value(string_type x, string_format_info fmt)8768: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})8769{}8770basic_value(string_type x, std::vector<std::string> com)8771: basic_value(std::move(x), string_format_info{}, std::move(com), region_type{})8772{}8773basic_value(string_type x, string_format_info fmt, std::vector<std::string> com)8774: basic_value(std::move(x), std::move(fmt), std::move(com), region_type{})8775{}8776basic_value(string_type x, string_format_info fmt,8777std::vector<std::string> com, region_type reg)8778: type_(value_t::string), string_(string_storage(std::move(x), std::move(fmt))),8779region_(std::move(reg)), comments_(std::move(com))8780#ifdef TOML11_ENABLE_ACCESS_CHECK8781, accessed_{false}8782#endif8783{}8784basic_value& operator=(string_type x)8785{8786string_format_info fmt;8787if(this->is_string())8788{8789fmt = this->as_string_fmt();8790}8791this->cleanup();8792this->type_ = value_t::string;8793this->region_ = region_type{};8794#ifdef TOML11_ENABLE_ACCESS_CHECK8795this->accessed_ = false;8796#endif8797assigner(this->string_, string_storage(x, std::move(fmt)));8798return *this;8799}88008801// "string literal"88028803basic_value(const typename string_type::value_type* x)8804: basic_value(x, string_format_info{}, std::vector<std::string>{}, region_type{})8805{}8806basic_value(const typename string_type::value_type* x, string_format_info fmt)8807: basic_value(x, std::move(fmt), std::vector<std::string>{}, region_type{})8808{}8809basic_value(const typename string_type::value_type* x, std::vector<std::string> com)8810: basic_value(x, string_format_info{}, std::move(com), region_type{})8811{}8812basic_value(const typename string_type::value_type* x, string_format_info fmt, std::vector<std::string> com)8813: basic_value(x, std::move(fmt), std::move(com), region_type{})8814{}8815basic_value(const typename string_type::value_type* x, string_format_info fmt,8816std::vector<std::string> com, region_type reg)8817: type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))),8818region_(std::move(reg)), comments_(std::move(com))8819#ifdef TOML11_ENABLE_ACCESS_CHECK8820, accessed_{false}8821#endif8822{}8823basic_value& operator=(const typename string_type::value_type* x)8824{8825string_format_info fmt;8826if(this->is_string())8827{8828fmt = this->as_string_fmt();8829}8830this->cleanup();8831this->type_ = value_t::string;8832this->region_ = region_type{};8833#ifdef TOML11_ENABLE_ACCESS_CHECK8834this->accessed_ = false;8835#endif8836assigner(this->string_, string_storage(string_type(x), std::move(fmt)));8837return *this;8838}88398840#if defined(TOML11_HAS_STRING_VIEW)8841using string_view_type = std::basic_string_view<8842typename string_type::value_type, typename string_type::traits_type>;88438844basic_value(string_view_type x)8845: basic_value(x, string_format_info{}, std::vector<std::string>{}, region_type{})8846{}8847basic_value(string_view_type x, string_format_info fmt)8848: basic_value(x, std::move(fmt), std::vector<std::string>{}, region_type{})8849{}8850basic_value(string_view_type x, std::vector<std::string> com)8851: basic_value(x, string_format_info{}, std::move(com), region_type{})8852{}8853basic_value(string_view_type x, string_format_info fmt, std::vector<std::string> com)8854: basic_value(x, std::move(fmt), std::move(com), region_type{})8855{}8856basic_value(string_view_type x, string_format_info fmt,8857std::vector<std::string> com, region_type reg)8858: type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))),8859region_(std::move(reg)), comments_(std::move(com))8860#ifdef TOML11_ENABLE_ACCESS_CHECK8861, accessed_{false}8862#endif8863{}8864basic_value& operator=(string_view_type x)8865{8866string_format_info fmt;8867if(this->is_string())8868{8869fmt = this->as_string_fmt();8870}8871this->cleanup();8872this->type_ = value_t::string;8873this->region_ = region_type{};8874#ifdef TOML11_ENABLE_ACCESS_CHECK8875this->accessed_ = false;8876#endif8877assigner(this->string_, string_storage(string_type(x), std::move(fmt)));8878return *this;8879}88808881#endif // TOML11_HAS_STRING_VIEW88828883template<typename T, cxx::enable_if_t<cxx::conjunction<8884cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8885detail::is_1byte_std_basic_string<T>8886>::value, std::nullptr_t> = nullptr>8887basic_value(const T& x)8888: basic_value(x, string_format_info{}, std::vector<std::string>{}, region_type{})8889{}8890template<typename T, cxx::enable_if_t<cxx::conjunction<8891cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8892detail::is_1byte_std_basic_string<T>8893>::value, std::nullptr_t> = nullptr>8894basic_value(const T& x, string_format_info fmt)8895: basic_value(x, std::move(fmt), std::vector<std::string>{}, region_type{})8896{}8897template<typename T, cxx::enable_if_t<cxx::conjunction<8898cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8899detail::is_1byte_std_basic_string<T>8900>::value, std::nullptr_t> = nullptr>8901basic_value(const T& x, std::vector<std::string> com)8902: basic_value(x, string_format_info{}, std::move(com), region_type{})8903{}8904template<typename T, cxx::enable_if_t<cxx::conjunction<8905cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8906detail::is_1byte_std_basic_string<T>8907>::value, std::nullptr_t> = nullptr>8908basic_value(const T& x, string_format_info fmt, std::vector<std::string> com)8909: basic_value(x, std::move(fmt), std::move(com), region_type{})8910{}8911template<typename T, cxx::enable_if_t<cxx::conjunction<8912cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8913detail::is_1byte_std_basic_string<T>8914>::value, std::nullptr_t> = nullptr>8915basic_value(const T& x, string_format_info fmt,8916std::vector<std::string> com, region_type reg)8917: type_(value_t::string),8918string_(string_storage(detail::string_conv<string_type>(x), std::move(fmt))),8919region_(std::move(reg)), comments_(std::move(com))8920#ifdef TOML11_ENABLE_ACCESS_CHECK8921, accessed_{false}8922#endif8923{}8924template<typename T, cxx::enable_if_t<cxx::conjunction<8925cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,8926detail::is_1byte_std_basic_string<T>8927>::value, std::nullptr_t> = nullptr>8928basic_value& operator=(const T& x)8929{8930string_format_info fmt;8931if(this->is_string())8932{8933fmt = this->as_string_fmt();8934}8935this->cleanup();8936this->type_ = value_t::string;8937this->region_ = region_type{};8938#ifdef TOML11_ENABLE_ACCESS_CHECK8939this->accessed_ = false;8940#endif8941assigner(this->string_, string_storage(detail::string_conv<string_type>(x), std::move(fmt)));8942return *this;8943}89448945// }}}89468947// constructor (local_date) =========================================== {{{89488949basic_value(local_date_type x)8950: basic_value(x, local_date_format_info{}, std::vector<std::string>{}, region_type{})8951{}8952basic_value(local_date_type x, local_date_format_info fmt)8953: basic_value(x, fmt, std::vector<std::string>{}, region_type{})8954{}8955basic_value(local_date_type x, std::vector<std::string> com)8956: basic_value(x, local_date_format_info{}, std::move(com), region_type{})8957{}8958basic_value(local_date_type x, local_date_format_info fmt, std::vector<std::string> com)8959: basic_value(x, fmt, std::move(com), region_type{})8960{}8961basic_value(local_date_type x, local_date_format_info fmt,8962std::vector<std::string> com, region_type reg)8963: type_(value_t::local_date), local_date_(local_date_storage(x, fmt)),8964region_(std::move(reg)), comments_(std::move(com))8965#ifdef TOML11_ENABLE_ACCESS_CHECK8966, accessed_{false}8967#endif8968{}8969basic_value& operator=(local_date_type x)8970{8971local_date_format_info fmt;8972if(this->is_local_date())8973{8974fmt = this->as_local_date_fmt();8975}8976this->cleanup();8977this->type_ = value_t::local_date;8978this->region_ = region_type{};8979#ifdef TOML11_ENABLE_ACCESS_CHECK8980this->accessed_ = false;8981#endif8982assigner(this->local_date_, local_date_storage(x, fmt));8983return *this;8984}89858986// }}}89878988// constructor (local_time) =========================================== {{{89898990basic_value(local_time_type x)8991: basic_value(x, local_time_format_info{}, std::vector<std::string>{}, region_type{})8992{}8993basic_value(local_time_type x, local_time_format_info fmt)8994: basic_value(x, fmt, std::vector<std::string>{}, region_type{})8995{}8996basic_value(local_time_type x, std::vector<std::string> com)8997: basic_value(x, local_time_format_info{}, std::move(com), region_type{})8998{}8999basic_value(local_time_type x, local_time_format_info fmt, std::vector<std::string> com)9000: basic_value(x, fmt, std::move(com), region_type{})9001{}9002basic_value(local_time_type x, local_time_format_info fmt,9003std::vector<std::string> com, region_type reg)9004: type_(value_t::local_time), local_time_(local_time_storage(x, fmt)),9005region_(std::move(reg)), comments_(std::move(com))9006#ifdef TOML11_ENABLE_ACCESS_CHECK9007, accessed_{false}9008#endif9009{}9010basic_value& operator=(local_time_type x)9011{9012local_time_format_info fmt;9013if(this->is_local_time())9014{9015fmt = this->as_local_time_fmt();9016}9017this->cleanup();9018this->type_ = value_t::local_time;9019this->region_ = region_type{};9020#ifdef TOML11_ENABLE_ACCESS_CHECK9021this->accessed_ = false;9022#endif9023assigner(this->local_time_, local_time_storage(x, fmt));9024return *this;9025}90269027template<typename Rep, typename Period>9028basic_value(const std::chrono::duration<Rep, Period>& x)9029: basic_value(local_time_type(x), local_time_format_info{}, std::vector<std::string>{}, region_type{})9030{}9031template<typename Rep, typename Period>9032basic_value(const std::chrono::duration<Rep, Period>& x, local_time_format_info fmt)9033: basic_value(local_time_type(x), std::move(fmt), std::vector<std::string>{}, region_type{})9034{}9035template<typename Rep, typename Period>9036basic_value(const std::chrono::duration<Rep, Period>& x, std::vector<std::string> com)9037: basic_value(local_time_type(x), local_time_format_info{}, std::move(com), region_type{})9038{}9039template<typename Rep, typename Period>9040basic_value(const std::chrono::duration<Rep, Period>& x, local_time_format_info fmt, std::vector<std::string> com)9041: basic_value(local_time_type(x), std::move(fmt), std::move(com), region_type{})9042{}9043template<typename Rep, typename Period>9044basic_value(const std::chrono::duration<Rep, Period>& x,9045local_time_format_info fmt,9046std::vector<std::string> com, region_type reg)9047: basic_value(local_time_type(x), std::move(fmt), std::move(com), std::move(reg))9048{}9049template<typename Rep, typename Period>9050basic_value& operator=(const std::chrono::duration<Rep, Period>& x)9051{9052local_time_format_info fmt;9053if(this->is_local_time())9054{9055fmt = this->as_local_time_fmt();9056}9057this->cleanup();9058this->type_ = value_t::local_time;9059this->region_ = region_type{};9060#ifdef TOML11_ENABLE_ACCESS_CHECK9061this->accessed_ = false;9062#endif9063assigner(this->local_time_, local_time_storage(local_time_type(x), std::move(fmt)));9064return *this;9065}90669067// }}}90689069// constructor (local_datetime) =========================================== {{{90709071basic_value(local_datetime_type x)9072: basic_value(x, local_datetime_format_info{}, std::vector<std::string>{}, region_type{})9073{}9074basic_value(local_datetime_type x, local_datetime_format_info fmt)9075: basic_value(x, fmt, std::vector<std::string>{}, region_type{})9076{}9077basic_value(local_datetime_type x, std::vector<std::string> com)9078: basic_value(x, local_datetime_format_info{}, std::move(com), region_type{})9079{}9080basic_value(local_datetime_type x, local_datetime_format_info fmt, std::vector<std::string> com)9081: basic_value(x, fmt, std::move(com), region_type{})9082{}9083basic_value(local_datetime_type x, local_datetime_format_info fmt,9084std::vector<std::string> com, region_type reg)9085: type_(value_t::local_datetime), local_datetime_(local_datetime_storage(x, fmt)),9086region_(std::move(reg)), comments_(std::move(com))9087#ifdef TOML11_ENABLE_ACCESS_CHECK9088, accessed_{false}9089#endif9090{}9091basic_value& operator=(local_datetime_type x)9092{9093local_datetime_format_info fmt;9094if(this->is_local_datetime())9095{9096fmt = this->as_local_datetime_fmt();9097}9098this->cleanup();9099this->type_ = value_t::local_datetime;9100this->region_ = region_type{};9101#ifdef TOML11_ENABLE_ACCESS_CHECK9102this->accessed_ = false;9103#endif9104assigner(this->local_datetime_, local_datetime_storage(x, fmt));9105return *this;9106}91079108// }}}91099110// constructor (offset_datetime) =========================================== {{{91119112basic_value(offset_datetime_type x)9113: basic_value(x, offset_datetime_format_info{}, std::vector<std::string>{}, region_type{})9114{}9115basic_value(offset_datetime_type x, offset_datetime_format_info fmt)9116: basic_value(x, fmt, std::vector<std::string>{}, region_type{})9117{}9118basic_value(offset_datetime_type x, std::vector<std::string> com)9119: basic_value(x, offset_datetime_format_info{}, std::move(com), region_type{})9120{}9121basic_value(offset_datetime_type x, offset_datetime_format_info fmt, std::vector<std::string> com)9122: basic_value(x, fmt, std::move(com), region_type{})9123{}9124basic_value(offset_datetime_type x, offset_datetime_format_info fmt,9125std::vector<std::string> com, region_type reg)9126: type_(value_t::offset_datetime), offset_datetime_(offset_datetime_storage(x, fmt)),9127region_(std::move(reg)), comments_(std::move(com))9128#ifdef TOML11_ENABLE_ACCESS_CHECK9129, accessed_{false}9130#endif9131{}9132basic_value& operator=(offset_datetime_type x)9133{9134offset_datetime_format_info fmt;9135if(this->is_offset_datetime())9136{9137fmt = this->as_offset_datetime_fmt();9138}9139this->cleanup();9140this->type_ = value_t::offset_datetime;9141this->region_ = region_type{};9142#ifdef TOML11_ENABLE_ACCESS_CHECK9143this->accessed_ = false;9144#endif9145assigner(this->offset_datetime_, offset_datetime_storage(x, fmt));9146return *this;9147}91489149// system_clock::time_point91509151basic_value(std::chrono::system_clock::time_point x)9152: basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::vector<std::string>{}, region_type{})9153{}9154basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt)9155: basic_value(offset_datetime_type(x), fmt, std::vector<std::string>{}, region_type{})9156{}9157basic_value(std::chrono::system_clock::time_point x, std::vector<std::string> com)9158: basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::move(com), region_type{})9159{}9160basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt, std::vector<std::string> com)9161: basic_value(offset_datetime_type(x), fmt, std::move(com), region_type{})9162{}9163basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt,9164std::vector<std::string> com, region_type reg)9165: basic_value(offset_datetime_type(x), std::move(fmt), std::move(com), std::move(reg))9166{}9167basic_value& operator=(std::chrono::system_clock::time_point x)9168{9169offset_datetime_format_info fmt;9170if(this->is_offset_datetime())9171{9172fmt = this->as_offset_datetime_fmt();9173}9174this->cleanup();9175this->type_ = value_t::offset_datetime;9176this->region_ = region_type{};9177#ifdef TOML11_ENABLE_ACCESS_CHECK9178this->accessed_ = false;9179#endif9180assigner(this->offset_datetime_, offset_datetime_storage(offset_datetime_type(x), fmt));9181return *this;9182}91839184// }}}91859186// constructor (array) ================================================ {{{91879188basic_value(array_type x)9189: basic_value(std::move(x), array_format_info{}, std::vector<std::string>{}, region_type{})9190{}9191basic_value(array_type x, array_format_info fmt)9192: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})9193{}9194basic_value(array_type x, std::vector<std::string> com)9195: basic_value(std::move(x), array_format_info{}, std::move(com), region_type{})9196{}9197basic_value(array_type x, array_format_info fmt, std::vector<std::string> com)9198: basic_value(std::move(x), fmt, std::move(com), region_type{})9199{}9200basic_value(array_type x, array_format_info fmt,9201std::vector<std::string> com, region_type reg)9202: type_(value_t::array), array_(array_storage(9203detail::storage<array_type>(std::move(x)), std::move(fmt)9204)), region_(std::move(reg)), comments_(std::move(com))9205#ifdef TOML11_ENABLE_ACCESS_CHECK9206, accessed_{false}9207#endif9208{}9209basic_value& operator=(array_type x)9210{9211array_format_info fmt;9212if(this->is_array())9213{9214fmt = this->as_array_fmt();9215}9216this->cleanup();9217this->type_ = value_t::array;9218this->region_ = region_type{};9219#ifdef TOML11_ENABLE_ACCESS_CHECK9220this->accessed_ = false;9221#endif9222assigner(this->array_, array_storage(9223detail::storage<array_type>(std::move(x)), std::move(fmt)));9224return *this;9225}92269227private:92289229template<typename T>9230using enable_if_array_like_t = cxx::enable_if_t<cxx::conjunction<9231detail::is_container<T>,9232cxx::negation<std::is_same<T, array_type>>,9233cxx::negation<detail::is_std_basic_string<T>>,9234#if defined(TOML11_HAS_STRING_VIEW)9235cxx::negation<detail::is_std_basic_string_view<T>>,9236#endif9237cxx::negation<detail::has_from_toml_method<T, config_type>>,9238cxx::negation<detail::has_specialized_from<T>>9239>::value, std::nullptr_t>;92409241public:92429243template<typename T, enable_if_array_like_t<T> = nullptr>9244basic_value(T x)9245: basic_value(std::move(x), array_format_info{}, std::vector<std::string>{}, region_type{})9246{}9247template<typename T, enable_if_array_like_t<T> = nullptr>9248basic_value(T x, array_format_info fmt)9249: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})9250{}9251template<typename T, enable_if_array_like_t<T> = nullptr>9252basic_value(T x, std::vector<std::string> com)9253: basic_value(std::move(x), array_format_info{}, std::move(com), region_type{})9254{}9255template<typename T, enable_if_array_like_t<T> = nullptr>9256basic_value(T x, array_format_info fmt, std::vector<std::string> com)9257: basic_value(std::move(x), fmt, std::move(com), region_type{})9258{}9259template<typename T, enable_if_array_like_t<T> = nullptr>9260basic_value(T x, array_format_info fmt,9261std::vector<std::string> com, region_type reg)9262: type_(value_t::array), array_(array_storage(9263detail::storage<array_type>(array_type(9264std::make_move_iterator(x.begin()),9265std::make_move_iterator(x.end()))9266), std::move(fmt)9267)), region_(std::move(reg)), comments_(std::move(com))9268#ifdef TOML11_ENABLE_ACCESS_CHECK9269, accessed_{false}9270#endif9271{}9272template<typename T, enable_if_array_like_t<T> = nullptr>9273basic_value& operator=(T x)9274{9275array_format_info fmt;9276if(this->is_array())9277{9278fmt = this->as_array_fmt();9279}9280this->cleanup();9281this->type_ = value_t::array;9282this->region_ = region_type{};9283#ifdef TOML11_ENABLE_ACCESS_CHECK9284this->accessed_ = false;9285#endif9286array_type a(std::make_move_iterator(x.begin()),9287std::make_move_iterator(x.end()));9288assigner(this->array_, array_storage(9289detail::storage<array_type>(std::move(a)), std::move(fmt)));9290return *this;9291}92929293// }}}92949295// constructor (table) ================================================ {{{92969297basic_value(table_type x)9298: basic_value(std::move(x), table_format_info{}, std::vector<std::string>{}, region_type{})9299{}9300basic_value(table_type x, table_format_info fmt)9301: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})9302{}9303basic_value(table_type x, std::vector<std::string> com)9304: basic_value(std::move(x), table_format_info{}, std::move(com), region_type{})9305{}9306basic_value(table_type x, table_format_info fmt, std::vector<std::string> com)9307: basic_value(std::move(x), fmt, std::move(com), region_type{})9308{}9309basic_value(table_type x, table_format_info fmt,9310std::vector<std::string> com, region_type reg)9311: type_(value_t::table), table_(table_storage(9312detail::storage<table_type>(std::move(x)), std::move(fmt)9313)), region_(std::move(reg)), comments_(std::move(com))9314#ifdef TOML11_ENABLE_ACCESS_CHECK9315, accessed_{false}9316#endif9317{}9318basic_value& operator=(table_type x)9319{9320table_format_info fmt;9321if(this->is_table())9322{9323fmt = this->as_table_fmt();9324}9325this->cleanup();9326this->type_ = value_t::table;9327this->region_ = region_type{};9328#ifdef TOML11_ENABLE_ACCESS_CHECK9329this->accessed_ = false;9330#endif9331assigner(this->table_, table_storage(9332detail::storage<table_type>(std::move(x)), std::move(fmt)));9333return *this;9334}93359336// table-like93379338private:93399340template<typename T>9341using enable_if_table_like_t = cxx::enable_if_t<cxx::conjunction<9342cxx::negation<std::is_same<T, table_type>>,9343detail::is_map<T>,9344cxx::negation<detail::has_from_toml_method<T, config_type>>,9345cxx::negation<detail::has_specialized_from<T>>9346>::value, std::nullptr_t>;93479348public:93499350template<typename T, enable_if_table_like_t<T> = nullptr>9351basic_value(T x)9352: basic_value(std::move(x), table_format_info{}, std::vector<std::string>{}, region_type{})9353{}9354template<typename T, enable_if_table_like_t<T> = nullptr>9355basic_value(T x, table_format_info fmt)9356: basic_value(std::move(x), std::move(fmt), std::vector<std::string>{}, region_type{})9357{}9358template<typename T, enable_if_table_like_t<T> = nullptr>9359basic_value(T x, std::vector<std::string> com)9360: basic_value(std::move(x), table_format_info{}, std::move(com), region_type{})9361{}9362template<typename T, enable_if_table_like_t<T> = nullptr>9363basic_value(T x, table_format_info fmt, std::vector<std::string> com)9364: basic_value(std::move(x), fmt, std::move(com), region_type{})9365{}9366template<typename T, enable_if_table_like_t<T> = nullptr>9367basic_value(T x, table_format_info fmt,9368std::vector<std::string> com, region_type reg)9369: type_(value_t::table), table_(table_storage(9370detail::storage<table_type>(table_type(9371std::make_move_iterator(x.begin()),9372std::make_move_iterator(x.end())9373)), std::move(fmt)9374)), region_(std::move(reg)), comments_(std::move(com))9375#ifdef TOML11_ENABLE_ACCESS_CHECK9376, accessed_{false}9377#endif9378{}9379template<typename T, enable_if_table_like_t<T> = nullptr>9380basic_value& operator=(T x)9381{9382table_format_info fmt;9383if(this->is_table())9384{9385fmt = this->as_table_fmt();9386}9387this->cleanup();9388this->type_ = value_t::table;9389this->region_ = region_type{};9390#ifdef TOML11_ENABLE_ACCESS_CHECK9391this->accessed_ = false;9392#endif9393table_type t(std::make_move_iterator(x.begin()),9394std::make_move_iterator(x.end()));9395assigner(this->table_, table_storage(9396detail::storage<table_type>(std::move(t)), std::move(fmt)));9397return *this;9398}93999400// }}}94019402// constructor (user_defined) ========================================= {{{94039404template<typename T, cxx::enable_if_t<9405detail::has_specialized_into<T>::value, std::nullptr_t> = nullptr>9406basic_value(const T& ud)9407: basic_value(9408into<cxx::remove_cvref_t<T>>::template into_toml<config_type>(ud))9409{}9410template<typename T, cxx::enable_if_t<9411detail::has_specialized_into<T>::value, std::nullptr_t> = nullptr>9412basic_value(const T& ud, std::vector<std::string> com)9413: basic_value(9414into<cxx::remove_cvref_t<T>>::template into_toml<config_type>(ud),9415std::move(com))9416{}9417template<typename T, cxx::enable_if_t<9418detail::has_specialized_into<T>::value, std::nullptr_t> = nullptr>9419basic_value& operator=(const T& ud)9420{9421*this = into<cxx::remove_cvref_t<T>>::template into_toml<config_type>(ud);9422#ifdef TOML11_ENABLE_ACCESS_CHECK9423this->accessed_ = false;9424#endif9425return *this;9426}94279428template<typename T, cxx::enable_if_t<cxx::conjunction<9429detail::has_into_toml_method<T>,9430cxx::negation<detail::has_specialized_into<T>>9431>::value, std::nullptr_t> = nullptr>9432basic_value(const T& ud): basic_value(ud.into_toml()) {}94339434template<typename T, cxx::enable_if_t<cxx::conjunction<9435detail::has_into_toml_method<T>,9436cxx::negation<detail::has_specialized_into<T>>9437>::value, std::nullptr_t> = nullptr>9438basic_value(const T& ud, std::vector<std::string> com)9439: basic_value(ud.into_toml(), std::move(com))9440{}9441template<typename T, cxx::enable_if_t<cxx::conjunction<9442detail::has_into_toml_method<T>,9443cxx::negation<detail::has_specialized_into<T>>9444>::value, std::nullptr_t> = nullptr>9445basic_value& operator=(const T& ud)9446{9447*this = ud.into_toml();9448#ifdef TOML11_ENABLE_ACCESS_CHECK9449this->accessed_ = false;9450#endif9451return *this;9452}94539454template<typename T, cxx::enable_if_t<cxx::conjunction<9455detail::has_template_into_toml_method<T, TypeConfig>,9456cxx::negation<detail::has_specialized_into<T>>9457>::value, std::nullptr_t> = nullptr>9458basic_value(const T& ud): basic_value(ud.template into_toml<TypeConfig>()) {}94599460template<typename T, cxx::enable_if_t<cxx::conjunction<9461detail::has_template_into_toml_method<T, TypeConfig>,9462cxx::negation<detail::has_specialized_into<T>>9463>::value, std::nullptr_t> = nullptr>9464basic_value(const T& ud, std::vector<std::string> com)9465: basic_value(ud.template into_toml<TypeConfig>(), std::move(com))9466{}9467template<typename T, cxx::enable_if_t<cxx::conjunction<9468detail::has_template_into_toml_method<T, TypeConfig>,9469cxx::negation<detail::has_specialized_into<T>>9470>::value, std::nullptr_t> = nullptr>9471basic_value& operator=(const T& ud)9472{9473*this = ud.template into_toml<TypeConfig>();9474#ifdef TOML11_ENABLE_ACCESS_CHECK9475this->accessed_ = false;9476#endif9477return *this;9478}9479// }}}94809481// empty value with region info ======================================= {{{94829483// mainly for `null` extension9484basic_value(detail::none_t, region_type reg) noexcept9485: type_(value_t::empty), empty_('\0'), region_(std::move(reg)), comments_{}9486#ifdef TOML11_ENABLE_ACCESS_CHECK9487, accessed_{false}9488#endif9489{}94909491// }}}94929493// type checking ====================================================== {{{94949495template<typename T, cxx::enable_if_t<9496detail::is_exact_toml_type<cxx::remove_cvref_t<T>, value_type>::value,9497std::nullptr_t> = nullptr>9498bool is() const noexcept9499{9500return this->is(detail::type_to_enum<T, value_type>::value);9501}9502bool is(value_t t) const noexcept9503{9504this->set_accessed();9505return t == this->type_;9506}95079508bool is_empty() const noexcept {return this->is(value_t::empty );}9509bool is_boolean() const noexcept {return this->is(value_t::boolean );}9510bool is_integer() const noexcept {return this->is(value_t::integer );}9511bool is_floating() const noexcept {return this->is(value_t::floating );}9512bool is_string() const noexcept {return this->is(value_t::string );}9513bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);}9514bool is_local_datetime() const noexcept {return this->is(value_t::local_datetime );}9515bool is_local_date() const noexcept {return this->is(value_t::local_date );}9516bool is_local_time() const noexcept {return this->is(value_t::local_time );}9517bool is_array() const noexcept {return this->is(value_t::array );}9518bool is_table() const noexcept {return this->is(value_t::table );}95199520bool is_array_of_tables() const noexcept9521{9522this->set_accessed();9523if( ! this->is_array()) {return false;}9524const auto& a = this->as_array(std::nothrow); // already checked.95259526// when you define [[array.of.tables]], at least one empty table will be9527// assigned. In case of array of inline tables, `array_of_tables = []`,9528// there is no reason to consider this as an array of *tables*.9529// So empty array is not an array-of-tables.9530if(a.empty()) {return false;}95319532// since toml v1.0.0 allows array of heterogeneous types, we need to9533// check all the elements. if any of the elements is not a table, it9534// is a heterogeneous array and cannot be expressed by `[[aot]]` form.9535for(const auto& e : a)9536{9537if( ! e.is_table()) {return false;}9538}9539return true;9540}95419542value_t type() const noexcept9543{9544this->set_accessed();9545return type_;9546}95479548// }}}95499550// as_xxx (noexcept) version ========================================== {{{95519552template<value_t T>9553detail::enum_to_type_t<T, basic_value<config_type>> const&9554as(const std::nothrow_t&) const noexcept9555{9556this->set_accessed();9557return detail::getter<config_type, T>::get_nothrow(*this);9558}9559template<value_t T>9560detail::enum_to_type_t<T, basic_value<config_type>>&9561as(const std::nothrow_t&) noexcept9562{9563this->set_accessed();9564return detail::getter<config_type, T>::get_nothrow(*this);9565}95669567boolean_type const& as_boolean (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->boolean_.value;}9568integer_type const& as_integer (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->integer_.value;}9569floating_type const& as_floating (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->floating_.value;}9570string_type const& as_string (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->string_.value;}9571offset_datetime_type const& as_offset_datetime(const std::nothrow_t&) const noexcept {this->set_accessed(); return this->offset_datetime_.value;}9572local_datetime_type const& as_local_datetime (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_datetime_.value;}9573local_date_type const& as_local_date (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_date_.value;}9574local_time_type const& as_local_time (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_time_.value;}9575array_type const& as_array (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->array_.value.get();}9576table_type const& as_table (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->table_.value.get();}95779578boolean_type & as_boolean (const std::nothrow_t&) noexcept {this->set_accessed(); return this->boolean_.value;}9579integer_type & as_integer (const std::nothrow_t&) noexcept {this->set_accessed(); return this->integer_.value;}9580floating_type & as_floating (const std::nothrow_t&) noexcept {this->set_accessed(); return this->floating_.value;}9581string_type & as_string (const std::nothrow_t&) noexcept {this->set_accessed(); return this->string_.value;}9582offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept {this->set_accessed(); return this->offset_datetime_.value;}9583local_datetime_type & as_local_datetime (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_datetime_.value;}9584local_date_type & as_local_date (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_date_.value;}9585local_time_type & as_local_time (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_time_.value;}9586array_type & as_array (const std::nothrow_t&) noexcept {this->set_accessed(); return this->array_.value.get();}9587table_type & as_table (const std::nothrow_t&) noexcept {this->set_accessed(); return this->table_.value.get();}95889589// }}}95909591// as_xxx (throw) ===================================================== {{{95929593template<value_t T>9594detail::enum_to_type_t<T, basic_value<config_type>> const& as() const9595{9596return detail::getter<config_type, T>::get(*this);9597}9598template<value_t T>9599detail::enum_to_type_t<T, basic_value<config_type>>& as()9600{9601return detail::getter<config_type, T>::get(*this);9602}96039604boolean_type const& as_boolean() const9605{9606if(this->type_ != value_t::boolean)9607{9608this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean);9609}9610this->set_accessed();9611return this->boolean_.value;9612}9613integer_type const& as_integer() const9614{9615if(this->type_ != value_t::integer)9616{9617this->throw_bad_cast("toml::value::as_integer()", value_t::integer);9618}9619this->set_accessed();9620return this->integer_.value;9621}9622floating_type const& as_floating() const9623{9624if(this->type_ != value_t::floating)9625{9626this->throw_bad_cast("toml::value::as_floating()", value_t::floating);9627}9628this->set_accessed();9629return this->floating_.value;9630}9631string_type const& as_string() const9632{9633if(this->type_ != value_t::string)9634{9635this->throw_bad_cast("toml::value::as_string()", value_t::string);9636}9637this->set_accessed();9638return this->string_.value;9639}9640offset_datetime_type const& as_offset_datetime() const9641{9642if(this->type_ != value_t::offset_datetime)9643{9644this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime);9645}9646this->set_accessed();9647return this->offset_datetime_.value;9648}9649local_datetime_type const& as_local_datetime() const9650{9651if(this->type_ != value_t::local_datetime)9652{9653this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime);9654}9655this->set_accessed();9656return this->local_datetime_.value;9657}9658local_date_type const& as_local_date() const9659{9660if(this->type_ != value_t::local_date)9661{9662this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date);9663}9664this->set_accessed();9665return this->local_date_.value;9666}9667local_time_type const& as_local_time() const9668{9669if(this->type_ != value_t::local_time)9670{9671this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time);9672}9673this->set_accessed();9674return this->local_time_.value;9675}9676array_type const& as_array() const9677{9678if(this->type_ != value_t::array)9679{9680this->throw_bad_cast("toml::value::as_array()", value_t::array);9681}9682this->set_accessed();9683return this->array_.value.get();9684}9685table_type const& as_table() const9686{9687if(this->type_ != value_t::table)9688{9689this->throw_bad_cast("toml::value::as_table()", value_t::table);9690}9691this->set_accessed();9692return this->table_.value.get();9693}96949695// ------------------------------------------------------------------------9696// nonconst reference96979698boolean_type& as_boolean()9699{9700if(this->type_ != value_t::boolean)9701{9702this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean);9703}9704this->set_accessed();9705return this->boolean_.value;9706}9707integer_type& as_integer()9708{9709if(this->type_ != value_t::integer)9710{9711this->throw_bad_cast("toml::value::as_integer()", value_t::integer);9712}9713this->set_accessed();9714return this->integer_.value;9715}9716floating_type& as_floating()9717{9718if(this->type_ != value_t::floating)9719{9720this->throw_bad_cast("toml::value::as_floating()", value_t::floating);9721}9722this->set_accessed();9723return this->floating_.value;9724}9725string_type& as_string()9726{9727if(this->type_ != value_t::string)9728{9729this->throw_bad_cast("toml::value::as_string()", value_t::string);9730}9731this->set_accessed();9732return this->string_.value;9733}9734offset_datetime_type& as_offset_datetime()9735{9736if(this->type_ != value_t::offset_datetime)9737{9738this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime);9739}9740this->set_accessed();9741return this->offset_datetime_.value;9742}9743local_datetime_type& as_local_datetime()9744{9745if(this->type_ != value_t::local_datetime)9746{9747this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime);9748}9749this->set_accessed();9750return this->local_datetime_.value;9751}9752local_date_type& as_local_date()9753{9754if(this->type_ != value_t::local_date)9755{9756this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date);9757}9758this->set_accessed();9759return this->local_date_.value;9760}9761local_time_type& as_local_time()9762{9763if(this->type_ != value_t::local_time)9764{9765this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time);9766}9767this->set_accessed();9768return this->local_time_.value;9769}9770array_type& as_array()9771{9772if(this->type_ != value_t::array)9773{9774this->throw_bad_cast("toml::value::as_array()", value_t::array);9775}9776this->set_accessed();9777return this->array_.value.get();9778}9779table_type& as_table()9780{9781if(this->type_ != value_t::table)9782{9783this->throw_bad_cast("toml::value::as_table()", value_t::table);9784}9785this->set_accessed();9786return this->table_.value.get();9787}97889789// }}}97909791// format accessors (noexcept) ======================================== {{{97929793template<value_t T>9794detail::enum_to_fmt_type_t<T> const&9795as_fmt(const std::nothrow_t&) const noexcept9796{9797return detail::getter<config_type, T>::get_fmt_nothrow(*this);9798}9799template<value_t T>9800detail::enum_to_fmt_type_t<T>&9801as_fmt(const std::nothrow_t&) noexcept9802{9803return detail::getter<config_type, T>::get_fmt_nothrow(*this);9804}98059806boolean_format_info & as_boolean_fmt (const std::nothrow_t&) noexcept {return this->boolean_.format;}9807integer_format_info & as_integer_fmt (const std::nothrow_t&) noexcept {return this->integer_.format;}9808floating_format_info & as_floating_fmt (const std::nothrow_t&) noexcept {return this->floating_.format;}9809string_format_info & as_string_fmt (const std::nothrow_t&) noexcept {return this->string_.format;}9810offset_datetime_format_info& as_offset_datetime_fmt(const std::nothrow_t&) noexcept {return this->offset_datetime_.format;}9811local_datetime_format_info & as_local_datetime_fmt (const std::nothrow_t&) noexcept {return this->local_datetime_.format;}9812local_date_format_info & as_local_date_fmt (const std::nothrow_t&) noexcept {return this->local_date_.format;}9813local_time_format_info & as_local_time_fmt (const std::nothrow_t&) noexcept {return this->local_time_.format;}9814array_format_info & as_array_fmt (const std::nothrow_t&) noexcept {return this->array_.format;}9815table_format_info & as_table_fmt (const std::nothrow_t&) noexcept {return this->table_.format;}98169817boolean_format_info const& as_boolean_fmt (const std::nothrow_t&) const noexcept {return this->boolean_.format;}9818integer_format_info const& as_integer_fmt (const std::nothrow_t&) const noexcept {return this->integer_.format;}9819floating_format_info const& as_floating_fmt (const std::nothrow_t&) const noexcept {return this->floating_.format;}9820string_format_info const& as_string_fmt (const std::nothrow_t&) const noexcept {return this->string_.format;}9821offset_datetime_format_info const& as_offset_datetime_fmt(const std::nothrow_t&) const noexcept {return this->offset_datetime_.format;}9822local_datetime_format_info const& as_local_datetime_fmt (const std::nothrow_t&) const noexcept {return this->local_datetime_.format;}9823local_date_format_info const& as_local_date_fmt (const std::nothrow_t&) const noexcept {return this->local_date_.format;}9824local_time_format_info const& as_local_time_fmt (const std::nothrow_t&) const noexcept {return this->local_time_.format;}9825array_format_info const& as_array_fmt (const std::nothrow_t&) const noexcept {return this->array_.format;}9826table_format_info const& as_table_fmt (const std::nothrow_t&) const noexcept {return this->table_.format;}98279828// }}}98299830// format accessors (throw) =========================================== {{{98319832template<value_t T>9833detail::enum_to_fmt_type_t<T> const& as_fmt() const9834{9835return detail::getter<config_type, T>::get_fmt(*this);9836}9837template<value_t T>9838detail::enum_to_fmt_type_t<T>& as_fmt()9839{9840return detail::getter<config_type, T>::get_fmt(*this);9841}98429843boolean_format_info const& as_boolean_fmt() const9844{9845if(this->type_ != value_t::boolean)9846{9847this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean);9848}9849return this->boolean_.format;9850}9851integer_format_info const& as_integer_fmt() const9852{9853if(this->type_ != value_t::integer)9854{9855this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer);9856}9857return this->integer_.format;9858}9859floating_format_info const& as_floating_fmt() const9860{9861if(this->type_ != value_t::floating)9862{9863this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating);9864}9865return this->floating_.format;9866}9867string_format_info const& as_string_fmt() const9868{9869if(this->type_ != value_t::string)9870{9871this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string);9872}9873return this->string_.format;9874}9875offset_datetime_format_info const& as_offset_datetime_fmt() const9876{9877if(this->type_ != value_t::offset_datetime)9878{9879this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime);9880}9881return this->offset_datetime_.format;9882}9883local_datetime_format_info const& as_local_datetime_fmt() const9884{9885if(this->type_ != value_t::local_datetime)9886{9887this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime);9888}9889return this->local_datetime_.format;9890}9891local_date_format_info const& as_local_date_fmt() const9892{9893if(this->type_ != value_t::local_date)9894{9895this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date);9896}9897return this->local_date_.format;9898}9899local_time_format_info const& as_local_time_fmt() const9900{9901if(this->type_ != value_t::local_time)9902{9903this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time);9904}9905return this->local_time_.format;9906}9907array_format_info const& as_array_fmt() const9908{9909if(this->type_ != value_t::array)9910{9911this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array);9912}9913return this->array_.format;9914}9915table_format_info const& as_table_fmt() const9916{9917if(this->type_ != value_t::table)9918{9919this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table);9920}9921return this->table_.format;9922}99239924// ------------------------------------------------------------------------9925// nonconst reference99269927boolean_format_info& as_boolean_fmt()9928{9929if(this->type_ != value_t::boolean)9930{9931this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean);9932}9933return this->boolean_.format;9934}9935integer_format_info& as_integer_fmt()9936{9937if(this->type_ != value_t::integer)9938{9939this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer);9940}9941return this->integer_.format;9942}9943floating_format_info& as_floating_fmt()9944{9945if(this->type_ != value_t::floating)9946{9947this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating);9948}9949return this->floating_.format;9950}9951string_format_info& as_string_fmt()9952{9953if(this->type_ != value_t::string)9954{9955this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string);9956}9957return this->string_.format;9958}9959offset_datetime_format_info& as_offset_datetime_fmt()9960{9961if(this->type_ != value_t::offset_datetime)9962{9963this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime);9964}9965return this->offset_datetime_.format;9966}9967local_datetime_format_info& as_local_datetime_fmt()9968{9969if(this->type_ != value_t::local_datetime)9970{9971this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime);9972}9973return this->local_datetime_.format;9974}9975local_date_format_info& as_local_date_fmt()9976{9977if(this->type_ != value_t::local_date)9978{9979this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date);9980}9981return this->local_date_.format;9982}9983local_time_format_info& as_local_time_fmt()9984{9985if(this->type_ != value_t::local_time)9986{9987this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time);9988}9989return this->local_time_.format;9990}9991array_format_info& as_array_fmt()9992{9993if(this->type_ != value_t::array)9994{9995this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array);9996}9997return this->array_.format;9998}9999table_format_info& as_table_fmt()10000{10001if(this->type_ != value_t::table)10002{10003this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table);10004}10005return this->table_.format;10006}10007// }}}1000810009// table accessors ==================================================== {{{1001010011value_type& at(const key_type& k)10012{10013if(!this->is_table())10014{10015this->throw_bad_cast("toml::value::at(key_type)", value_t::table);10016}10017auto& table = this->as_table(std::nothrow);10018const auto found = table.find(k);10019if(found == table.end())10020{10021this->throw_key_not_found_error("toml::value::at", k);10022}10023assert(found->first == k);10024return found->second;10025}10026value_type const& at(const key_type& k) const10027{10028if(!this->is_table())10029{10030this->throw_bad_cast("toml::value::at(key_type)", value_t::table);10031}10032const auto& table = this->as_table(std::nothrow);10033const auto found = table.find(k);10034if(found == table.end())10035{10036this->throw_key_not_found_error("toml::value::at", k);10037}10038assert(found->first == k);10039return found->second;10040}10041value_type& operator[](const key_type& k)10042{10043if(this->is_empty())10044{10045(*this) = table_type{};10046}10047else if( ! this->is_table()) // initialized, but not a table10048{10049this->throw_bad_cast("toml::value::operator[](key_type)", value_t::table);10050}10051return (this->as_table(std::nothrow))[k];10052}10053std::size_t count(const key_type& k) const10054{10055if(!this->is_table())10056{10057this->throw_bad_cast("toml::value::count(key_type)", value_t::table);10058}10059return this->as_table(std::nothrow).count(k);10060}10061bool contains(const key_type& k) const10062{10063if(!this->is_table())10064{10065this->throw_bad_cast("toml::value::contains(key_type)", value_t::table);10066}10067const auto& table = this->as_table(std::nothrow);10068return table.find(k) != table.end();10069}10070// }}}1007110072// array accessors ==================================================== {{{1007310074value_type& at(const std::size_t idx)10075{10076if(!this->is_array())10077{10078this->throw_bad_cast("toml::value::at(idx)", value_t::array);10079}10080auto& ar = this->as_array(std::nothrow);1008110082if(ar.size() <= idx)10083{10084std::ostringstream oss;10085oss << "actual length (" << ar.size()10086<< ") is shorter than the specified index (" << idx << ").";10087throw std::out_of_range(format_error(10088"toml::value::at(idx): no element corresponding to the index",10089this->location(), oss.str()10090));10091}10092return ar.at(idx);10093}10094value_type const& at(const std::size_t idx) const10095{10096if(!this->is_array())10097{10098this->throw_bad_cast("toml::value::at(idx)", value_t::array);10099}10100const auto& ar = this->as_array(std::nothrow);1010110102if(ar.size() <= idx)10103{10104std::ostringstream oss;10105oss << "actual length (" << ar.size()10106<< ") is shorter than the specified index (" << idx << ").";1010710108throw std::out_of_range(format_error(10109"toml::value::at(idx): no element corresponding to the index",10110this->location(), oss.str()10111));10112}10113return ar.at(idx);10114}1011510116value_type& operator[](const std::size_t idx) noexcept10117{10118// no check...10119return this->as_array(std::nothrow)[idx];10120}10121value_type const& operator[](const std::size_t idx) const noexcept10122{10123// no check...10124return this->as_array(std::nothrow)[idx];10125}1012610127void push_back(const value_type& x)10128{10129if(!this->is_array())10130{10131this->throw_bad_cast("toml::value::push_back(idx)", value_t::array);10132}10133this->as_array(std::nothrow).push_back(x);10134return;10135}10136void push_back(value_type&& x)10137{10138if(!this->is_array())10139{10140this->throw_bad_cast("toml::value::push_back(idx)", value_t::array);10141}10142this->as_array(std::nothrow).push_back(std::move(x));10143return;10144}1014510146template<typename ... Ts>10147value_type& emplace_back(Ts&& ... args)10148{10149if(!this->is_array())10150{10151this->throw_bad_cast("toml::value::emplace_back(idx)", value_t::array);10152}10153auto& ar = this->as_array(std::nothrow);10154ar.emplace_back(std::forward<Ts>(args) ...);10155return ar.back();10156}1015710158std::size_t size() const10159{10160switch(this->type_)10161{10162case value_t::array:10163{10164return this->as_array(std::nothrow).size();10165}10166case value_t::table:10167{10168return this->as_table(std::nothrow).size();10169}10170case value_t::string:10171{10172return this->as_string(std::nothrow).size();10173}10174default:10175{10176throw type_error(format_error(10177"toml::value::size(): bad_cast to container types",10178this->location(),10179"the actual type is " + to_string(this->type_)10180), this->location());10181}10182}10183}1018410185// }}}1018610187source_location location() const10188{10189return source_location(this->region_);10190}1019110192comment_type const& comments() const noexcept {return this->comments_;}10193comment_type& comments() noexcept {return this->comments_;}1019410195#ifdef TOML11_ENABLE_ACCESS_CHECK10196bool accessed() const {return this->accessed_.load();}10197#endif1019810199private:1020010201// private helper functions =========================================== {{{1020210203void set_accessed() const noexcept10204{10205#ifdef TOML11_ENABLE_ACCESS_CHECK10206this->accessed_.store(true);10207#endif10208return;10209}1021010211void cleanup() noexcept10212{10213switch(this->type_)10214{10215case value_t::boolean : { boolean_ .~boolean_storage (); break; }10216case value_t::integer : { integer_ .~integer_storage (); break; }10217case value_t::floating : { floating_ .~floating_storage (); break; }10218case value_t::string : { string_ .~string_storage (); break; }10219case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); break; }10220case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); break; }10221case value_t::local_date : { local_date_ .~local_date_storage (); break; }10222case value_t::local_time : { local_time_ .~local_time_storage (); break; }10223case value_t::array : { array_ .~array_storage (); break; }10224case value_t::table : { table_ .~table_storage (); break; }10225default : { break; }10226}10227#ifdef TOML11_ENABLE_ACCESS_CHECK10228this->accessed_ = false;10229#endif10230this->type_ = value_t::empty;10231return;10232}1023310234template<typename T, typename U>10235static void assigner(T& dst, U&& v)10236{10237const auto tmp = ::new(std::addressof(dst)) T(std::forward<U>(v));10238assert(tmp == std::addressof(dst));10239(void)tmp;10240}1024110242[[noreturn]]10243void throw_bad_cast(const std::string& funcname, const value_t ty) const10244{10245throw type_error(format_error(detail::make_type_error(*this, funcname, ty)),10246this->location());10247}1024810249[[noreturn]]10250void throw_key_not_found_error(const std::string& funcname, const key_type& key) const10251{10252throw std::out_of_range(format_error(10253detail::make_not_found_error(*this, funcname, key)));10254}1025510256template<typename TC>10257friend void detail::change_region_of_value(basic_value<TC>&, const basic_value<TC>&);1025810259template<typename TC>10260friend class basic_value;102611026210263#ifdef TOML11_ENABLE_ACCESS_CHECK10264template<typename TC>10265friend void detail::unset_access_flag(basic_value<TC>&);10266#endif1026710268// }}}1026910270private:1027110272using boolean_storage = detail::value_with_format<boolean_type, boolean_format_info >;10273using integer_storage = detail::value_with_format<integer_type, integer_format_info >;10274using floating_storage = detail::value_with_format<floating_type, floating_format_info >;10275using string_storage = detail::value_with_format<string_type, string_format_info >;10276using offset_datetime_storage = detail::value_with_format<offset_datetime_type, offset_datetime_format_info>;10277using local_datetime_storage = detail::value_with_format<local_datetime_type, local_datetime_format_info >;10278using local_date_storage = detail::value_with_format<local_date_type, local_date_format_info >;10279using local_time_storage = detail::value_with_format<local_time_type, local_time_format_info >;10280using array_storage = detail::value_with_format<detail::storage<array_type>, array_format_info >;10281using table_storage = detail::value_with_format<detail::storage<table_type>, table_format_info >;1028210283private:1028410285value_t type_;10286union10287{10288char empty_; // the smallest type10289boolean_storage boolean_;10290integer_storage integer_;10291floating_storage floating_;10292string_storage string_;10293offset_datetime_storage offset_datetime_;10294local_datetime_storage local_datetime_;10295local_date_storage local_date_;10296local_time_storage local_time_;10297array_storage array_;10298table_storage table_;10299};10300region_type region_;10301comment_type comments_;1030210303#ifdef TOML11_ENABLE_ACCESS_CHECK10304mutable std::atomic<bool> accessed_;10305#endif10306};1030710308template<typename TC>10309bool operator==(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10310{10311if(lhs.type() != rhs.type()) {return false;}10312if(lhs.comments() != rhs.comments()) {return false;}1031310314switch(lhs.type())10315{10316case value_t::boolean :10317{10318return lhs.as_boolean() == rhs.as_boolean();10319}10320case value_t::integer :10321{10322return lhs.as_integer() == rhs.as_integer();10323}10324case value_t::floating :10325{10326return lhs.as_floating() == rhs.as_floating();10327}10328case value_t::string :10329{10330return lhs.as_string() == rhs.as_string();10331}10332case value_t::offset_datetime:10333{10334return lhs.as_offset_datetime() == rhs.as_offset_datetime();10335}10336case value_t::local_datetime:10337{10338return lhs.as_local_datetime() == rhs.as_local_datetime();10339}10340case value_t::local_date:10341{10342return lhs.as_local_date() == rhs.as_local_date();10343}10344case value_t::local_time:10345{10346return lhs.as_local_time() == rhs.as_local_time();10347}10348case value_t::array :10349{10350return lhs.as_array() == rhs.as_array();10351}10352case value_t::table :10353{10354return lhs.as_table() == rhs.as_table();10355}10356case value_t::empty : {return true; }10357default: {return false;}10358}10359}1036010361template<typename TC>10362bool operator!=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10363{10364return !(lhs == rhs);10365}1036610367template<typename TC>10368cxx::enable_if_t<cxx::conjunction<10369detail::is_comparable<typename basic_value<TC>::array_type>,10370detail::is_comparable<typename basic_value<TC>::table_type>10371>::value, bool>10372operator<(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10373{10374if(lhs.type() != rhs.type())10375{10376return (lhs.type() < rhs.type());10377}10378switch(lhs.type())10379{10380case value_t::boolean :10381{10382return lhs.as_boolean() < rhs.as_boolean() ||10383(lhs.as_boolean() == rhs.as_boolean() &&10384lhs.comments() < rhs.comments());10385}10386case value_t::integer :10387{10388return lhs.as_integer() < rhs.as_integer() ||10389(lhs.as_integer() == rhs.as_integer() &&10390lhs.comments() < rhs.comments());10391}10392case value_t::floating :10393{10394return lhs.as_floating() < rhs.as_floating() ||10395(lhs.as_floating() == rhs.as_floating() &&10396lhs.comments() < rhs.comments());10397}10398case value_t::string :10399{10400return lhs.as_string() < rhs.as_string() ||10401(lhs.as_string() == rhs.as_string() &&10402lhs.comments() < rhs.comments());10403}10404case value_t::offset_datetime:10405{10406return lhs.as_offset_datetime() < rhs.as_offset_datetime() ||10407(lhs.as_offset_datetime() == rhs.as_offset_datetime() &&10408lhs.comments() < rhs.comments());10409}10410case value_t::local_datetime:10411{10412return lhs.as_local_datetime() < rhs.as_local_datetime() ||10413(lhs.as_local_datetime() == rhs.as_local_datetime() &&10414lhs.comments() < rhs.comments());10415}10416case value_t::local_date:10417{10418return lhs.as_local_date() < rhs.as_local_date() ||10419(lhs.as_local_date() == rhs.as_local_date() &&10420lhs.comments() < rhs.comments());10421}10422case value_t::local_time:10423{10424return lhs.as_local_time() < rhs.as_local_time() ||10425(lhs.as_local_time() == rhs.as_local_time() &&10426lhs.comments() < rhs.comments());10427}10428case value_t::array :10429{10430return lhs.as_array() < rhs.as_array() ||10431(lhs.as_array() == rhs.as_array() &&10432lhs.comments() < rhs.comments());10433}10434case value_t::table :10435{10436return lhs.as_table() < rhs.as_table() ||10437(lhs.as_table() == rhs.as_table() &&10438lhs.comments() < rhs.comments());10439}10440case value_t::empty :10441{10442return lhs.comments() < rhs.comments();10443}10444default:10445{10446return lhs.comments() < rhs.comments();10447}10448}10449}1045010451template<typename TC>10452cxx::enable_if_t<cxx::conjunction<10453detail::is_comparable<typename basic_value<TC>::array_type>,10454detail::is_comparable<typename basic_value<TC>::table_type>10455>::value, bool>10456operator<=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10457{10458return (lhs < rhs) || (lhs == rhs);10459}10460template<typename TC>10461cxx::enable_if_t<cxx::conjunction<10462detail::is_comparable<typename basic_value<TC>::array_type>,10463detail::is_comparable<typename basic_value<TC>::table_type>10464>::value, bool>10465operator>(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10466{10467return !(lhs <= rhs);10468}10469template<typename TC>10470cxx::enable_if_t<cxx::conjunction<10471detail::is_comparable<typename basic_value<TC>::array_type>,10472detail::is_comparable<typename basic_value<TC>::table_type>10473>::value, bool>10474operator>=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)10475{10476return !(lhs < rhs);10477}1047810479// error_info helper10480namespace detail10481{10482template<typename TC, typename ... Ts>10483error_info make_error_info_rec(error_info e,10484const basic_value<TC>& v, std::string msg, Ts&& ... tail)10485{10486return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward<Ts>(tail)...);10487}10488} // detail1048910490template<typename TC, typename ... Ts>10491error_info make_error_info(10492std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)10493{10494return make_error_info(std::move(title),10495v.location(), std::move(msg), std::forward<Ts>(tail)...);10496}10497template<typename TC, typename ... Ts>10498std::string format_error(std::string title,10499const basic_value<TC>& v, std::string msg, Ts&& ... tail)10500{10501return format_error(std::move(title),10502v.location(), std::move(msg), std::forward<Ts>(tail)...);10503}1050410505namespace detail10506{1050710508template<typename TC>10509error_info make_type_error(const basic_value<TC>& v, const std::string& fname, const value_t ty)10510{10511return make_error_info(fname + ": bad_cast to " + to_string(ty),10512v.location(), "the actual type is " + to_string(v.type()));10513}10514template<typename TC>10515error_info make_not_found_error(const basic_value<TC>& v, const std::string& fname, const typename basic_value<TC>::key_type& key)10516{10517const auto loc = v.location();10518const std::string title = fname + ": key \"" + string_conv<std::string>(key) + "\" not found";1051910520std::vector<std::pair<source_location, std::string>> locs;10521if( ! loc.is_ok())10522{10523return error_info(title, locs);10524}1052510526if(loc.first_line_number() == 1 && loc.first_column_number() == 1 && loc.length() == 1)10527{10528// The top-level table has its region at the 0th character of the file.10529// That means that, in the case when a key is not found in the top-level10530// table, the error message points to the first character. If the file has10531// the first table at the first line, the error message would be like this.10532// ```console10533// [error] key "a" not found10534// --> example.toml10535// |10536// 1 | [table]10537// | ^------ in this table10538// ```10539// It actually points to the top-level table at the first character, not10540// `[table]`. But it is too confusing. To avoid the confusion, the error10541// message should explicitly say "key not found in the top-level table".10542locs.emplace_back(v.location(), "at the top-level table");10543}10544else10545{10546locs.emplace_back(v.location(), "in this table");10547}10548return error_info(title, locs);10549}1055010551#define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \10552template<typename TC> \10553struct getter<TC, value_t::ty> \10554{ \10555using value_type = basic_value<TC>; \10556using result_type = enum_to_type_t<value_t::ty, value_type>; \10557using format_type = enum_to_fmt_type_t<value_t::ty>; \10558\10559static result_type& get(value_type& v) \10560{ \10561return v.as_ ## ty(); \10562} \10563static result_type const& get(const value_type& v) \10564{ \10565return v.as_ ## ty(); \10566} \10567\10568static result_type& get_nothrow(value_type& v) noexcept \10569{ \10570return v.as_ ## ty(std::nothrow); \10571} \10572static result_type const& get_nothrow(const value_type& v) noexcept \10573{ \10574return v.as_ ## ty(std::nothrow); \10575} \10576\10577static format_type& get_fmt(value_type& v) \10578{ \10579return v.as_ ## ty ## _fmt(); \10580} \10581static format_type const& get_fmt(const value_type& v) \10582{ \10583return v.as_ ## ty ## _fmt(); \10584} \10585\10586static format_type& get_fmt_nothrow(value_type& v) noexcept \10587{ \10588return v.as_ ## ty ## _fmt(std::nothrow); \10589} \10590static format_type const& get_fmt_nothrow(const value_type& v) noexcept \10591{ \10592return v.as_ ## ty ## _fmt(std::nothrow); \10593} \10594};1059510596TOML11_DETAIL_GENERATE_COMPTIME_GETTER(boolean )10597TOML11_DETAIL_GENERATE_COMPTIME_GETTER(integer )10598TOML11_DETAIL_GENERATE_COMPTIME_GETTER(floating )10599TOML11_DETAIL_GENERATE_COMPTIME_GETTER(string )10600TOML11_DETAIL_GENERATE_COMPTIME_GETTER(offset_datetime)10601TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_datetime )10602TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_date )10603TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_time )10604TOML11_DETAIL_GENERATE_COMPTIME_GETTER(array )10605TOML11_DETAIL_GENERATE_COMPTIME_GETTER(table )1060610607#undef TOML11_DETAIL_GENERATE_COMPTIME_GETTER1060810609template<typename TC>10610void change_region_of_value(basic_value<TC>& dst, const basic_value<TC>& src)10611{10612dst.region_ = std::move(src.region_);10613return;10614}1061510616#ifdef TOML11_ENABLE_ACCESS_CHECK10617template<typename TC>10618void unset_access_flag(basic_value<TC>& v)10619{10620v.accessed_.store(false);10621}1062210623template<typename TC>10624void unset_access_flag_recursively(basic_value<TC>& v)10625{10626switch(v.type())10627{10628case value_t::empty : { return unset_access_flag(v); }10629case value_t::boolean : { return unset_access_flag(v); }10630case value_t::integer : { return unset_access_flag(v); }10631case value_t::floating : { return unset_access_flag(v); }10632case value_t::string : { return unset_access_flag(v); }10633case value_t::offset_datetime : { return unset_access_flag(v); }10634case value_t::local_datetime : { return unset_access_flag(v); }10635case value_t::local_date : { return unset_access_flag(v); }10636case value_t::local_time : { return unset_access_flag(v); }10637case value_t::array:10638{10639for(auto& elem : v.as_array())10640{10641unset_access_flag_recursively(elem);10642}10643return unset_access_flag(v);10644}10645case value_t::table:10646{10647for(auto& kv : v.as_table())10648{10649unset_access_flag_recursively(kv.second);10650}10651return unset_access_flag(v);10652}10653default: { return unset_access_flag(v); }10654}10655}10656#endif1065710658} // namespace detail10659} // TOML11_INLINE_VERSION_NAMESPACE10660} // namespace toml10661#endif // TOML11_VALUE_HPP10662#ifndef TOML11_VISIT_HPP10663#define TOML11_VISIT_HPP106641066510666namespace toml10667{10668inline namespace TOML11_INLINE_VERSION_NAMESPACE10669{1067010671namespace detail10672{1067310674template<typename F, typename ... Ts>10675using visit_result_t = decltype(std::declval<F>()(std::declval<Ts>().as_boolean() ...));1067610677template<typename F, typename T>10678struct front_binder10679{10680template<typename ... Args>10681auto operator()(Args&& ... args) -> decltype(std::declval<F>()(std::declval<T>(), std::forward<Args>(args)...))10682{10683return func(std::move(front), std::forward<Args>(args)...);10684}10685F func;10686T front;10687};1068810689template<typename F, typename T>10690front_binder<cxx::remove_cvref_t<F>, cxx::remove_cvref_t<T>>10691bind_front(F&& f, T&& t)10692{10693return front_binder<cxx::remove_cvref_t<F>, cxx::remove_cvref_t<T>>{10694std::forward<F>(f), std::forward<T>(t)10695};10696}1069710698template<typename Visitor, typename TC, typename ... Args>10699visit_result_t<Visitor, const basic_value<TC>&, Args...>10700visit_impl(Visitor&& visitor, const basic_value<TC>& v, Args&& ... args);1070110702template<typename Visitor, typename TC, typename ... Args>10703visit_result_t<Visitor, basic_value<TC>&, Args...>10704visit_impl(Visitor&& visitor, basic_value<TC>& v, Args&& ... args);1070510706template<typename Visitor, typename TC, typename ... Args>10707visit_result_t<Visitor, basic_value<TC>, Args...>10708visit_impl(Visitor&& visitor, basic_value<TC>&& v, Args&& ... args);107091071010711template<typename Visitor>10712visit_result_t<Visitor> visit_impl(Visitor&& visitor)10713{10714return visitor();10715}1071610717template<typename Visitor, typename TC, typename ... Args>10718visit_result_t<Visitor, basic_value<TC>&, Args...>10719visit_impl(Visitor&& visitor, basic_value<TC>& v, Args&& ... args)10720{10721switch(v.type())10722{10723case value_t::boolean : {return visit_impl(bind_front(visitor, std::ref(v.as_boolean ())), std::forward<Args>(args)...);}10724case value_t::integer : {return visit_impl(bind_front(visitor, std::ref(v.as_integer ())), std::forward<Args>(args)...);}10725case value_t::floating : {return visit_impl(bind_front(visitor, std::ref(v.as_floating ())), std::forward<Args>(args)...);}10726case value_t::string : {return visit_impl(bind_front(visitor, std::ref(v.as_string ())), std::forward<Args>(args)...);}10727case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::ref(v.as_offset_datetime())), std::forward<Args>(args)...);}10728case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::ref(v.as_local_datetime ())), std::forward<Args>(args)...);}10729case value_t::local_date : {return visit_impl(bind_front(visitor, std::ref(v.as_local_date ())), std::forward<Args>(args)...);}10730case value_t::local_time : {return visit_impl(bind_front(visitor, std::ref(v.as_local_time ())), std::forward<Args>(args)...);}10731case value_t::array : {return visit_impl(bind_front(visitor, std::ref(v.as_array ())), std::forward<Args>(args)...);}10732case value_t::table : {return visit_impl(bind_front(visitor, std::ref(v.as_table ())), std::forward<Args>(args)...);}10733case value_t::empty : break;10734default: break;10735}10736throw type_error(format_error("[error] toml::visit: toml::basic_value "10737"does not have any valid type.", v.location(), "here"), v.location());10738}1073910740template<typename Visitor, typename TC, typename ... Args>10741visit_result_t<Visitor, const basic_value<TC>&, Args...>10742visit_impl(Visitor&& visitor, const basic_value<TC>& v, Args&& ... args)10743{10744switch(v.type())10745{10746case value_t::boolean : {return visit_impl(bind_front(visitor, std::cref(v.as_boolean ())), std::forward<Args>(args)...);}10747case value_t::integer : {return visit_impl(bind_front(visitor, std::cref(v.as_integer ())), std::forward<Args>(args)...);}10748case value_t::floating : {return visit_impl(bind_front(visitor, std::cref(v.as_floating ())), std::forward<Args>(args)...);}10749case value_t::string : {return visit_impl(bind_front(visitor, std::cref(v.as_string ())), std::forward<Args>(args)...);}10750case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::cref(v.as_offset_datetime())), std::forward<Args>(args)...);}10751case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::cref(v.as_local_datetime ())), std::forward<Args>(args)...);}10752case value_t::local_date : {return visit_impl(bind_front(visitor, std::cref(v.as_local_date ())), std::forward<Args>(args)...);}10753case value_t::local_time : {return visit_impl(bind_front(visitor, std::cref(v.as_local_time ())), std::forward<Args>(args)...);}10754case value_t::array : {return visit_impl(bind_front(visitor, std::cref(v.as_array ())), std::forward<Args>(args)...);}10755case value_t::table : {return visit_impl(bind_front(visitor, std::cref(v.as_table ())), std::forward<Args>(args)...);}10756case value_t::empty : break;10757default: break;10758}10759throw type_error(format_error("[error] toml::visit: toml::basic_value "10760"does not have any valid type.", v.location(), "here"), v.location());10761}1076210763template<typename Visitor, typename TC, typename ... Args>10764visit_result_t<Visitor, basic_value<TC>, Args...>10765visit_impl(Visitor&& visitor, basic_value<TC>&& v, Args&& ... args)10766{10767switch(v.type())10768{10769case value_t::boolean : {return visit_impl(bind_front(visitor, std::move(v.as_boolean ())), std::forward<Args>(args)...);}10770case value_t::integer : {return visit_impl(bind_front(visitor, std::move(v.as_integer ())), std::forward<Args>(args)...);}10771case value_t::floating : {return visit_impl(bind_front(visitor, std::move(v.as_floating ())), std::forward<Args>(args)...);}10772case value_t::string : {return visit_impl(bind_front(visitor, std::move(v.as_string ())), std::forward<Args>(args)...);}10773case value_t::offset_datetime: {return visit_impl(bind_front(visitor, std::move(v.as_offset_datetime())), std::forward<Args>(args)...);}10774case value_t::local_datetime : {return visit_impl(bind_front(visitor, std::move(v.as_local_datetime ())), std::forward<Args>(args)...);}10775case value_t::local_date : {return visit_impl(bind_front(visitor, std::move(v.as_local_date ())), std::forward<Args>(args)...);}10776case value_t::local_time : {return visit_impl(bind_front(visitor, std::move(v.as_local_time ())), std::forward<Args>(args)...);}10777case value_t::array : {return visit_impl(bind_front(visitor, std::move(v.as_array ())), std::forward<Args>(args)...);}10778case value_t::table : {return visit_impl(bind_front(visitor, std::move(v.as_table ())), std::forward<Args>(args)...);}10779case value_t::empty : break;10780default: break;10781}10782throw type_error(format_error("[error] toml::visit: toml::basic_value "10783"does not have any valid type.", v.location(), "here"), v.location());10784}1078510786} // detail1078710788template<typename Visitor, typename ... Args>10789detail::visit_result_t<Visitor, Args...>10790visit(Visitor&& visitor, Args&& ... args)10791{10792return detail::visit_impl(std::forward<Visitor>(visitor), std::forward<Args>(args)...);10793}1079410795} // TOML11_INLINE_VERSION_NAMESPACE10796} // toml10797#endif // TOML11_VISIT_HPP10798#ifndef TOML11_TYPES_HPP10799#define TOML11_TYPES_HPP108001080110802#include <ostream>10803#include <sstream>10804#include <string>10805#include <type_traits>10806#include <unordered_map>10807#include <vector>1080810809#include <cstdint>10810#include <cstdio>1081110812namespace toml10813{10814inline namespace TOML11_INLINE_VERSION_NAMESPACE10815{1081610817// forward decl10818template<typename TypeConfig>10819class basic_value;1082010821// when you use a special integer type as toml::value::integer_type, parse must10822// be able to read it. So, type_config has static member functions that read the10823// integer_type as {dec, hex, oct, bin}-integer. But, in most cases, operator<<10824// is enough. To make config easy, we provide the default read functions.10825//10826// Before this functions is called, syntax is checked and prefix(`0x` etc) and10827// spacer(`_`) are removed.1082810829template<typename T>10830result<T, error_info>10831read_dec_int(const std::string& str, const source_location src)10832{10833constexpr auto max_digits = std::numeric_limits<T>::digits;10834assert( ! str.empty());1083510836T val{0};10837std::istringstream iss(str);10838iss >> val;10839if(iss.fail())10840{10841return err(make_error_info("toml::parse_dec_integer: "10842"too large integer: current max digits = 2^" + std::to_string(max_digits),10843std::move(src), "must be < 2^" + std::to_string(max_digits)));10844}10845return ok(val);10846}1084710848template<typename T>10849result<T, error_info>10850read_hex_int(const std::string& str, const source_location src)10851{10852constexpr auto max_digits = std::numeric_limits<T>::digits;10853assert( ! str.empty());1085410855T val{0};10856std::istringstream iss(str);10857iss >> std::hex >> val;10858if(iss.fail())10859{10860return err(make_error_info("toml::parse_hex_integer: "10861"too large integer: current max value = 2^" + std::to_string(max_digits),10862std::move(src), "must be < 2^" + std::to_string(max_digits)));10863}10864return ok(val);10865}1086610867template<typename T>10868result<T, error_info>10869read_oct_int(const std::string& str, const source_location src)10870{10871constexpr auto max_digits = std::numeric_limits<T>::digits;10872assert( ! str.empty());1087310874T val{0};10875std::istringstream iss(str);10876iss >> std::oct >> val;10877if(iss.fail())10878{10879return err(make_error_info("toml::parse_oct_integer: "10880"too large integer: current max value = 2^" + std::to_string(max_digits),10881std::move(src), "must be < 2^" + std::to_string(max_digits)));10882}10883return ok(val);10884}1088510886template<typename T>10887result<T, error_info>10888read_bin_int(const std::string& str, const source_location src)10889{10890constexpr auto is_bounded = std::numeric_limits<T>::is_bounded;10891constexpr auto max_digits = std::numeric_limits<T>::digits;10892const auto max_value = (std::numeric_limits<T>::max)();1089310894T val{0};10895T base{1};10896for(auto i = str.rbegin(); i != str.rend(); ++i)10897{10898const auto c = *i;10899if(c == '1')10900{10901val += base;10902// prevent `base` from overflow10903if(is_bounded && max_value / 2 < base && std::next(i) != str.rend())10904{10905base = 0;10906}10907else10908{10909base *= 2;10910}10911}10912else10913{10914assert(c == '0');1091510916if(is_bounded && max_value / 2 < base && std::next(i) != str.rend())10917{10918base = 0;10919}10920else10921{10922base *= 2;10923}10924}10925}10926if(base == 0)10927{10928return err(make_error_info("toml::parse_bin_integer: "10929"too large integer: current max value = 2^" + std::to_string(max_digits),10930std::move(src), "must be < 2^" + std::to_string(max_digits)));10931}10932return ok(val);10933}1093410935template<typename T>10936result<T, error_info>10937read_int(const std::string& str, const source_location src, const std::uint8_t base)10938{10939assert(base == 10 || base == 16 || base == 8 || base == 2);10940switch(base)10941{10942case 2: { return read_bin_int<T>(str, src); }10943case 8: { return read_oct_int<T>(str, src); }10944case 16: { return read_hex_int<T>(str, src); }10945default:10946{10947assert(base == 10);10948return read_dec_int<T>(str, src);10949}10950}10951}1095210953inline result<float, error_info>10954read_hex_float(const std::string& str, const source_location src, float val)10955{10956#if defined(_MSC_VER) && ! defined(__clang__)10957const auto res = ::sscanf_s(str.c_str(), "%a", std::addressof(val));10958#else10959const auto res = std::sscanf(str.c_str(), "%a", std::addressof(val));10960#endif10961if(res != 1)10962{10963return err(make_error_info("toml::parse_floating: "10964"failed to read hexadecimal floating point value ",10965std::move(src), "here"));10966}10967return ok(val);10968}10969inline result<double, error_info>10970read_hex_float(const std::string& str, const source_location src, double val)10971{10972#if defined(_MSC_VER) && ! defined(__clang__)10973const auto res = ::sscanf_s(str.c_str(), "%la", std::addressof(val));10974#else10975const auto res = std::sscanf(str.c_str(), "%la", std::addressof(val));10976#endif10977if(res != 1)10978{10979return err(make_error_info("toml::parse_floating: "10980"failed to read hexadecimal floating point value ",10981std::move(src), "here"));10982}10983return ok(val);10984}10985template<typename T>10986cxx::enable_if_t<cxx::conjunction<10987cxx::negation<std::is_same<cxx::remove_cvref_t<T>, double>>,10988cxx::negation<std::is_same<cxx::remove_cvref_t<T>, float>>10989>::value, result<T, error_info>>10990read_hex_float(const std::string&, const source_location src, T)10991{10992return err(make_error_info("toml::parse_floating: failed to read "10993"floating point value because of unknown type in type_config",10994std::move(src), "here"));10995}1099610997template<typename T>10998result<T, error_info>10999read_dec_float(const std::string& str, const source_location src)11000{11001T val;11002std::istringstream iss(str);11003iss >> val;11004if(iss.fail())11005{11006return err(make_error_info("toml::parse_floating: "11007"failed to read floating point value from stream",11008std::move(src), "here"));11009}11010return ok(val);11011}1101211013template<typename T>11014result<T, error_info>11015read_float(const std::string& str, const source_location src, const bool is_hex)11016{11017if(is_hex)11018{11019return read_hex_float(str, src, T{});11020}11021else11022{11023return read_dec_float<T>(str, src);11024}11025}1102611027struct type_config11028{11029using comment_type = preserve_comments;1103011031using boolean_type = bool;11032using integer_type = std::int64_t;11033using floating_type = double;11034using string_type = std::string;1103511036template<typename T>11037using array_type = std::vector<T>;11038template<typename K, typename T>11039using table_type = std::unordered_map<K, T>;1104011041static result<integer_type, error_info>11042parse_int(const std::string& str, const source_location src, const std::uint8_t base)11043{11044return read_int<integer_type>(str, src, base);11045}11046static result<floating_type, error_info>11047parse_float(const std::string& str, const source_location src, const bool is_hex)11048{11049return read_float<floating_type>(str, src, is_hex);11050}11051};1105211053using value = basic_value<type_config>;11054using table = typename value::table_type;11055using array = typename value::array_type;1105611057struct ordered_type_config11058{11059using comment_type = preserve_comments;1106011061using boolean_type = bool;11062using integer_type = std::int64_t;11063using floating_type = double;11064using string_type = std::string;1106511066template<typename T>11067using array_type = std::vector<T>;11068template<typename K, typename T>11069using table_type = ordered_map<K, T>;1107011071static result<integer_type, error_info>11072parse_int(const std::string& str, const source_location src, const std::uint8_t base)11073{11074return read_int<integer_type>(str, src, base);11075}11076static result<floating_type, error_info>11077parse_float(const std::string& str, const source_location src, const bool is_hex)11078{11079return read_float<floating_type>(str, src, is_hex);11080}11081};1108211083using ordered_value = basic_value<ordered_type_config>;11084using ordered_table = typename ordered_value::table_type;11085using ordered_array = typename ordered_value::array_type;1108611087// ----------------------------------------------------------------------------11088// meta functions for internal use1108911090namespace detail11091{1109211093// ----------------------------------------------------------------------------11094// check if type T has all the needed member types1109511096template<typename T, typename U = void>11097struct has_comment_type: std::false_type{};11098template<typename T>11099struct has_comment_type<T, cxx::void_t<typename T::comment_type>>: std::true_type{};1110011101template<typename T, typename U = void>11102struct has_integer_type: std::false_type{};11103template<typename T>11104struct has_integer_type<T, cxx::void_t<typename T::integer_type>>: std::true_type{};1110511106template<typename T, typename U = void>11107struct has_floating_type: std::false_type{};11108template<typename T>11109struct has_floating_type<T, cxx::void_t<typename T::floating_type>>: std::true_type{};1111011111template<typename T, typename U = void>11112struct has_string_type: std::false_type{};11113template<typename T>11114struct has_string_type<T, cxx::void_t<typename T::string_type>>: std::true_type{};1111511116template<typename T, typename U = void>11117struct has_array_type: std::false_type{};11118template<typename T>11119struct has_array_type<T, cxx::void_t<typename T::template array_type<int>>>: std::true_type{};1112011121template<typename T, typename U = void>11122struct has_table_type: std::false_type{};11123template<typename T>11124struct has_table_type<T, cxx::void_t<typename T::template table_type<int, int>>>: std::true_type{};1112511126template<typename T, typename U = void>11127struct has_parse_int: std::false_type{};11128template<typename T>11129struct has_parse_int<T, cxx::void_t<decltype(std::declval<T>().parse_int(11130std::declval<std::string const&>(),11131std::declval<::toml::source_location const&>(),11132std::declval<std::uint8_t>()11133))>>: std::true_type{};1113411135template<typename T, typename U = void>11136struct has_parse_float: std::false_type{};11137template<typename T>11138struct has_parse_float<T, cxx::void_t<decltype(std::declval<T>().parse_float(11139std::declval<std::string const&>(),11140std::declval<::toml::source_location const&>(),11141std::declval<bool>()11142))>>: std::true_type{};1114311144template<typename T>11145using is_type_config = cxx::conjunction<11146has_comment_type<T>,11147has_integer_type<T>,11148has_floating_type<T>,11149has_string_type<T>,11150has_array_type<T>,11151has_table_type<T>,11152has_parse_int<T>,11153has_parse_float<T>11154>;1115511156} // namespace detail11157} // TOML11_INLINE_VERSION_NAMESPACE11158} // namespace toml1115911160#if defined(TOML11_COMPILE_SOURCES)11161namespace toml11162{11163inline namespace TOML11_INLINE_VERSION_NAMESPACE11164{11165extern template class basic_value<type_config>;11166extern template class basic_value<ordered_type_config>;11167} // TOML11_INLINE_VERSION_NAMESPACE11168} // toml11169#endif // TOML11_COMPILE_SOURCES1117011171#endif // TOML11_TYPES_HPP11172#ifndef TOML11_SERIALIZER_HPP11173#define TOML11_SERIALIZER_HPP111741117511176#include <iomanip>11177#include <iterator>11178#include <sstream>1117911180#include <cmath>11181#include <cstdio>1118211183namespace toml11184{11185inline namespace TOML11_INLINE_VERSION_NAMESPACE11186{1118711188struct serialization_error final : public ::toml::exception11189{11190public:11191explicit serialization_error(std::string what_arg, source_location loc)11192: what_(std::move(what_arg)), loc_(std::move(loc))11193{}11194~serialization_error() noexcept override = default;1119511196const char* what() const noexcept override {return what_.c_str();}11197source_location const& location() const noexcept {return loc_;}1119811199private:11200std::string what_;11201source_location loc_;11202};1120311204namespace detail11205{11206template<typename TC>11207class serializer11208{11209public:1121011211using value_type = basic_value<TC>;1121211213using key_type = typename value_type::key_type ;11214using comment_type = typename value_type::comment_type ;11215using boolean_type = typename value_type::boolean_type ;11216using integer_type = typename value_type::integer_type ;11217using floating_type = typename value_type::floating_type ;11218using string_type = typename value_type::string_type ;11219using local_time_type = typename value_type::local_time_type ;11220using local_date_type = typename value_type::local_date_type ;11221using local_datetime_type = typename value_type::local_datetime_type ;11222using offset_datetime_type = typename value_type::offset_datetime_type;11223using array_type = typename value_type::array_type ;11224using table_type = typename value_type::table_type ;1122511226using char_type = typename string_type::value_type;1122711228public:1122911230explicit serializer(const spec& sp)11231: spec_(sp), force_inline_(false), current_indent_(0)11232{}1123311234string_type operator()(const std::vector<key_type>& ks, const value_type& v)11235{11236for(const auto& k : ks)11237{11238this->keys_.push_back(k);11239}11240return (*this)(v);11241}1124211243string_type operator()(const key_type& k, const value_type& v)11244{11245this->keys_.push_back(k);11246return (*this)(v);11247}1124811249string_type operator()(const value_type& v)11250{11251switch(v.type())11252{11253case value_t::boolean : {return (*this)(v.as_boolean (), v.as_boolean_fmt (), v.location());}11254case value_t::integer : {return (*this)(v.as_integer (), v.as_integer_fmt (), v.location());}11255case value_t::floating : {return (*this)(v.as_floating (), v.as_floating_fmt (), v.location());}11256case value_t::string : {return (*this)(v.as_string (), v.as_string_fmt (), v.location());}11257case value_t::offset_datetime: {return (*this)(v.as_offset_datetime(), v.as_offset_datetime_fmt(), v.location());}11258case value_t::local_datetime : {return (*this)(v.as_local_datetime (), v.as_local_datetime_fmt (), v.location());}11259case value_t::local_date : {return (*this)(v.as_local_date (), v.as_local_date_fmt (), v.location());}11260case value_t::local_time : {return (*this)(v.as_local_time (), v.as_local_time_fmt (), v.location());}11261case value_t::array :11262{11263return (*this)(v.as_array(), v.as_array_fmt(), v.comments(), v.location());11264}11265case value_t::table :11266{11267string_type retval;11268if(this->keys_.empty()) // it might be the root table. emit comments here.11269{11270retval += format_comments(v.comments(), v.as_table_fmt().indent_type);11271}11272if( ! retval.empty()) // we have comment.11273{11274retval += char_type('\n');11275}1127611277retval += (*this)(v.as_table(), v.as_table_fmt(), v.comments(), v.location());11278return retval;11279}11280case value_t::empty:11281{11282if(this->spec_.ext_null_value)11283{11284return string_conv<string_type>("null");11285}11286break;11287}11288default:11289{11290break;11291}11292}11293throw serialization_error(format_error(11294"[error] toml::serializer: toml::basic_value "11295"does not have any valid type.", v.location(), "here"), v.location());11296}1129711298private:1129911300string_type operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{11301{11302if(b)11303{11304return string_conv<string_type>("true");11305}11306else11307{11308return string_conv<string_type>("false");11309}11310} // }}}1131111312string_type operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{11313{11314std::ostringstream oss;11315this->set_locale(oss);1131611317const auto insert_spacer = [&fmt](std::string s) -> std::string {11318if(fmt.spacer == 0) {return s;}1131911320std::string sign;11321if( ! s.empty() && (s.at(0) == '+' || s.at(0) == '-'))11322{11323sign += s.at(0);11324s.erase(s.begin());11325}1132611327std::string spaced;11328std::size_t counter = 0;11329for(auto iter = s.rbegin(); iter != s.rend(); ++iter)11330{11331if(counter != 0 && counter % fmt.spacer == 0)11332{11333spaced += '_';11334}11335spaced += *iter;11336counter += 1;11337}11338if(!spaced.empty() && spaced.back() == '_') {spaced.pop_back();}1133911340s.clear();11341std::copy(spaced.rbegin(), spaced.rend(), std::back_inserter(s));11342return sign + s;11343};1134411345std::string retval;11346if(fmt.fmt == integer_format::dec)11347{11348oss << std::setw(static_cast<int>(fmt.width)) << std::dec << i;11349retval = insert_spacer(oss.str());1135011351if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11352{11353retval += '_';11354retval += fmt.suffix;11355}11356}11357else11358{11359if(i < 0)11360{11361throw serialization_error(format_error("binary, octal, hexadecimal "11362"integer does not allow negative value", loc, "here"), loc);11363}11364switch(fmt.fmt)11365{11366case integer_format::hex:11367{11368oss << std::noshowbase11369<< std::setw(static_cast<int>(fmt.width))11370<< std::setfill('0')11371<< std::hex;11372if(fmt.uppercase)11373{11374oss << std::uppercase;11375}11376else11377{11378oss << std::nouppercase;11379}11380oss << i;11381retval = std::string("0x") + insert_spacer(oss.str());11382break;11383}11384case integer_format::oct:11385{11386oss << std::setw(static_cast<int>(fmt.width)) << std::setfill('0') << std::oct << i;11387retval = std::string("0o") + insert_spacer(oss.str());11388break;11389}11390case integer_format::bin:11391{11392integer_type x{i};11393std::string tmp;11394std::size_t bits(0);11395while(x != 0)11396{11397if(fmt.spacer != 0)11398{11399if(bits != 0 && (bits % fmt.spacer) == 0) {tmp += '_';}11400}11401if(x % 2 == 1) { tmp += '1'; } else { tmp += '0'; }11402x >>= 1;11403bits += 1;11404}11405for(; bits < fmt.width; ++bits)11406{11407if(fmt.spacer != 0)11408{11409if(bits != 0 && (bits % fmt.spacer) == 0) {tmp += '_';}11410}11411tmp += '0';11412}11413for(auto iter = tmp.rbegin(); iter != tmp.rend(); ++iter)11414{11415oss << *iter;11416}11417retval = std::string("0b") + oss.str();11418break;11419}11420default:11421{11422throw serialization_error(format_error(11423"none of dec, hex, oct, bin: " + to_string(fmt.fmt),11424loc, "here"), loc);11425}11426}11427}11428return string_conv<string_type>(retval);11429} // }}}1143011431string_type operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{11432{11433using std::isnan;11434using std::isinf;11435using std::signbit;1143611437std::ostringstream oss;11438this->set_locale(oss);1143911440if(isnan(f))11441{11442if(signbit(f))11443{11444oss << '-';11445}11446oss << "nan";11447if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11448{11449oss << '_';11450oss << fmt.suffix;11451}11452return string_conv<string_type>(oss.str());11453}1145411455if(isinf(f))11456{11457if(signbit(f))11458{11459oss << '-';11460}11461oss << "inf";11462if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11463{11464oss << '_';11465oss << fmt.suffix;11466}11467return string_conv<string_type>(oss.str());11468}1146911470switch(fmt.fmt)11471{11472case floating_format::defaultfloat:11473{11474if(fmt.prec != 0)11475{11476oss << std::setprecision(static_cast<int>(fmt.prec));11477}11478oss << f;11479// since defaultfloat may omit point, we need to add it11480std::string s = oss.str();11481if (s.find('.') == std::string::npos &&11482s.find('e') == std::string::npos &&11483s.find('E') == std::string::npos )11484{11485s += ".0";11486}11487if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11488{11489s += '_';11490s += fmt.suffix;11491}11492return string_conv<string_type>(s);11493}11494case floating_format::fixed:11495{11496if(fmt.prec != 0)11497{11498oss << std::setprecision(static_cast<int>(fmt.prec));11499}11500oss << std::fixed << f;11501if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11502{11503oss << '_' << fmt.suffix;11504}11505return string_conv<string_type>(oss.str());11506}11507case floating_format::scientific:11508{11509if(fmt.prec != 0)11510{11511oss << std::setprecision(static_cast<int>(fmt.prec));11512}11513oss << std::scientific << f;11514if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11515{11516oss << '_' << fmt.suffix;11517}11518return string_conv<string_type>(oss.str());11519}11520case floating_format::hex:11521{11522if(this->spec_.ext_hex_float)11523{11524oss << std::hexfloat << f;11525// suffix is only for decimal numbers.11526return string_conv<string_type>(oss.str());11527}11528else // no hex allowed. output with max precision.11529{11530oss << std::setprecision(std::numeric_limits<floating_type>::max_digits10)11531<< std::scientific << f;11532// suffix is only for decimal numbers.11533return string_conv<string_type>(oss.str());11534}11535}11536default:11537{11538if(this->spec_.ext_num_suffix && ! fmt.suffix.empty())11539{11540oss << '_' << fmt.suffix;11541}11542return string_conv<string_type>(oss.str());11543}11544}11545} // }}}1154611547string_type operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{11548{11549string_type retval;11550switch(fmt.fmt)11551{11552case string_format::basic:11553{11554retval += char_type('"');11555retval += this->escape_basic_string(s);11556retval += char_type('"');11557return retval;11558}11559case string_format::literal:11560{11561if(std::find(s.begin(), s.end(), char_type('\n')) != s.end())11562{11563throw serialization_error(format_error("toml::serializer: "11564"(non-multiline) literal string cannot have a newline",11565loc, "here"), loc);11566}11567retval += char_type('\'');11568retval += s;11569retval += char_type('\'');11570return retval;11571}11572case string_format::multiline_basic:11573{11574retval += string_conv<string_type>("\"\"\"");11575if(fmt.start_with_newline)11576{11577retval += char_type('\n');11578}1157911580retval += this->escape_ml_basic_string(s);1158111582retval += string_conv<string_type>("\"\"\"");11583return retval;11584}11585case string_format::multiline_literal:11586{11587retval += string_conv<string_type>("'''");11588if(fmt.start_with_newline)11589{11590retval += char_type('\n');11591}11592retval += s;11593retval += string_conv<string_type>("'''");11594return retval;11595}11596default:11597{11598throw serialization_error(format_error(11599"[error] toml::serializer::operator()(string): "11600"invalid string_format value", loc, "here"), loc);11601}11602}11603} // }}}1160411605string_type operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{11606{11607std::ostringstream oss;11608oss << d;11609return string_conv<string_type>(oss.str());11610} // }}}1161111612string_type operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{11613{11614return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision);11615} // }}}1161611617string_type operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{11618{11619std::ostringstream oss;11620oss << dt.date;11621switch(fmt.delimiter)11622{11623case datetime_delimiter_kind::upper_T: { oss << 'T'; break; }11624case datetime_delimiter_kind::lower_t: { oss << 't'; break; }11625case datetime_delimiter_kind::space: { oss << ' '; break; }11626default: { oss << 'T'; break; }11627}11628return string_conv<string_type>(oss.str()) +11629this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision);11630} // }}}1163111632string_type operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{11633{11634std::ostringstream oss;11635oss << odt.date;11636switch(fmt.delimiter)11637{11638case datetime_delimiter_kind::upper_T: { oss << 'T'; break; }11639case datetime_delimiter_kind::lower_t: { oss << 't'; break; }11640case datetime_delimiter_kind::space: { oss << ' '; break; }11641default: { oss << 'T'; break; }11642}11643oss << string_conv<std::string>(this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision));11644oss << odt.offset;11645return string_conv<string_type>(oss.str());11646} // }}}1164711648string_type operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{11649{11650array_format f = fmt.fmt;11651if(fmt.fmt == array_format::default_format)11652{11653// [[in.this.form]], you cannot add a comment to the array itself11654// (but you can add a comment to each table).11655// To keep comments, we need to avoid multiline array-of-tables11656// if array itself has a comment.11657if( ! this->keys_.empty() &&11658! a.empty() &&11659com.empty() &&11660std::all_of(a.begin(), a.end(), [](const value_type& e) {return e.is_table();}))11661{11662f = array_format::array_of_tables;11663}11664else11665{11666f = array_format::oneline;1166711668// check if it becomes long11669std::size_t approx_len = 0;11670for(const auto& e : a)11671{11672// have a comment. cannot be inlined11673if( ! e.comments().empty())11674{11675f = array_format::multiline;11676break;11677}11678// possibly long types ...11679if(e.is_array() || e.is_table() || e.is_offset_datetime() || e.is_local_datetime())11680{11681f = array_format::multiline;11682break;11683}11684else if(e.is_boolean())11685{11686approx_len += (*this)(e.as_boolean(), e.as_boolean_fmt(), e.location()).size();11687}11688else if(e.is_integer())11689{11690approx_len += (*this)(e.as_integer(), e.as_integer_fmt(), e.location()).size();11691}11692else if(e.is_floating())11693{11694approx_len += (*this)(e.as_floating(), e.as_floating_fmt(), e.location()).size();11695}11696else if(e.is_string())11697{11698if(e.as_string_fmt().fmt == string_format::multiline_basic ||11699e.as_string_fmt().fmt == string_format::multiline_literal)11700{11701f = array_format::multiline;11702break;11703}11704approx_len += 2 + (*this)(e.as_string(), e.as_string_fmt(), e.location()).size();11705}11706else if(e.is_local_date())11707{11708approx_len += 10; // 1234-56-7811709}11710else if(e.is_local_time())11711{11712approx_len += 15; // 12:34:56.78901211713}1171411715if(approx_len > 60) // key, ` = `, `[...]` < 8011716{11717f = array_format::multiline;11718break;11719}11720approx_len += 2; // `, `11721}11722}11723}11724if(this->force_inline_ && f == array_format::array_of_tables)11725{11726f = array_format::multiline;11727}11728if(a.empty() && f == array_format::array_of_tables)11729{11730f = array_format::oneline;11731}1173211733// --------------------------------------------------------------------1173411735if(f == array_format::array_of_tables)11736{11737if(this->keys_.empty())11738{11739throw serialization_error("array of table must have its key. "11740"use format(key, v)", loc);11741}11742string_type retval;11743for(const auto& e : a)11744{11745assert(e.is_table());1174611747this->current_indent_ += e.as_table_fmt().name_indent;11748retval += this->format_comments(e.comments(), e.as_table_fmt().indent_type);11749retval += this->format_indent(e.as_table_fmt().indent_type);11750this->current_indent_ -= e.as_table_fmt().name_indent;1175111752retval += string_conv<string_type>("[[");11753retval += this->format_keys(this->keys_).value();11754retval += string_conv<string_type>("]]\n");1175511756retval += this->format_ml_table(e.as_table(), e.as_table_fmt());11757}11758return retval;11759}11760else if(f == array_format::oneline)11761{11762// ignore comments. we cannot emit comments11763string_type retval;11764retval += char_type('[');11765for(const auto& e : a)11766{11767this->force_inline_ = true;11768retval += (*this)(e);11769retval += string_conv<string_type>(", ");11770}11771if( ! a.empty())11772{11773retval.pop_back(); // ` `11774retval.pop_back(); // `,`11775}11776retval += char_type(']');11777this->force_inline_ = false;11778return retval;11779}11780else11781{11782assert(f == array_format::multiline);1178311784string_type retval;11785retval += string_conv<string_type>("[\n");1178611787for(const auto& e : a)11788{11789this->current_indent_ += fmt.body_indent;11790retval += this->format_comments(e.comments(), fmt.indent_type);11791retval += this->format_indent(fmt.indent_type);11792this->current_indent_ -= fmt.body_indent;1179311794this->force_inline_ = true;11795retval += (*this)(e);11796retval += string_conv<string_type>(",\n");11797}11798this->force_inline_ = false;1179911800this->current_indent_ += fmt.closing_indent;11801retval += this->format_indent(fmt.indent_type);11802this->current_indent_ -= fmt.closing_indent;1180311804retval += char_type(']');11805return retval;11806}11807} // }}}1180811809string_type operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{11810{11811if(this->force_inline_)11812{11813if(fmt.fmt == table_format::multiline_oneline)11814{11815return this->format_ml_inline_table(t, fmt);11816}11817else11818{11819return this->format_inline_table(t, fmt);11820}11821}11822else11823{11824if(fmt.fmt == table_format::multiline)11825{11826string_type retval;11827// comment is emitted inside format_ml_table11828if(auto k = this->format_keys(this->keys_))11829{11830this->current_indent_ += fmt.name_indent;11831retval += this->format_comments(com, fmt.indent_type);11832retval += this->format_indent(fmt.indent_type);11833this->current_indent_ -= fmt.name_indent;11834retval += char_type('[');11835retval += k.value();11836retval += string_conv<string_type>("]\n");11837}11838// otherwise, its the root.1183911840retval += this->format_ml_table(t, fmt);11841return retval;11842}11843else if(fmt.fmt == table_format::oneline)11844{11845return this->format_inline_table(t, fmt);11846}11847else if(fmt.fmt == table_format::multiline_oneline)11848{11849return this->format_ml_inline_table(t, fmt);11850}11851else if(fmt.fmt == table_format::dotted)11852{11853std::vector<string_type> keys;11854if(this->keys_.empty())11855{11856throw serialization_error(format_error("toml::serializer: "11857"dotted table must have its key. use format(key, v)",11858loc, "here"), loc);11859}11860keys.push_back(this->keys_.back());1186111862const auto retval = this->format_dotted_table(t, fmt, loc, keys);11863keys.pop_back();11864return retval;11865}11866else11867{11868assert(fmt.fmt == table_format::implicit);1186911870string_type retval;11871for(const auto& kv : t)11872{11873const auto& k = kv.first;11874const auto& v = kv.second;1187511876if( ! v.is_table() && ! v.is_array_of_tables())11877{11878throw serialization_error(format_error("toml::serializer: "11879"an implicit table cannot have non-table value.",11880v.location(), "here"), v.location());11881}11882if(v.is_table())11883{11884if(v.as_table_fmt().fmt != table_format::multiline &&11885v.as_table_fmt().fmt != table_format::implicit)11886{11887throw serialization_error(format_error("toml::serializer: "11888"an implicit table cannot have non-multiline table",11889v.location(), "here"), v.location());11890}11891}11892else11893{11894assert(v.is_array());11895for(const auto& e : v.as_array())11896{11897if(e.as_table_fmt().fmt != table_format::multiline &&11898v.as_table_fmt().fmt != table_format::implicit)11899{11900throw serialization_error(format_error("toml::serializer: "11901"an implicit table cannot have non-multiline table",11902e.location(), "here"), e.location());11903}11904}11905}1190611907keys_.push_back(k);11908retval += (*this)(v);11909keys_.pop_back();11910}11911return retval;11912}11913}11914} // }}}1191511916private:1191711918string_type escape_basic_string(const string_type& s) const // {{{11919{11920string_type retval;11921for(const char_type c : s)11922{11923switch(c)11924{11925case char_type('\\'): {retval += string_conv<string_type>("\\\\"); break;}11926case char_type('\"'): {retval += string_conv<string_type>("\\\""); break;}11927case char_type('\b'): {retval += string_conv<string_type>("\\b" ); break;}11928case char_type('\t'): {retval += string_conv<string_type>("\\t" ); break;}11929case char_type('\f'): {retval += string_conv<string_type>("\\f" ); break;}11930case char_type('\n'): {retval += string_conv<string_type>("\\n" ); break;}11931case char_type('\r'): {retval += string_conv<string_type>("\\r" ); break;}11932default :11933{11934if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e)11935{11936retval += string_conv<string_type>("\\e");11937}11938else if((char_type(0x00) <= c && c <= char_type(0x08)) ||11939(char_type(0x0A) <= c && c <= char_type(0x1F)) ||11940c == char_type(0x7F))11941{11942if(spec_.v1_1_0_add_escape_sequence_x)11943{11944retval += string_conv<string_type>("\\x");11945}11946else11947{11948retval += string_conv<string_type>("\\u00");11949}11950const auto c1 = c / 16;11951const auto c2 = c % 16;11952retval += static_cast<char_type>('0' + c1);11953if(c2 < 10)11954{11955retval += static_cast<char_type>('0' + c2);11956}11957else // 10 <= c211958{11959retval += static_cast<char_type>('A' + (c2 - 10));11960}11961}11962else11963{11964retval += c;11965}11966}11967}11968}11969return retval;11970} // }}}1197111972string_type escape_ml_basic_string(const string_type& s) // {{{11973{11974string_type retval;11975for(const char_type c : s)11976{11977switch(c)11978{11979case char_type('\\'): {retval += string_conv<string_type>("\\\\"); break;}11980case char_type('\b'): {retval += string_conv<string_type>("\\b" ); break;}11981case char_type('\t'): {retval += string_conv<string_type>("\\t" ); break;}11982case char_type('\f'): {retval += string_conv<string_type>("\\f" ); break;}11983case char_type('\n'): {retval += string_conv<string_type>("\n" ); break;}11984case char_type('\r'): {retval += string_conv<string_type>("\\r" ); break;}11985default :11986{11987if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e)11988{11989retval += string_conv<string_type>("\\e");11990}11991else if((char_type(0x00) <= c && c <= char_type(0x08)) ||11992(char_type(0x0A) <= c && c <= char_type(0x1F)) ||11993c == char_type(0x7F))11994{11995if(spec_.v1_1_0_add_escape_sequence_x)11996{11997retval += string_conv<string_type>("\\x");11998}11999else12000{12001retval += string_conv<string_type>("\\u00");12002}12003const auto c1 = c / 16;12004const auto c2 = c % 16;12005retval += static_cast<char_type>('0' + c1);12006if(c2 < 10)12007{12008retval += static_cast<char_type>('0' + c2);12009}12010else // 10 <= c212011{12012retval += static_cast<char_type>('A' + (c2 - 10));12013}12014}12015else12016{12017retval += c;12018}12019}12020}12021}12022// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.12023// 3 consecutive `"`s are considered as a closing delimiter.12024// We need to check if there are 3 or more consecutive `"`s and insert12025// backslash to break them down into several short `"`s like the `str6`12026// in the following example.12027// ```toml12028// str4 = """Here are two quotation marks: "". Simple enough."""12029// # str5 = """Here are three quotation marks: """.""" # INVALID12030// str5 = """Here are three quotation marks: ""\"."""12031// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""12032// ```12033auto found_3_quotes = retval.find(string_conv<string_type>("\"\"\""));12034while(found_3_quotes != string_type::npos)12035{12036retval.replace(found_3_quotes, 3, string_conv<string_type>("\"\"\\\""));12037found_3_quotes = retval.find(string_conv<string_type>("\"\"\""));12038}12039return retval;12040} // }}}1204112042string_type format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{12043{12044std::ostringstream oss;12045oss << std::setfill('0') << std::setw(2) << static_cast<int>(t.hour);12046oss << ':';12047oss << std::setfill('0') << std::setw(2) << static_cast<int>(t.minute);12048if(has_seconds)12049{12050oss << ':';12051oss << std::setfill('0') << std::setw(2) << static_cast<int>(t.second);12052if(subsec_prec != 0)12053{12054std::ostringstream subsec;12055subsec << std::setfill('0') << std::setw(3) << static_cast<int>(t.millisecond);12056subsec << std::setfill('0') << std::setw(3) << static_cast<int>(t.microsecond);12057subsec << std::setfill('0') << std::setw(3) << static_cast<int>(t.nanosecond);12058std::string subsec_str = subsec.str();12059oss << '.' << subsec_str.substr(0, subsec_prec);12060}12061}12062return string_conv<string_type>(oss.str());12063} // }}}1206412065string_type format_ml_table(const table_type& t, const table_format_info& fmt) // {{{12066{12067const auto format_later = [](const value_type& v) -> bool {1206812069const bool is_ml_table = v.is_table() &&12070v.as_table_fmt().fmt != table_format::oneline &&12071v.as_table_fmt().fmt != table_format::multiline_oneline &&12072v.as_table_fmt().fmt != table_format::dotted ;1207312074const bool is_ml_array_table = v.is_array_of_tables() &&12075v.as_array_fmt().fmt != array_format::oneline &&12076v.as_array_fmt().fmt != array_format::multiline;1207712078return is_ml_table || is_ml_array_table;12079};1208012081string_type retval;12082this->current_indent_ += fmt.body_indent;12083for(const auto& kv : t)12084{12085const auto& key = kv.first;12086const auto& val = kv.second;12087if(format_later(val))12088{12089continue;12090}12091this->keys_.push_back(key);1209212093retval += format_comments(val.comments(), fmt.indent_type);12094retval += format_indent(fmt.indent_type);12095if(val.is_table() && val.as_table_fmt().fmt == table_format::dotted)12096{12097retval += (*this)(val);12098}12099else12100{12101retval += format_key(key);12102retval += string_conv<string_type>(" = ");12103retval += (*this)(val);12104retval += char_type('\n');12105}12106this->keys_.pop_back();12107}12108this->current_indent_ -= fmt.body_indent;1210912110if( ! retval.empty())12111{12112retval += char_type('\n'); // for readability, add empty line between tables12113}12114for(const auto& kv : t)12115{12116if( ! format_later(kv.second))12117{12118continue;12119}12120// must be a [multiline.table] or [[multiline.array.of.tables]].12121// comments will be generated inside it.12122this->keys_.push_back(kv.first);12123retval += (*this)(kv.second);12124this->keys_.pop_back();12125}12126return retval;12127} // }}}1212812129string_type format_inline_table(const table_type& t, const table_format_info&) // {{{12130{12131// comments are ignored because we cannot write without newline12132string_type retval;12133retval += char_type('{');12134for(const auto& kv : t)12135{12136this->force_inline_ = true;12137retval += this->format_key(kv.first);12138retval += string_conv<string_type>(" = ");12139retval += (*this)(kv.second);12140retval += string_conv<string_type>(", ");12141}12142if( ! t.empty())12143{12144retval.pop_back(); // ' '12145retval.pop_back(); // ','12146}12147retval += char_type('}');12148this->force_inline_ = false;12149return retval;12150} // }}}1215112152string_type format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{12153{12154string_type retval;12155retval += string_conv<string_type>("{\n");12156this->current_indent_ += fmt.body_indent;12157for(const auto& kv : t)12158{12159this->force_inline_ = true;12160retval += format_comments(kv.second.comments(), fmt.indent_type);12161retval += format_indent(fmt.indent_type);12162retval += kv.first;12163retval += string_conv<string_type>(" = ");1216412165this->force_inline_ = true;12166retval += (*this)(kv.second);1216712168retval += string_conv<string_type>(",\n");12169}12170if( ! t.empty())12171{12172retval.pop_back(); // '\n'12173retval.pop_back(); // ','12174}12175this->current_indent_ -= fmt.body_indent;12176this->force_inline_ = false;1217712178this->current_indent_ += fmt.closing_indent;12179retval += format_indent(fmt.indent_type);12180this->current_indent_ -= fmt.closing_indent;1218112182retval += char_type('}');12183return retval;12184} // }}}1218512186string_type format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{12187const source_location&, std::vector<string_type>& keys)12188{12189// lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }`12190// and `a` and `b` are `dotted`.12191//12192// - in case if `c` is `oneline`:12193// ```toml12194// a.b.c = {d = "foo", e = "bar"}12195// ```12196//12197// - in case if and `c` is `dotted`:12198// ```toml12199// a.b.c.d = "foo"12200// a.b.c.e = "bar"12201// ```1220212203string_type retval;1220412205for(const auto& kv : t)12206{12207const auto& key = kv.first;12208const auto& val = kv.second;1220912210keys.push_back(key);1221112212// format recursive dotted table?12213if (val.is_table() &&12214val.as_table_fmt().fmt != table_format::oneline &&12215val.as_table_fmt().fmt != table_format::multiline_oneline)12216{12217retval += this->format_dotted_table(val.as_table(), val.as_table_fmt(), val.location(), keys);12218}12219else // non-table or inline tables. format normally12220{12221retval += format_comments(val.comments(), fmt.indent_type);12222retval += format_indent(fmt.indent_type);12223retval += format_keys(keys).value();12224retval += string_conv<string_type>(" = ");12225this->force_inline_ = true; // sub-table must be inlined12226retval += (*this)(val);12227retval += char_type('\n');12228this->force_inline_ = false;12229}12230keys.pop_back();12231}12232return retval;12233} // }}}1223412235string_type format_key(const key_type& key) // {{{12236{12237if(key.empty())12238{12239return string_conv<string_type>("\"\"");12240}1224112242// check the key can be a bare (unquoted) key12243auto loc = detail::make_temporary_location(string_conv<std::string>(key));12244auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc);12245if(reg.is_ok() && loc.eof())12246{12247return key;12248}1224912250//if it includes special characters, then format it in a "quoted" key.12251string_type formatted = string_conv<string_type>("\"");12252for(const char_type c : key)12253{12254switch(c)12255{12256case char_type('\\'): {formatted += string_conv<string_type>("\\\\"); break;}12257case char_type('\"'): {formatted += string_conv<string_type>("\\\""); break;}12258case char_type('\b'): {formatted += string_conv<string_type>("\\b" ); break;}12259case char_type('\t'): {formatted += string_conv<string_type>("\\t" ); break;}12260case char_type('\f'): {formatted += string_conv<string_type>("\\f" ); break;}12261case char_type('\n'): {formatted += string_conv<string_type>("\\n" ); break;}12262case char_type('\r'): {formatted += string_conv<string_type>("\\r" ); break;}12263default :12264{12265// ASCII ctrl char12266if( (char_type(0x00) <= c && c <= char_type(0x08)) ||12267(char_type(0x0A) <= c && c <= char_type(0x1F)) ||12268c == char_type(0x7F))12269{12270if(spec_.v1_1_0_add_escape_sequence_x)12271{12272formatted += string_conv<string_type>("\\x");12273}12274else12275{12276formatted += string_conv<string_type>("\\u00");12277}12278const auto c1 = c / 16;12279const auto c2 = c % 16;12280formatted += static_cast<char_type>('0' + c1);12281if(c2 < 10)12282{12283formatted += static_cast<char_type>('0' + c2);12284}12285else // 10 <= c212286{12287formatted += static_cast<char_type>('A' + (c2 - 10));12288}12289}12290else12291{12292formatted += c;12293}12294break;12295}12296}12297}12298formatted += string_conv<string_type>("\"");12299return formatted;12300} // }}}12301cxx::optional<string_type> format_keys(const std::vector<key_type>& keys) // {{{12302{12303if(keys.empty())12304{12305return cxx::make_nullopt();12306}1230712308string_type formatted;12309for(const auto& ky : keys)12310{12311formatted += format_key(ky);12312formatted += char_type('.');12313}12314formatted.pop_back(); // remove the last dot '.'12315return formatted;12316} // }}}1231712318string_type format_comments(const discard_comments&, const indent_char) const // {{{12319{12320return string_conv<string_type>("");12321} // }}}12322string_type format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{12323{12324string_type retval;12325for(const auto& c : comments)12326{12327if(c.empty()) {continue;}12328retval += format_indent(indent_type);12329if(c.front() != '#') {retval += char_type('#');}12330retval += string_conv<string_type>(c);12331if(c.back() != '\n') {retval += char_type('\n');}12332}12333return retval;12334} // }}}1233512336string_type format_indent(const indent_char indent_type) const // {{{12337{12338const auto indent = static_cast<std::size_t>((std::max)(0, this->current_indent_));12339if(indent_type == indent_char::space)12340{12341return string_conv<string_type>(make_string(indent, ' '));12342}12343else if(indent_type == indent_char::tab)12344{12345return string_conv<string_type>(make_string(indent, '\t'));12346}12347else12348{12349return string_type{};12350}12351} // }}}1235212353std::locale set_locale(std::ostream& os) const12354{12355return os.imbue(std::locale::classic());12356}1235712358private:1235912360spec spec_;12361bool force_inline_; // table inside an array without fmt specification12362std::int32_t current_indent_;12363std::vector<key_type> keys_;12364};12365} // detail1236612367template<typename TC>12368typename basic_value<TC>::string_type12369format(const basic_value<TC>& v, const spec s = spec::default_version())12370{12371detail::serializer<TC> ser(s);12372return ser(v);12373}12374template<typename TC>12375typename basic_value<TC>::string_type12376format(const typename basic_value<TC>::key_type& k,12377const basic_value<TC>& v,12378const spec s = spec::default_version())12379{12380detail::serializer<TC> ser(s);12381return ser(k, v);12382}12383template<typename TC>12384typename basic_value<TC>::string_type12385format(const std::vector<typename basic_value<TC>::key_type>& ks,12386const basic_value<TC>& v,12387const spec s = spec::default_version())12388{12389detail::serializer<TC> ser(s);12390return ser(ks, v);12391}1239212393template<typename TC>12394std::ostream& operator<<(std::ostream& os, const basic_value<TC>& v)12395{12396os << format(v);12397return os;12398}1239912400} // TOML11_INLINE_VERSION_NAMESPACE12401} // toml1240212403#if defined(TOML11_COMPILE_SOURCES)12404namespace toml12405{12406inline namespace TOML11_INLINE_VERSION_NAMESPACE12407{12408struct type_config;12409struct ordered_type_config;1241012411extern template typename basic_value<type_config>::string_type12412format<type_config>(const basic_value<type_config>&, const spec);1241312414extern template typename basic_value<type_config>::string_type12415format<type_config>(const typename basic_value<type_config>::key_type& k,12416const basic_value<type_config>& v, const spec);1241712418extern template typename basic_value<type_config>::string_type12419format<type_config>(const std::vector<typename basic_value<type_config>::key_type>& ks,12420const basic_value<type_config>& v, const spec s);1242112422extern template typename basic_value<type_config>::string_type12423format<ordered_type_config>(const basic_value<ordered_type_config>&, const spec);1242412425extern template typename basic_value<type_config>::string_type12426format<ordered_type_config>(const typename basic_value<ordered_type_config>::key_type& k,12427const basic_value<ordered_type_config>& v, const spec);1242812429extern template typename basic_value<type_config>::string_type12430format<ordered_type_config>(const std::vector<typename basic_value<ordered_type_config>::key_type>& ks,12431const basic_value<ordered_type_config>& v, const spec s);1243212433namespace detail12434{12435extern template class serializer<::toml::type_config>;12436extern template class serializer<::toml::ordered_type_config>;12437} // detail12438} // TOML11_INLINE_VERSION_NAMESPACE12439} // toml12440#endif // TOML11_COMPILE_SOURCES124411244212443#endif // TOML11_SERIALIZER_HPP12444#ifndef TOML11_GET_HPP12445#define TOML11_GET_HPP1244612447#include <algorithm>124481244912450#if defined(TOML11_HAS_STRING_VIEW)12451#include <string_view>12452#endif // string_view1245312454namespace toml12455{12456inline namespace TOML11_INLINE_VERSION_NAMESPACE12457{1245812459// ============================================================================12460// T is toml::value; identity transformation.1246112462template<typename T, typename TC>12463cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T>&12464get(basic_value<TC>& v)12465{12466return v;12467}1246812469template<typename T, typename TC>12470cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T> const&12471get(const basic_value<TC>& v)12472{12473return v;12474}1247512476template<typename T, typename TC>12477cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T>12478get(basic_value<TC>&& v)12479{12480return basic_value<TC>(std::move(v));12481}1248212483// ============================================================================12484// exact toml::* type1248512486template<typename T, typename TC>12487cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T> &12488get(basic_value<TC>& v)12489{12490constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;12491return detail::getter<TC, ty>::get(v);12492}1249312494template<typename T, typename TC>12495cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T> const&12496get(const basic_value<TC>& v)12497{12498constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;12499return detail::getter<TC, ty>::get(v);12500}1250112502template<typename T, typename TC>12503cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T>12504get(basic_value<TC>&& v)12505{12506constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;12507return detail::getter<TC, ty>::get(std::move(v));12508}1250912510// ============================================================================12511// T is toml::basic_value<U>1251212513template<typename T, typename TC>12514cxx::enable_if_t<cxx::conjunction<12515detail::is_basic_value<T>,12516cxx::negation<std::is_same<T, basic_value<TC>>>12517>::value, T>12518get(basic_value<TC> v)12519{12520return T(std::move(v));12521}1252212523// ============================================================================12524// integer convertible from toml::value::integer_type1252512526template<typename T, typename TC>12527cxx::enable_if_t<cxx::conjunction<12528std::is_integral<T>,12529cxx::negation<std::is_same<T, bool>>,12530detail::is_not_toml_type<T, basic_value<TC>>,12531cxx::negation<detail::has_from_toml_method<T, TC>>,12532cxx::negation<detail::has_specialized_from<T>>12533>::value, T>12534get(const basic_value<TC>& v)12535{12536return static_cast<T>(v.as_integer());12537}1253812539// ============================================================================12540// floating point convertible from toml::value::floating_type1254112542template<typename T, typename TC>12543cxx::enable_if_t<cxx::conjunction<12544std::is_floating_point<T>,12545detail::is_not_toml_type<T, basic_value<TC>>,12546cxx::negation<detail::has_from_toml_method<T, TC>>,12547cxx::negation<detail::has_specialized_from<T>>12548>::value, T>12549get(const basic_value<TC>& v)12550{12551return static_cast<T>(v.as_floating());12552}1255312554// ============================================================================12555// std::string with different char/trait/allocator1255612557template<typename T, typename TC>12558cxx::enable_if_t<cxx::conjunction<12559detail::is_not_toml_type<T, basic_value<TC>>,12560detail::is_1byte_std_basic_string<T>12561>::value, T>12562get(const basic_value<TC>& v)12563{12564return detail::string_conv<cxx::remove_cvref_t<T>>(v.as_string());12565}1256612567// ============================================================================12568// std::string_view1256912570#if defined(TOML11_HAS_STRING_VIEW)1257112572template<typename T, typename TC>12573cxx::enable_if_t<detail::is_string_view_of<T, typename basic_value<TC>::string_type>::value, T>12574get(const basic_value<TC>& v)12575{12576return T(v.as_string());12577}1257812579#endif // string_view1258012581// ============================================================================12582// std::chrono::duration from toml::local_time1258312584template<typename T, typename TC>12585cxx::enable_if_t<detail::is_chrono_duration<T>::value, T>12586get(const basic_value<TC>& v)12587{12588return std::chrono::duration_cast<T>(12589std::chrono::nanoseconds(v.as_local_time()));12590}1259112592// ============================================================================12593// std::chrono::system_clock::time_point from toml::datetime variants1259412595template<typename T, typename TC>12596cxx::enable_if_t<12597std::is_same<std::chrono::system_clock::time_point, T>::value, T>12598get(const basic_value<TC>& v)12599{12600switch(v.type())12601{12602case value_t::local_date:12603{12604return std::chrono::system_clock::time_point(v.as_local_date());12605}12606case value_t::local_datetime:12607{12608return std::chrono::system_clock::time_point(v.as_local_datetime());12609}12610case value_t::offset_datetime:12611{12612return std::chrono::system_clock::time_point(v.as_offset_datetime());12613}12614default:12615{12616const auto loc = v.location();12617throw type_error(format_error("toml::get: "12618"bad_cast to std::chrono::system_clock::time_point", loc,12619"the actual type is " + to_string(v.type())), loc);12620}12621}12622}1262312624// ============================================================================12625// forward declaration to use this recursively. ignore this and go ahead.1262612627// array-like (w/ push_back)12628template<typename T, typename TC>12629cxx::enable_if_t<cxx::conjunction<12630detail::is_container<T>, // T is a container12631detail::has_push_back_method<T>, // .push_back() works12632detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array12633cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>12634#if defined(TOML11_HAS_STRING_VIEW)12635cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>12636#endif12637cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12638cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12639cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12640>::value, T>12641get(const basic_value<TC>&);1264212643// std::array12644template<typename T, typename TC>12645cxx::enable_if_t<detail::is_std_array<T>::value, T>12646get(const basic_value<TC>&);1264712648// std::forward_list12649template<typename T, typename TC>12650cxx::enable_if_t<detail::is_std_forward_list<T>::value, T>12651get(const basic_value<TC>&);1265212653// std::pair<T1, T2>12654template<typename T, typename TC>12655cxx::enable_if_t<detail::is_std_pair<T>::value, T>12656get(const basic_value<TC>&);1265712658// std::tuple<T1, T2, ...>12659template<typename T, typename TC>12660cxx::enable_if_t<detail::is_std_tuple<T>::value, T>12661get(const basic_value<TC>&);1266212663// std::map<key, value> (key is convertible from toml::value::key_type)12664template<typename T, typename TC>12665cxx::enable_if_t<cxx::conjunction<12666detail::is_map<T>, // T is map12667detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table12668std::is_convertible<typename basic_value<TC>::key_type,12669typename T::key_type>, // keys are convertible12670cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12671cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12672cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12673>::value, T>12674get(const basic_value<TC>& v);1267512676// std::map<key, value> (key is not convertible from toml::value::key_type, but12677// is a std::basic_string)12678template<typename T, typename TC>12679cxx::enable_if_t<cxx::conjunction<12680detail::is_map<T>, // T is map12681detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table12682cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,12683typename T::key_type>>, // keys are NOT convertible12684detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string12685cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12686cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12687cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12688>::value, T>12689get(const basic_value<TC>& v);1269012691// toml::from<T>::from_toml(v)12692template<typename T, typename TC>12693cxx::enable_if_t<detail::has_specialized_from<T>::value, T>12694get(const basic_value<TC>&);1269512696// has T.from_toml(v) but no from<T>12697template<typename T, typename TC>12698cxx::enable_if_t<cxx::conjunction<12699detail::has_from_toml_method<T, TC>, // has T.from_toml()12700cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12701std::is_default_constructible<T> // T{} works12702>::value, T>12703get(const basic_value<TC>&);1270412705// T(const toml::value&) and T is not toml::basic_value,12706// and it does not have `from<T>` nor `from_toml`.12707template<typename T, typename TC>12708cxx::enable_if_t<cxx::conjunction<12709std::is_constructible<T, const basic_value<TC>&>, // has T(const basic_value&)12710cxx::negation<detail::is_basic_value<T>>, // but not basic_value itself12711cxx::negation<detail::has_from_toml_method<T, TC>>, // no .from_toml()12712cxx::negation<detail::has_specialized_from<T>> // no toml::from<T>12713>::value, T>12714get(const basic_value<TC>&);1271512716// ============================================================================12717// array-like types; most likely STL container, like std::vector, etc.1271812719template<typename T, typename TC>12720cxx::enable_if_t<cxx::conjunction<12721detail::is_container<T>, // T is a container12722detail::has_push_back_method<T>, // .push_back() works12723detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array12724cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>12725#if defined(TOML11_HAS_STRING_VIEW)12726cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>12727#endif12728cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12729cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12730cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12731>::value, T>12732get(const basic_value<TC>& v)12733{12734using value_type = typename T::value_type;12735const auto& a = v.as_array();1273612737T container;12738detail::try_reserve(container, a.size()); // if T has .reserve(), call it1273912740for(const auto& elem : a)12741{12742container.push_back(get<value_type>(elem));12743}12744return container;12745}1274612747// ============================================================================12748// std::array1274912750template<typename T, typename TC>12751cxx::enable_if_t<detail::is_std_array<T>::value, T>12752get(const basic_value<TC>& v)12753{12754using value_type = typename T::value_type;12755const auto& a = v.as_array();1275612757T container;12758if(a.size() != container.size())12759{12760const auto loc = v.location();12761throw std::out_of_range(format_error("toml::get: while converting to an array: "12762" array size is " + std::to_string(container.size()) +12763" but there are " + std::to_string(a.size()) + " elements in toml array.",12764loc, "here"));12765}12766for(std::size_t i=0; i<a.size(); ++i)12767{12768container.at(i) = ::toml::get<value_type>(a.at(i));12769}12770return container;12771}1277212773// ============================================================================12774// std::forward_list1277512776template<typename T, typename TC>12777cxx::enable_if_t<detail::is_std_forward_list<T>::value, T>12778get(const basic_value<TC>& v)12779{12780using value_type = typename T::value_type;1278112782T container;12783for(const auto& elem : v.as_array())12784{12785container.push_front(get<value_type>(elem));12786}12787container.reverse();12788return container;12789}1279012791// ============================================================================12792// std::pair1279312794template<typename T, typename TC>12795cxx::enable_if_t<detail::is_std_pair<T>::value, T>12796get(const basic_value<TC>& v)12797{12798using first_type = typename T::first_type;12799using second_type = typename T::second_type;1280012801const auto& ar = v.as_array();12802if(ar.size() != 2)12803{12804const auto loc = v.location();12805throw std::out_of_range(format_error("toml::get: while converting std::pair: "12806" but there are " + std::to_string(ar.size()) + " > 2 elements in toml array.",12807loc, "here"));12808}12809return std::make_pair(::toml::get<first_type >(ar.at(0)),12810::toml::get<second_type>(ar.at(1)));12811}1281212813// ============================================================================12814// std::tuple.1281512816namespace detail12817{12818template<typename T, typename Array, std::size_t ... I>12819T get_tuple_impl(const Array& a, cxx::index_sequence<I...>)12820{12821return std::make_tuple(12822::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);12823}12824} // detail1282512826template<typename T, typename TC>12827cxx::enable_if_t<detail::is_std_tuple<T>::value, T>12828get(const basic_value<TC>& v)12829{12830const auto& ar = v.as_array();12831if(ar.size() != std::tuple_size<T>::value)12832{12833const auto loc = v.location();12834throw std::out_of_range(format_error("toml::get: while converting std::tuple: "12835" there are " + std::to_string(ar.size()) + " > " +12836std::to_string(std::tuple_size<T>::value) + " elements in toml array.",12837loc, "here"));12838}12839return detail::get_tuple_impl<T>(ar,12840cxx::make_index_sequence<std::tuple_size<T>::value>{});12841}1284212843// ============================================================================12844// std::unordered_set1284512846template<typename T, typename TC>12847cxx::enable_if_t<toml::detail::is_unordered_set<T>::value, T>12848get(const basic_value<TC>& v)12849{12850using value_type = typename T::value_type;12851const auto& a = v.as_array();1285212853T container;12854for (const auto& elem : a)12855{12856container.insert(get<value_type>(elem));12857}12858return container;12859}128601286112862// ============================================================================12863// map-like types; most likely STL map, like std::map or std::unordered_map.1286412865// key is convertible from toml::value::key_type12866template<typename T, typename TC>12867cxx::enable_if_t<cxx::conjunction<12868detail::is_map<T>, // T is map12869detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table12870std::is_convertible<typename basic_value<TC>::key_type,12871typename T::key_type>, // keys are convertible12872cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12873cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12874cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12875>::value, T>12876get(const basic_value<TC>& v)12877{12878using key_type = typename T::key_type;12879using mapped_type = typename T::mapped_type;12880static_assert(12881std::is_convertible<typename basic_value<TC>::key_type, key_type>::value,12882"toml::get only supports map type of which key_type is "12883"convertible from toml::basic_value::key_type.");1288412885T m;12886for(const auto& kv : v.as_table())12887{12888m.emplace(key_type(kv.first), get<mapped_type>(kv.second));12889}12890return m;12891}1289212893// key is NOT convertible from toml::value::key_type but std::basic_string12894template<typename T, typename TC>12895cxx::enable_if_t<cxx::conjunction<12896detail::is_map<T>, // T is map12897detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table12898cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,12899typename T::key_type>>, // keys are NOT convertible12900detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string12901cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()12902cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12903cxx::negation<std::is_constructible<T, const basic_value<TC>&>>12904>::value, T>12905get(const basic_value<TC>& v)12906{12907using key_type = typename T::key_type;12908using mapped_type = typename T::mapped_type;1290912910T m;12911for(const auto& kv : v.as_table())12912{12913m.emplace(detail::string_conv<key_type>(kv.first), get<mapped_type>(kv.second));12914}12915return m;12916}1291712918// ============================================================================12919// user-defined, but convertible types.1292012921// toml::from<T>12922template<typename T, typename TC>12923cxx::enable_if_t<detail::has_specialized_from<T>::value, T>12924get(const basic_value<TC>& v)12925{12926return ::toml::from<T>::from_toml(v);12927}1292812929// has T.from_toml(v) but no from<T>12930template<typename T, typename TC>12931cxx::enable_if_t<cxx::conjunction<12932detail::has_from_toml_method<T, TC>, // has T.from_toml()12933cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>12934std::is_default_constructible<T> // T{} works12935>::value, T>12936get(const basic_value<TC>& v)12937{12938T ud;12939ud.from_toml(v);12940return ud;12941}1294212943// T(const toml::value&) and T is not toml::basic_value,12944// and it does not have `from<T>` nor `from_toml`.12945template<typename T, typename TC>12946cxx::enable_if_t<cxx::conjunction<12947std::is_constructible<T, const basic_value<TC>&>, // has T(const basic_value&)12948cxx::negation<detail::is_basic_value<T>>, // but not basic_value itself12949cxx::negation<detail::has_from_toml_method<T, TC>>, // no .from_toml()12950cxx::negation<detail::has_specialized_from<T>> // no toml::from<T>12951>::value, T>12952get(const basic_value<TC>& v)12953{12954return T(v);12955}1295612957// ============================================================================12958// get_or(value, fallback)1295912960template<typename TC>12961cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&12962get_or(const basic_value<TC>& v, const basic_value<TC>&)12963{12964return v;12965}1296612967template<typename TC>12968cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&12969get_or(basic_value<TC>& v, basic_value<TC>&)12970{12971return v;12972}1297312974template<typename TC>12975cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>12976get_or(basic_value<TC>&& v, basic_value<TC>&&)12977{12978return v;12979}1298012981// ----------------------------------------------------------------------------12982// specialization for the exact toml types (return type becomes lvalue ref)1298312984template<typename T, typename TC>12985cxx::enable_if_t<12986detail::is_exact_toml_type<T, basic_value<TC>>::value, T> const&12987get_or(const basic_value<TC>& v, const T& opt) noexcept12988{12989try12990{12991return get<cxx::remove_cvref_t<T>>(v);12992}12993catch(...)12994{12995return opt;12996}12997}12998template<typename T, typename TC>12999cxx::enable_if_t<cxx::conjunction<13000cxx::negation<std::is_const<T>>,13001detail::is_exact_toml_type<T, basic_value<TC>>13002>::value, T>&13003get_or(basic_value<TC>& v, T& opt) noexcept13004{13005try13006{13007return get<cxx::remove_cvref_t<T>>(v);13008}13009catch(...)13010{13011return opt;13012}13013}13014template<typename T, typename TC>13015cxx::enable_if_t<detail::is_exact_toml_type<cxx::remove_cvref_t<T>,13016basic_value<TC>>::value, cxx::remove_cvref_t<T>>13017get_or(basic_value<TC>&& v, T&& opt) noexcept13018{13019try13020{13021return get<cxx::remove_cvref_t<T>>(std::move(v));13022}13023catch(...)13024{13025return cxx::remove_cvref_t<T>(std::forward<T>(opt));13026}13027}1302813029// ----------------------------------------------------------------------------13030// specialization for string literal1303113032// template<std::size_t N, typename TC>13033// typename basic_value<TC>::string_type13034// get_or(const basic_value<TC>& v,13035// const typename basic_value<TC>::string_type::value_type (&opt)[N])13036// {13037// try13038// {13039// return v.as_string();13040// }13041// catch(...)13042// {13043// return typename basic_value<TC>::string_type(opt);13044// }13045// }13046//13047// The above only matches to the literal, like `get_or(v, "foo");` but not13048// ```cpp13049// const auto opt = "foo";13050// const auto str = get_or(v, opt);13051// ```13052// . And the latter causes an error.13053// To match to both `"foo"` and `const auto opt = "foo"`, we take a pointer to13054// a character here.1305513056template<typename TC>13057typename basic_value<TC>::string_type13058get_or(const basic_value<TC>& v,13059const typename basic_value<TC>::string_type::value_type* opt)13060{13061try13062{13063return v.as_string();13064}13065catch(...)13066{13067return typename basic_value<TC>::string_type(opt);13068}13069}1307013071// ----------------------------------------------------------------------------13072// others (require type conversion and return type cannot be lvalue reference)1307313074template<typename T, typename TC>13075cxx::enable_if_t<cxx::conjunction<13076cxx::negation<detail::is_basic_value<T>>,13077cxx::negation<detail::is_exact_toml_type<T, basic_value<TC>>>,13078cxx::negation<std::is_same<cxx::remove_cvref_t<T>, typename basic_value<TC>::string_type::value_type const*>>13079>::value, cxx::remove_cvref_t<T>>13080get_or(const basic_value<TC>& v, T&& opt)13081{13082try13083{13084return get<cxx::remove_cvref_t<T>>(v);13085}13086catch(...)13087{13088return cxx::remove_cvref_t<T>(std::forward<T>(opt));13089}13090}1309113092} // TOML11_INLINE_VERSION_NAMESPACE13093} // toml13094#endif // TOML11_GET_HPP13095#ifndef TOML11_FIND_HPP13096#define TOML11_FIND_HPP1309713098#include <algorithm>130991310013101#if defined(TOML11_HAS_STRING_VIEW)13102#include <string_view>13103#endif1310413105namespace toml13106{13107inline namespace TOML11_INLINE_VERSION_NAMESPACE13108{1310913110// ----------------------------------------------------------------------------13111// find<T>(value, key);1311213113template<typename T, typename TC>13114cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13115decltype(::toml::get<T>(std::declval<basic_value<TC> const&>()))>13116find(const basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)13117{13118return ::toml::get<T>(v.at(ky));13119}1312013121template<typename T, typename TC>13122cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13123decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))>13124find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)13125{13126return ::toml::get<T>(v.at(ky));13127}1312813129template<typename T, typename TC>13130cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13131decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))>13132find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky)13133{13134return ::toml::get<T>(std::move(v.at(ky)));13135}1313613137// ----------------------------------------------------------------------------13138// find<T>(value, idx)1313913140template<typename T, typename TC>13141cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13142decltype(::toml::get<T>(std::declval<basic_value<TC> const&>()))>13143find(const basic_value<TC>& v, const std::size_t idx)13144{13145return ::toml::get<T>(v.at(idx));13146}13147template<typename T, typename TC>13148cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13149decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))>13150find(basic_value<TC>& v, const std::size_t idx)13151{13152return ::toml::get<T>(v.at(idx));13153}13154template<typename T, typename TC>13155cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13156decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))>13157find(basic_value<TC>&& v, const std::size_t idx)13158{13159return ::toml::get<T>(std::move(v.at(idx)));13160}1316113162// ----------------------------------------------------------------------------13163// find(value, key/idx), w/o conversion1316413165template<typename TC>13166cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&13167find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)13168{13169return v.at(ky);13170}13171template<typename TC>13172cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&13173find(basic_value<TC> const& v, const typename basic_value<TC>::key_type& ky)13174{13175return v.at(ky);13176}13177template<typename TC>13178cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>13179find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky)13180{13181return basic_value<TC>(std::move(v.at(ky)));13182}1318313184template<typename TC>13185cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&13186find(basic_value<TC>& v, const std::size_t idx)13187{13188return v.at(idx);13189}13190template<typename TC>13191cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&13192find(basic_value<TC> const& v, const std::size_t idx)13193{13194return v.at(idx);13195}13196template<typename TC>13197cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>13198find(basic_value<TC>&& v, const std::size_t idx)13199{13200return basic_value<TC>(std::move(v.at(idx)));13201}1320213203// --------------------------------------------------------------------------13204// find<optional<T>>1320513206#if defined(TOML11_HAS_OPTIONAL)13207template<typename T, typename TC>13208cxx::enable_if_t<detail::is_std_optional<T>::value, T>13209find(const basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)13210{13211if(v.contains(ky))13212{13213return ::toml::get<typename T::value_type>(v.at(ky));13214}13215else13216{13217return std::nullopt;13218}13219}1322013221template<typename T, typename TC>13222cxx::enable_if_t<detail::is_std_optional<T>::value, T>13223find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)13224{13225if(v.contains(ky))13226{13227return ::toml::get<typename T::value_type>(v.at(ky));13228}13229else13230{13231return std::nullopt;13232}13233}1323413235template<typename T, typename TC>13236cxx::enable_if_t<detail::is_std_optional<T>::value, T>13237find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky)13238{13239if(v.contains(ky))13240{13241return ::toml::get<typename T::value_type>(std::move(v.at(ky)));13242}13243else13244{13245return std::nullopt;13246}13247}1324813249template<typename T, typename K, typename TC>13250cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K>::value, T>13251find(const basic_value<TC>& v, const K& k)13252{13253if(static_cast<std::size_t>(k) < v.size())13254{13255return ::toml::get<typename T::value_type>(v.at(static_cast<std::size_t>(k)));13256}13257else13258{13259return std::nullopt;13260}13261}1326213263template<typename T, typename K, typename TC>13264cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K>::value, T>13265find(basic_value<TC>& v, const K& k)13266{13267if(static_cast<std::size_t>(k) < v.size())13268{13269return ::toml::get<typename T::value_type>(v.at(static_cast<std::size_t>(k)));13270}13271else13272{13273return std::nullopt;13274}13275}1327613277template<typename T, typename K, typename TC>13278cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K>::value, T>13279find(basic_value<TC>&& v, const K& k)13280{13281if(static_cast<std::size_t>(k) < v.size())13282{13283return ::toml::get<typename T::value_type>(std::move(v.at(static_cast<std::size_t>(k))));13284}13285else13286{13287return std::nullopt;13288}13289}13290#endif // optional1329113292// --------------------------------------------------------------------------13293// toml::find(toml::value, toml::key, Ts&& ... keys)1329413295namespace detail13296{1329713298// It suppresses warnings by -Wsign-conversion when we pass integer literal13299// to toml::find. integer literal `0` is deduced as an int, and will be13300// converted to std::size_t. This causes sign-conversion.1330113302template<typename TC>13303std::size_t key_cast(const std::size_t& v) noexcept13304{13305return v;13306}13307template<typename TC, typename T>13308cxx::enable_if_t<std::is_integral<cxx::remove_cvref_t<T>>::value, std::size_t>13309key_cast(const T& v) noexcept13310{13311return static_cast<std::size_t>(v);13312}1331313314// for string-like (string, string literal, string_view)1331513316template<typename TC>13317typename basic_value<TC>::key_type const&13318key_cast(const typename basic_value<TC>::key_type& v) noexcept13319{13320return v;13321}13322template<typename TC>13323typename basic_value<TC>::key_type13324key_cast(const typename basic_value<TC>::key_type::value_type* v)13325{13326return typename basic_value<TC>::key_type(v);13327}13328#if defined(TOML11_HAS_STRING_VIEW)13329template<typename TC>13330typename basic_value<TC>::key_type13331key_cast(const std::string_view v)13332{13333return typename basic_value<TC>::key_type(v);13334}13335#endif // string_view1333613337} // detail1333813339// ----------------------------------------------------------------------------13340// find(v, keys...)1334113342template<typename TC, typename K1, typename K2, typename ... Ks>13343cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&13344find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13345{13346return find(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);13347}13348template<typename TC, typename K1, typename K2, typename ... Ks>13349cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&13350find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13351{13352return find(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);13353}13354template<typename TC, typename K1, typename K2, typename ... Ks>13355cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>13356find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks)13357{13358return find(std::move(v.at(detail::key_cast<TC>(k1))), detail::key_cast<TC>(k2), ks...);13359}1336013361// ----------------------------------------------------------------------------13362// find<T>(v, keys...)1336313364template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13365cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13366decltype(::toml::get<T>(std::declval<const basic_value<TC>&>()))>13367find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13368{13369return find<T>(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);13370}13371template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13372cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13373decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))>13374find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13375{13376return find<T>(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);13377}13378template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13379cxx::enable_if_t<cxx::negation<detail::is_std_optional<T>>::value,13380decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))>13381find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks)13382{13383return find<T>(std::move(v.at(detail::key_cast<TC>(k1))), detail::key_cast<TC>(k2), ks...);13384}1338513386#if defined(TOML11_HAS_OPTIONAL)13387template<typename T, typename TC, typename K2, typename ... Ks>13388cxx::enable_if_t<detail::is_std_optional<T>::value, T>13389find(const basic_value<TC>& v, const typename basic_value<TC>::key_type& k1, const K2& k2, const Ks& ... ks)13390{13391if(v.contains(k1))13392{13393return find<T>(v.at(k1), detail::key_cast<TC>(k2), ks...);13394}13395else13396{13397return std::nullopt;13398}13399}13400template<typename T, typename TC, typename K2, typename ... Ks>13401cxx::enable_if_t<detail::is_std_optional<T>::value, T>13402find(basic_value<TC>& v, const typename basic_value<TC>::key_type& k1, const K2& k2, const Ks& ... ks)13403{13404if(v.contains(k1))13405{13406return find<T>(v.at(k1), detail::key_cast<TC>(k2), ks...);13407}13408else13409{13410return std::nullopt;13411}13412}13413template<typename T, typename TC, typename K2, typename ... Ks>13414cxx::enable_if_t<detail::is_std_optional<T>::value, T>13415find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& k1, const K2& k2, const Ks& ... ks)13416{13417if(v.contains(k1))13418{13419return find<T>(v.at(k1), detail::key_cast<TC>(k2), ks...);13420}13421else13422{13423return std::nullopt;13424}13425}1342613427template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13428cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K1>::value, T>13429find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13430{13431if(static_cast<std::size_t>(k1) < v.size())13432{13433return find<T>(v.at(static_cast<std::size_t>(k1)), detail::key_cast<TC>(k2), ks...);13434}13435else13436{13437return std::nullopt;13438}13439}13440template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13441cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K1>::value, T>13442find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)13443{13444if(static_cast<std::size_t>(k1) < v.size())13445{13446return find<T>(v.at(static_cast<std::size_t>(k1)), detail::key_cast<TC>(k2), ks...);13447}13448else13449{13450return std::nullopt;13451}13452}13453template<typename T, typename TC, typename K1, typename K2, typename ... Ks>13454cxx::enable_if_t<detail::is_std_optional<T>::value && std::is_integral<K1>::value, T>13455find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks)13456{13457if(static_cast<std::size_t>(k1) < v.size())13458{13459return find<T>(v.at(static_cast<std::size_t>(k1)), detail::key_cast<TC>(k2), ks...);13460}13461else13462{13463return std::nullopt;13464}13465}13466#endif // optional1346713468// ===========================================================================13469// find_or<T>(value, key, fallback)1347013471// ---------------------------------------------------------------------------13472// find_or(v, key, other_v)1347313474template<typename TC, typename K>13475cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&13476find_or(basic_value<TC>& v, const K& k, basic_value<TC>& opt) noexcept13477{13478try13479{13480return ::toml::find(v, detail::key_cast<TC>(k));13481}13482catch(...)13483{13484return opt;13485}13486}13487template<typename TC, typename K>13488cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&13489find_or(const basic_value<TC>& v, const K& k, const basic_value<TC>& opt) noexcept13490{13491try13492{13493return ::toml::find(v, detail::key_cast<TC>(k));13494}13495catch(...)13496{13497return opt;13498}13499}13500template<typename TC, typename K>13501cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>13502find_or(basic_value<TC>&& v, const K& k, basic_value<TC>&& opt) noexcept13503{13504try13505{13506return ::toml::find(v, detail::key_cast<TC>(k));13507}13508catch(...)13509{13510return opt;13511}13512}1351313514// ---------------------------------------------------------------------------13515// toml types (return type can be a reference)1351613517template<typename T, typename TC, typename K>13518cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,13519cxx::remove_cvref_t<T> const&>13520find_or(const basic_value<TC>& v, const K& k, const T& opt)13521{13522try13523{13524return ::toml::get<T>(v.at(detail::key_cast<TC>(k)));13525}13526catch(...)13527{13528return opt;13529}13530}1353113532template<typename T, typename TC, typename K>13533cxx::enable_if_t<cxx::conjunction<13534cxx::negation<std::is_const<T>>,13535detail::is_exact_toml_type<T, basic_value<TC>>13536>::value, cxx::remove_cvref_t<T>&>13537find_or(basic_value<TC>& v, const K& k, T& opt)13538{13539try13540{13541return ::toml::get<T>(v.at(detail::key_cast<TC>(k)));13542}13543catch(...)13544{13545return opt;13546}13547}1354813549template<typename T, typename TC, typename K>13550cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,13551cxx::remove_cvref_t<T>>13552find_or(basic_value<TC>&& v, const K& k, T opt)13553{13554try13555{13556return ::toml::get<T>(std::move(v.at(detail::key_cast<TC>(k))));13557}13558catch(...)13559{13560return T(std::move(opt));13561}13562}1356313564// ---------------------------------------------------------------------------13565// string literal (deduced as std::string)1356613567// XXX to avoid confusion when T is explicitly specified in find_or<T>(),13568// we restrict the string type as std::string.13569template<typename TC, typename K>13570cxx::enable_if_t<detail::is_type_config<TC>::value, std::string>13571find_or(const basic_value<TC>& v, const K& k, const char* opt)13572{13573try13574{13575return ::toml::get<std::string>(v.at(detail::key_cast<TC>(k)));13576}13577catch(...)13578{13579return std::string(opt);13580}13581}1358213583// ---------------------------------------------------------------------------13584// other types (requires type conversion and return type cannot be a reference)1358513586template<typename T, typename TC, typename K>13587cxx::enable_if_t<cxx::conjunction<13588cxx::negation<detail::is_basic_value<cxx::remove_cvref_t<T>>>,13589detail::is_not_toml_type<cxx::remove_cvref_t<T>, basic_value<TC>>,13590cxx::negation<std::is_same<cxx::remove_cvref_t<T>,13591const typename basic_value<TC>::string_type::value_type*>>13592>::value, cxx::remove_cvref_t<T>>13593find_or(const basic_value<TC>& v, const K& ky, T opt)13594{13595try13596{13597return ::toml::get<cxx::remove_cvref_t<T>>(v.at(detail::key_cast<TC>(ky)));13598}13599catch(...)13600{13601return cxx::remove_cvref_t<T>(std::move(opt));13602}13603}1360413605// ----------------------------------------------------------------------------13606// recursive1360713608namespace detail13609{1361013611template<typename ...Ts>13612auto last_one(Ts&&... args)13613-> decltype(std::get<sizeof...(Ts)-1>(std::forward_as_tuple(std::forward<Ts>(args)...)))13614{13615return std::get<sizeof...(Ts)-1>(std::forward_as_tuple(std::forward<Ts>(args)...));13616}1361713618} // detail1361913620template<typename Value, typename K1, typename K2, typename K3, typename ... Ks>13621auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&& ... keys) noexcept13622-> cxx::enable_if_t<13623detail::is_basic_value<cxx::remove_cvref_t<Value>>::value,13624decltype(find_or(v, k2, std::forward<K3>(k3), std::forward<Ks>(keys)...))13625>13626{13627try13628{13629return find_or(v.at(k1), k2, std::forward<K3>(k3), std::forward<Ks>(keys)...);13630}13631catch(...)13632{13633return detail::last_one(k3, keys...);13634}13635}1363613637template<typename T, typename TC, typename K1, typename K2, typename K3, typename ... Ks>13638T find_or(const basic_value<TC>& v, const K1& k1, const K2& k2, const K3& k3, const Ks& ... keys) noexcept13639{13640try13641{13642return find_or<T>(v.at(k1), k2, k3, keys...);13643}13644catch(...)13645{13646return static_cast<T>(detail::last_one(k3, keys...));13647}13648}1364913650// ===========================================================================13651// find_or_default<T>(value, key)1365213653template<typename T, typename TC, typename K>13654cxx::enable_if_t<std::is_default_constructible<T>::value, T>13655find_or_default(const basic_value<TC>& v, K&& k) noexcept(std::is_nothrow_default_constructible<T>::value)13656{13657try13658{13659return ::toml::get<T>(v.at(detail::key_cast<TC>(std::forward<K>(k))));13660}13661catch(...)13662{13663return T();13664}13665}1366613667template<typename T, typename TC, typename K1, typename ... Ks>13668cxx::enable_if_t<std::is_default_constructible<T>::value, T>13669find_or_default(const basic_value<TC>& v, K1&& k1, Ks&& ... keys) noexcept(std::is_nothrow_default_constructible<T>::value)13670{13671try13672{13673return find_or_default<T>(v.at(std::forward<K1>(k1)), std::forward<Ks>(keys)...);13674}13675catch(...)13676{13677return T();13678}13679}1368013681} // TOML11_INLINE_VERSION_NAMESPACE13682} // toml13683#endif // TOML11_FIND_HPP13684#ifndef TOML11_CONVERSION_HPP13685#define TOML11_CONVERSION_HPP136861368713688#if defined(TOML11_HAS_OPTIONAL)1368913690#include <optional>1369113692namespace toml13693{13694inline namespace TOML11_INLINE_VERSION_NAMESPACE13695{13696namespace detail13697{1369813699template<typename T>13700inline constexpr bool is_optional_v = false;1370113702template<typename T>13703inline constexpr bool is_optional_v<std::optional<T>> = true;1370413705template<typename T, typename TC>13706void find_member_variable_from_value(T& obj, const basic_value<TC>& v, const char* var_name)13707{13708if constexpr(is_optional_v<T>)13709{13710if(v.contains(var_name))13711{13712obj = toml::find<typename T::value_type>(v, var_name);13713}13714else13715{13716obj = std::nullopt;13717}13718}13719else13720{13721obj = toml::find<T>(v, var_name);13722}13723}1372413725template<typename T, typename TC>13726void assign_member_variable_to_value(const T& obj, basic_value<TC>& v, const char* var_name)13727{13728if constexpr(is_optional_v<T>)13729{13730if(obj.has_value())13731{13732v[var_name] = obj.value();13733}13734}13735else13736{13737v[var_name] = obj;13738}13739}1374013741} // detail13742} // TOML11_INLINE_VERSION_NAMESPACE13743} // toml1374413745#else1374613747namespace toml13748{13749inline namespace TOML11_INLINE_VERSION_NAMESPACE13750{13751namespace detail13752{1375313754template<typename T, typename TC>13755void find_member_variable_from_value(T& obj, const basic_value<TC>& v, const char* var_name)13756{13757obj = toml::find<T>(v, var_name);13758}1375913760template<typename T, typename TC>13761void assign_member_variable_to_value(const T& obj, basic_value<TC>& v, const char* var_name)13762{13763v[var_name] = obj;13764}1376513766} // detail13767} // TOML11_INLINE_VERSION_NAMESPACE13768} // toml1376913770#endif // optional1377113772// use it in the following way.13773// ```cpp13774// namespace foo13775// {13776// struct Foo13777// {13778// std::string s;13779// double d;13780// int i;13781// };13782// } // foo13783//13784// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)13785// ```13786//13787// And then you can use `toml::get<foo::Foo>(v)` and `toml::find<foo::Foo>(file, "foo");`13788//1378913790#define TOML11_STRINGIZE_AUX(x) #x13791#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)1379213793#define TOML11_CONCATENATE_AUX(x, y) x##y13794#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)1379513796// ============================================================================13797// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE1379813799#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE1380013801// ----------------------------------------------------------------------------13802// TOML11_ARGS_SIZE1380313804#define TOML11_INDEX_RSEQ() \1380532, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \1380616, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 013807#define TOML11_ARGS_SIZE_IMPL(\13808ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \13809ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \13810ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \13811ARG31, ARG32, N, ...) N13812#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)13813#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())1381413815// ----------------------------------------------------------------------------13816// TOML11_FOR_EACH_VA_ARGS1381713818#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)13819#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)13820#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)13821#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)13822#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)13823#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)13824#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)13825#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)13826#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)13827#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)13828#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)13829#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)13830#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)13831#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)13832#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)13833#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)13834#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)13835#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)13836#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)13837#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)13838#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)13839#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)13840#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)13841#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)13842#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)13843#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)13844#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)13845#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)13846#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)13847#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)13848#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)13849#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)1385013851#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\13852TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)138531385413855#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\13856toml::detail::find_member_variable_from_value(obj.VAR_NAME, v, TOML11_STRINGIZE(VAR_NAME));1385713858#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\13859toml::detail::assign_member_variable_to_value(obj.VAR_NAME, v, TOML11_STRINGIZE(VAR_NAME));1386013861#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\13862namespace toml { \13863inline namespace TOML11_INLINE_VERSION_NAMESPACE { \13864template<> \13865struct from<NAME> \13866{ \13867template<typename TC> \13868static NAME from_toml(const basic_value<TC>& v) \13869{ \13870NAME obj; \13871TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \13872return obj; \13873} \13874}; \13875template<> \13876struct into<NAME> \13877{ \13878template<typename TC> \13879static basic_value<TC> into_toml(const NAME& obj) \13880{ \13881::toml::basic_value<TC> v = typename ::toml::basic_value<TC>::table_type{}; \13882TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \13883return v; \13884} \13885}; \13886} /* TOML11_INLINE_VERSION_NAMESPACE */ \13887} /* toml */1388813889#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE1389013891#endif // TOML11_CONVERSION_HPP13892#ifndef TOML11_CONTEXT_HPP13893#define TOML11_CONTEXT_HPP138941389513896#include <vector>1389713898namespace toml13899{13900inline namespace TOML11_INLINE_VERSION_NAMESPACE13901{13902namespace detail13903{1390413905template<typename TypeConfig>13906class context13907{13908public:1390913910explicit context(const spec& toml_spec)13911: toml_spec_(toml_spec), errors_{}13912{}1391313914bool has_error() const noexcept {return !errors_.empty();}1391513916std::vector<error_info> const& errors() const noexcept {return errors_;}1391713918semantic_version& toml_version() noexcept {return toml_spec_.version;}13919semantic_version const& toml_version() const noexcept {return toml_spec_.version;}1392013921spec& toml_spec() noexcept {return toml_spec_;}13922spec const& toml_spec() const noexcept {return toml_spec_;}1392313924void report_error(error_info err)13925{13926this->errors_.push_back(std::move(err));13927}1392813929error_info pop_last_error()13930{13931assert( ! errors_.empty());13932auto e = std::move(errors_.back());13933errors_.pop_back();13934return e;13935}1393613937private:1393813939spec toml_spec_;13940std::vector<error_info> errors_;13941};1394213943} // detail13944} // TOML11_INLINE_VERSION_NAMESPACE13945} // toml1394613947#if defined(TOML11_COMPILE_SOURCES)13948namespace toml13949{13950inline namespace TOML11_INLINE_VERSION_NAMESPACE13951{13952struct type_config;13953struct ordered_type_config;13954namespace detail13955{13956extern template class context<::toml::type_config>;13957extern template class context<::toml::ordered_type_config>;13958} // detail13959} // TOML11_INLINE_VERSION_NAMESPACE13960} // toml13961#endif // TOML11_COMPILE_SOURCES1396213963#endif // TOML11_CONTEXT_HPP13964#ifndef TOML11_SKIP_HPP13965#define TOML11_SKIP_HPP139661396713968#include <cassert>1396913970namespace toml13971{13972inline namespace TOML11_INLINE_VERSION_NAMESPACE13973{13974namespace detail13975{1397613977template<typename TC>13978bool skip_whitespace(location& loc, const context<TC>& ctx)13979{13980return syntax::ws(ctx.toml_spec()).scan(loc).is_ok();13981}1398213983template<typename TC>13984bool skip_empty_lines(location& loc, const context<TC>& ctx)13985{13986return repeat_at_least(1, sequence(13987syntax::ws(ctx.toml_spec()),13988syntax::newline(ctx.toml_spec())13989)).scan(loc).is_ok();13990}1399113992// For error recovery.13993//13994// In case if a comment line contains an invalid character, we need to skip it13995// to advance parsing.13996template<typename TC>13997void skip_comment_block(location& loc, const context<TC>& ctx)13998{13999while( ! loc.eof())14000{14001skip_whitespace(loc, ctx);14002if(loc.current() == '#')14003{14004while( ! loc.eof())14005{14006// both CRLF and LF ends with LF.14007if(loc.current() == '\n')14008{14009loc.advance();14010break;14011}14012}14013}14014else if(syntax::newline(ctx.toml_spec()).scan(loc).is_ok())14015{14016; // an empty line. skip this also14017}14018else14019{14020// the next token is neither a comment nor empty line.14021return ;14022}14023}14024return ;14025}1402614027template<typename TC>14028void skip_empty_or_comment_lines(location& loc, const context<TC>& ctx)14029{14030const auto& spec = ctx.toml_spec();14031repeat_at_least(0, sequence(14032syntax::ws(spec),14033maybe(syntax::comment(spec)),14034syntax::newline(spec))14035).scan(loc);14036return ;14037}1403814039// For error recovery.14040//14041// Sometimes we need to skip a value and find a delimiter, like `,`, `]`, or `}`.14042// To find delimiter, we need to skip delimiters in a string.14043// Since we are skipping invalid value while error recovery, we don't need14044// to check the syntax. Here we just skip string-like region until closing quote14045// is found.14046template<typename TC>14047void skip_string_like(location& loc, const context<TC>&)14048{14049// if """ is found, skip until the closing """ is found.14050if(literal("\"\"\"").scan(loc).is_ok())14051{14052while( ! loc.eof())14053{14054if(literal("\"\"\"").scan(loc).is_ok())14055{14056return;14057}14058loc.advance();14059}14060}14061else if(literal("'''").scan(loc).is_ok())14062{14063while( ! loc.eof())14064{14065if(literal("'''").scan(loc).is_ok())14066{14067return;14068}14069loc.advance();14070}14071}14072// if " is found, skip until the closing " or newline is found.14073else if(loc.current() == '"')14074{14075while( ! loc.eof())14076{14077loc.advance();14078if(loc.current() == '"' || loc.current() == '\n')14079{14080loc.advance();14081return;14082}14083}14084}14085else if(loc.current() == '\'')14086{14087while( ! loc.eof())14088{14089loc.advance();14090if(loc.current() == '\'' || loc.current() == '\n')14091{14092loc.advance();14093return ;14094}14095}14096}14097return;14098}1409914100template<typename TC>14101void skip_value(location& loc, const context<TC>& ctx);14102template<typename TC>14103void skip_array_like(location& loc, const context<TC>& ctx);14104template<typename TC>14105void skip_inline_table_like(location& loc, const context<TC>& ctx);14106template<typename TC>14107void skip_key_value_pair(location& loc, const context<TC>& ctx);1410814109template<typename TC>14110result<value_t, error_info>14111guess_value_type(const location& loc, const context<TC>& ctx);1411214113template<typename TC>14114void skip_array_like(location& loc, const context<TC>& ctx)14115{14116const auto& spec = ctx.toml_spec();14117assert(loc.current() == '[');14118loc.advance();1411914120while( ! loc.eof())14121{14122if(loc.current() == '\"' || loc.current() == '\'')14123{14124skip_string_like(loc, ctx);14125}14126else if(loc.current() == '#')14127{14128skip_comment_block(loc, ctx);14129}14130else if(loc.current() == '{')14131{14132skip_inline_table_like(loc, ctx);14133}14134else if(loc.current() == '[')14135{14136const auto checkpoint = loc;14137if(syntax::std_table(spec).scan(loc).is_ok() ||14138syntax::array_table(spec).scan(loc).is_ok())14139{14140loc = checkpoint;14141break;14142}14143// if it is not a table-definition, then it is an array.14144skip_array_like(loc, ctx);14145}14146else if(loc.current() == '=')14147{14148// key-value pair cannot be inside the array.14149// guessing the error is "missing closing bracket `]`".14150// find the previous key just before `=`.14151while(loc.get_location() != 0)14152{14153loc.retrace();14154if(loc.current() == '\n')14155{14156loc.advance();14157break;14158}14159}14160break;14161}14162else if(loc.current() == ']')14163{14164break; // found closing bracket14165}14166else14167{14168loc.advance();14169}14170}14171return ;14172}1417314174template<typename TC>14175void skip_inline_table_like(location& loc, const context<TC>& ctx)14176{14177assert(loc.current() == '{');14178loc.advance();1417914180const auto& spec = ctx.toml_spec();1418114182while( ! loc.eof())14183{14184if(loc.current() == '\n' && ! spec.v1_1_0_allow_newlines_in_inline_tables)14185{14186break; // missing closing `}`.14187}14188else if(loc.current() == '\"' || loc.current() == '\'')14189{14190skip_string_like(loc, ctx);14191}14192else if(loc.current() == '#')14193{14194skip_comment_block(loc, ctx);14195if( ! spec.v1_1_0_allow_newlines_in_inline_tables)14196{14197// comment must end with newline.14198break; // missing closing `}`.14199}14200}14201else if(loc.current() == '[')14202{14203const auto checkpoint = loc;14204if(syntax::std_table(spec).scan(loc).is_ok() ||14205syntax::array_table(spec).scan(loc).is_ok())14206{14207loc = checkpoint;14208break; // missing closing `}`.14209}14210// if it is not a table-definition, then it is an array.14211skip_array_like(loc, ctx);14212}14213else if(loc.current() == '{')14214{14215skip_inline_table_like(loc, ctx);14216}14217else if(loc.current() == '}')14218{14219// closing brace found. guessing the error is inside the table.14220break;14221}14222else14223{14224// skip otherwise.14225loc.advance();14226}14227}14228return ;14229}1423014231template<typename TC>14232void skip_value(location& loc, const context<TC>& ctx)14233{14234value_t ty = guess_value_type(loc, ctx).unwrap_or(value_t::empty);14235if(ty == value_t::string)14236{14237skip_string_like(loc, ctx);14238}14239else if(ty == value_t::array)14240{14241skip_array_like(loc, ctx);14242}14243else if(ty == value_t::table)14244{14245// In case of multiline tables, it may skip key-value pair but not the14246// whole table.14247skip_inline_table_like(loc, ctx);14248}14249else // others are an "in-line" values. skip until the next line14250{14251while( ! loc.eof())14252{14253if(loc.current() == '\n')14254{14255break;14256}14257else if(loc.current() == ',' || loc.current() == ']' || loc.current() == '}')14258{14259break;14260}14261loc.advance();14262}14263}14264return;14265}1426614267template<typename TC>14268void skip_key_value_pair(location& loc, const context<TC>& ctx)14269{14270while( ! loc.eof())14271{14272if(loc.current() == '=')14273{14274skip_whitespace(loc, ctx);14275skip_value(loc, ctx);14276return;14277}14278else if(loc.current() == '\n')14279{14280// newline is found before finding `=`. assuming "missing `=`".14281return;14282}14283loc.advance();14284}14285return ;14286}1428714288template<typename TC>14289void skip_until_next_table(location& loc, const context<TC>& ctx)14290{14291const auto& spec = ctx.toml_spec();14292while( ! loc.eof())14293{14294if(loc.current() == '\n')14295{14296loc.advance();14297const auto line_begin = loc;1429814299skip_whitespace(loc, ctx);14300if(syntax::std_table(spec).scan(loc).is_ok())14301{14302loc = line_begin;14303return ;14304}14305if(syntax::array_table(spec).scan(loc).is_ok())14306{14307loc = line_begin;14308return ;14309}14310}14311loc.advance();14312}14313}1431414315} // namespace detail14316} // TOML11_INLINE_VERSION_NAMESPACE14317} // namespace toml1431814319#if defined(TOML11_COMPILE_SOURCES)14320namespace toml14321{14322inline namespace TOML11_INLINE_VERSION_NAMESPACE14323{14324struct type_config;14325struct ordered_type_config;1432614327namespace detail14328{14329extern template bool skip_whitespace <type_config>(location& loc, const context<type_config>&);14330extern template bool skip_empty_lines <type_config>(location& loc, const context<type_config>&);14331extern template void skip_comment_block <type_config>(location& loc, const context<type_config>&);14332extern template void skip_empty_or_comment_lines<type_config>(location& loc, const context<type_config>&);14333extern template void skip_string_like <type_config>(location& loc, const context<type_config>&);14334extern template void skip_array_like <type_config>(location& loc, const context<type_config>&);14335extern template void skip_inline_table_like <type_config>(location& loc, const context<type_config>&);14336extern template void skip_value <type_config>(location& loc, const context<type_config>&);14337extern template void skip_key_value_pair <type_config>(location& loc, const context<type_config>&);14338extern template void skip_until_next_table <type_config>(location& loc, const context<type_config>&);1433914340extern template bool skip_whitespace <ordered_type_config>(location& loc, const context<ordered_type_config>&);14341extern template bool skip_empty_lines <ordered_type_config>(location& loc, const context<ordered_type_config>&);14342extern template void skip_comment_block <ordered_type_config>(location& loc, const context<ordered_type_config>&);14343extern template void skip_empty_or_comment_lines<ordered_type_config>(location& loc, const context<ordered_type_config>&);14344extern template void skip_string_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);14345extern template void skip_array_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);14346extern template void skip_inline_table_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);14347extern template void skip_value <ordered_type_config>(location& loc, const context<ordered_type_config>&);14348extern template void skip_key_value_pair <ordered_type_config>(location& loc, const context<ordered_type_config>&);14349extern template void skip_until_next_table <ordered_type_config>(location& loc, const context<ordered_type_config>&);1435014351} // detail14352} // TOML11_INLINE_VERSION_NAMESPACE14353} // toml14354#endif // TOML11_COMPILE_SOURCES1435514356#endif // TOML11_SKIP_HPP14357#ifndef TOML11_PARSER_HPP14358#define TOML11_PARSER_HPP143591436014361#include <fstream>14362#include <sstream>1436314364#include <cassert>14365#include <cmath>1436614367#if defined(TOML11_HAS_FILESYSTEM) && TOML11_HAS_FILESYSTEM14368#include <filesystem>14369#endif1437014371namespace toml14372{14373inline namespace TOML11_INLINE_VERSION_NAMESPACE14374{1437514376struct syntax_error final : public ::toml::exception14377{14378public:14379syntax_error(std::string what_arg, std::vector<error_info> err)14380: what_(std::move(what_arg)), err_(std::move(err))14381{}14382~syntax_error() noexcept override = default;1438314384const char* what() const noexcept override {return what_.c_str();}1438514386std::vector<error_info> const& errors() const noexcept14387{14388return err_;14389}1439014391private:14392std::string what_;14393std::vector<error_info> err_;14394};1439514396struct file_io_error final : public ::toml::exception14397{14398public:1439914400file_io_error(const std::string& msg, const std::string& fname)14401: errno_(cxx::make_nullopt()),14402what_(msg + " \"" + fname + "\"")14403{}14404file_io_error(int errnum, const std::string& msg, const std::string& fname)14405: errno_(errnum),14406what_(msg + " \"" + fname + "\": errno=" + std::to_string(errnum))14407{}14408~file_io_error() noexcept override = default;1440914410const char* what() const noexcept override {return what_.c_str();}1441114412bool has_errno() const noexcept {return errno_.has_value();}14413int get_errno() const noexcept {return errno_.value_or(0);}1441414415private:1441614417cxx::optional<int> errno_;14418std::string what_;14419};1442014421namespace detail14422{1442314424/* ============================================================================14425* __ ___ _ __ _ __ ___ _ _14426* / _/ _ \ ' \| ' \/ _ \ ' \14427* \__\___/_|_|_|_|_|_\___/_||_|14428*/1442914430template<typename S>14431error_info make_syntax_error(std::string title,14432const S& scanner, location loc, std::string suffix = "")14433{14434auto msg = std::string("expected ") + scanner.expected_chars(loc);14435auto src = source_location(region(loc));14436return make_error_info(14437std::move(title), std::move(src), std::move(msg), std::move(suffix));14438}144391444014441/* ============================================================================14442* _14443* __ ___ _ __ _ __ ___ _ _| |_14444* / _/ _ \ ' \| ' \/ -_) ' \ _|14445* \__\___/_|_|_|_|_|_\___|_||_\__|14446*/1444714448template<typename TC>14449result<cxx::optional<std::string>, error_info>14450parse_comment_line(location& loc, context<TC>& ctx)14451{14452const auto& spec = ctx.toml_spec();14453const auto first = loc;1445414455skip_whitespace(loc, ctx);1445614457const auto com_reg = syntax::comment(spec).scan(loc);14458if(com_reg.is_ok())14459{14460// once comment started, newline must follow (or reach EOF).14461if( ! loc.eof() && ! syntax::newline(spec).scan(loc).is_ok())14462{14463while( ! loc.eof()) // skip until newline to continue parsing14464{14465loc.advance();14466if(loc.current() == '\n') { /*skip LF*/ loc.advance(); break; }14467}14468return err(make_error_info("toml::parse_comment_line: "14469"newline (LF / CRLF) or EOF is expected",14470source_location(region(loc)), "but got this",14471"Hint: most of the control characters are not allowed in comments"));14472}14473return ok(cxx::optional<std::string>(com_reg.as_string()));14474}14475else14476{14477loc = first; // rollback whitespace to parse indent14478return ok(cxx::optional<std::string>(cxx::make_nullopt()));14479}14480}1448114482/* ============================================================================14483* ___ _14484* | _ ) ___ ___| |___ __ _ _ _14485* | _ \/ _ \/ _ \ / -_) _` | ' \14486* |___/\___/\___/_\___\__,_|_||_|14487*/1448814489template<typename TC>14490result<basic_value<TC>, error_info>14491parse_boolean(location& loc, const context<TC>& ctx)14492{14493const auto& spec = ctx.toml_spec();1449414495// ----------------------------------------------------------------------14496// check syntax14497auto reg = syntax::boolean(spec).scan(loc);14498if( ! reg.is_ok())14499{14500return err(make_syntax_error("toml::parse_boolean: "14501"invalid boolean: boolean must be `true` or `false`, in lowercase. "14502"string must be surrounded by `\"`", syntax::boolean(spec), loc));14503}1450414505// ----------------------------------------------------------------------14506// it matches. gen value14507const auto str = reg.as_string();14508const auto val = [&str]() {14509if(str == "true")14510{14511return true;14512}14513else14514{14515assert(str == "false");14516return false;14517}14518}();1451914520// ----------------------------------------------------------------------14521// no format info for boolean14522boolean_format_info fmt;1452314524return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));14525}1452614527/* ============================================================================14528* ___ _14529* |_ _|_ _| |_ ___ __ _ ___ _ _14530* | || ' \ _/ -_) _` / -_) '_|14531* |___|_||_\__\___\__, \___|_|14532* |___/14533*/1453414535template<typename TC>14536result<basic_value<TC>, error_info>14537parse_bin_integer(location& loc, const context<TC>& ctx)14538{14539const auto first = loc;14540const auto& spec = ctx.toml_spec();14541auto reg = syntax::bin_int(spec).scan(loc);14542if( ! reg.is_ok())14543{14544return err(make_syntax_error("toml::parse_bin_integer: "14545"invalid integer: bin_int must be like: 0b0101, 0b1111_0000",14546syntax::bin_int(spec), loc));14547}1454814549auto str = reg.as_string();1455014551integer_format_info fmt;14552fmt.fmt = integer_format::bin;14553fmt.width = str.size() - 2 - static_cast<std::size_t>(std::count(str.begin(), str.end(), '_'));1455414555const auto first_underscore = std::find(str.rbegin(), str.rend(), '_');14556if(first_underscore != str.rend())14557{14558fmt.spacer = static_cast<std::size_t>(std::distance(str.rbegin(), first_underscore));14559}1456014561// skip prefix `0b` and zeros and underscores at the MSB14562str.erase(str.begin(), std::find(std::next(str.begin(), 2), str.end(), '1'));1456314564// remove all `_` before calling TC::parse_int14565str.erase(std::remove(str.begin(), str.end(), '_'), str.end());1456614567// 0b0000_0000 becomes empty.14568if(str.empty()) { str = "0"; }1456914570const auto val = TC::parse_int(str, source_location(region(loc)), 2);14571if(val.is_ok())14572{14573return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));14574}14575else14576{14577loc = first;14578return err(val.as_err());14579}14580}1458114582// ----------------------------------------------------------------------------1458314584template<typename TC>14585result<basic_value<TC>, error_info>14586parse_oct_integer(location& loc, const context<TC>& ctx)14587{14588const auto first = loc;14589const auto& spec = ctx.toml_spec();14590auto reg = syntax::oct_int(spec).scan(loc);14591if( ! reg.is_ok())14592{14593return err(make_syntax_error("toml::parse_oct_integer: "14594"invalid integer: oct_int must be like: 0o775, 0o04_44",14595syntax::oct_int(spec), loc));14596}1459714598auto str = reg.as_string();1459914600integer_format_info fmt;14601fmt.fmt = integer_format::oct;14602fmt.width = str.size() - 2 - static_cast<std::size_t>(std::count(str.begin(), str.end(), '_'));1460314604const auto first_underscore = std::find(str.rbegin(), str.rend(), '_');14605if(first_underscore != str.rend())14606{14607fmt.spacer = static_cast<std::size_t>(std::distance(str.rbegin(), first_underscore));14608}1460914610// skip prefix `0o` and zeros and underscores at the MSB14611str.erase(str.begin(), std::find_if(14612std::next(str.begin(), 2), str.end(), [](const char c) {14613return c != '0' && c != '_';14614}));1461514616// remove all `_` before calling TC::parse_int14617str.erase(std::remove(str.begin(), str.end(), '_'), str.end());1461814619// 0o0000_0000 becomes empty.14620if(str.empty()) { str = "0"; }1462114622const auto val = TC::parse_int(str, source_location(region(loc)), 8);14623if(val.is_ok())14624{14625return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));14626}14627else14628{14629loc = first;14630return err(val.as_err());14631}14632}1463314634template<typename TC>14635result<basic_value<TC>, error_info>14636parse_hex_integer(location& loc, const context<TC>& ctx)14637{14638const auto first = loc;14639const auto& spec = ctx.toml_spec();14640auto reg = syntax::hex_int(spec).scan(loc);14641if( ! reg.is_ok())14642{14643return err(make_syntax_error("toml::parse_hex_integer: "14644"invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef",14645syntax::hex_int(spec), loc));14646}1464714648auto str = reg.as_string();1464914650integer_format_info fmt;14651fmt.fmt = integer_format::hex;14652fmt.width = str.size() - 2 - static_cast<std::size_t>(std::count(str.begin(), str.end(), '_'));1465314654const auto first_underscore = std::find(str.rbegin(), str.rend(), '_');14655if(first_underscore != str.rend())14656{14657fmt.spacer = static_cast<std::size_t>(std::distance(str.rbegin(), first_underscore));14658}1465914660// skip prefix `0x` and zeros and underscores at the MSB14661str.erase(str.begin(), std::find_if(14662std::next(str.begin(), 2), str.end(), [](const char c) {14663return c != '0' && c != '_';14664}));1466514666// remove all `_` before calling TC::parse_int14667str.erase(std::remove(str.begin(), str.end(), '_'), str.end());1466814669// 0x0000_0000 becomes empty.14670if(str.empty()) { str = "0"; }1467114672// prefix zero and _ is removed. check if it uses upper/lower case.14673// if both upper and lower case letters are found, set upper=true.14674const auto lower_not_found = std::find_if(str.begin(), str.end(),14675[](const char c) { return std::islower(static_cast<int>(c)) != 0; }) == str.end();14676const auto upper_found = std::find_if(str.begin(), str.end(),14677[](const char c) { return std::isupper(static_cast<int>(c)) != 0; }) != str.end();14678fmt.uppercase = lower_not_found || upper_found;1467914680const auto val = TC::parse_int(str, source_location(region(loc)), 16);14681if(val.is_ok())14682{14683return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));14684}14685else14686{14687loc = first;14688return err(val.as_err());14689}14690}1469114692template<typename TC>14693result<basic_value<TC>, error_info>14694parse_dec_integer(location& loc, const context<TC>& ctx)14695{14696const auto first = loc;14697const auto& spec = ctx.toml_spec();1469814699// ----------------------------------------------------------------------14700// check syntax14701auto reg = syntax::dec_int(spec).scan(loc);14702if( ! reg.is_ok())14703{14704return err(make_syntax_error("toml::parse_dec_integer: "14705"invalid integer: dec_int must be like: 42, 123_456_789",14706syntax::dec_int(spec), loc));14707}1470814709// ----------------------------------------------------------------------14710// it matches. gen value14711auto str = reg.as_string();1471214713integer_format_info fmt;14714fmt.fmt = integer_format::dec;14715fmt.width = str.size() - static_cast<std::size_t>(std::count(str.begin(), str.end(), '_'));1471614717const auto first_underscore = std::find(str.rbegin(), str.rend(), '_');14718if(first_underscore != str.rend())14719{14720fmt.spacer = static_cast<std::size_t>(std::distance(str.rbegin(), first_underscore));14721}1472214723// remove all `_` before calling TC::parse_int14724str.erase(std::remove(str.begin(), str.end(), '_'), str.end());1472514726auto src = source_location(region(loc));14727const auto val = TC::parse_int(str, src, 10);14728if(val.is_err())14729{14730loc = first;14731return err(val.as_err());14732}1473314734// ----------------------------------------------------------------------14735// parse suffix (extension)1473614737if(spec.ext_num_suffix && loc.current() == '_')14738{14739const auto sfx_reg = syntax::num_suffix(spec).scan(loc);14740if( ! sfx_reg.is_ok())14741{14742loc = first;14743return err(make_error_info("toml::parse_dec_integer: "14744"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",14745source_location(region(loc)), "here"));14746}14747auto sfx = sfx_reg.as_string();14748assert( ! sfx.empty() && sfx.front() == '_');14749sfx.erase(sfx.begin()); // remove the first `_`1475014751fmt.suffix = sfx;14752}1475314754return ok(basic_value<TC>(val.as_ok(), std::move(fmt), {}, std::move(reg)));14755}1475614757template<typename TC>14758result<basic_value<TC>, error_info>14759parse_integer(location& loc, const context<TC>& ctx)14760{14761const auto first = loc;1476214763if( ! loc.eof() && (loc.current() == '+' || loc.current() == '-'))14764{14765// skip +/- to diagnose +0xDEADBEEF or -0b0011 (invalid).14766// without this, +0xDEAD_BEEF will be parsed as a decimal int and14767// unexpected "xDEAD_BEEF" will appear after integer "+0".14768loc.advance();14769}1477014771if( ! loc.eof() && loc.current() == '0')14772{14773loc.advance();14774if(loc.eof())14775{14776// `[+-]?0`. parse as an decimal integer.14777loc = first;14778return parse_dec_integer(loc, ctx);14779}1478014781const auto prefix = loc.current();14782auto prefix_src = source_location(region(loc));1478314784loc = first;1478514786if(prefix == 'b') {return parse_bin_integer(loc, ctx);}14787if(prefix == 'o') {return parse_oct_integer(loc, ctx);}14788if(prefix == 'x') {return parse_hex_integer(loc, ctx);}1478914790if(std::isdigit(prefix))14791{14792auto src = source_location(region(loc));14793return err(make_error_info("toml::parse_integer: "14794"leading zero in an decimal integer is not allowed",14795std::move(src), "leading zero"));14796}14797}1479814799loc = first;14800return parse_dec_integer(loc, ctx);14801}1480214803/* ============================================================================14804* ___ _ _ _14805* | __| |___ __ _| |_(_)_ _ __ _14806* | _|| / _ \/ _` | _| | ' \/ _` |14807* |_| |_\___/\__,_|\__|_|_||_\__, |14808* |___/14809*/1481014811template<typename TC>14812result<basic_value<TC>, error_info>14813parse_floating(location& loc, const context<TC>& ctx)14814{14815using floating_type = typename basic_value<TC>::floating_type;1481614817const auto first = loc;14818const auto& spec = ctx.toml_spec();1481914820// ----------------------------------------------------------------------14821// check syntax14822bool is_hex = false;14823std::string str;14824region reg;14825if(spec.ext_hex_float && literal("0x").scan(loc).is_ok())14826{14827loc = first;14828is_hex = true;1482914830reg = syntax::hex_floating(spec).scan(loc);14831if( ! reg.is_ok())14832{14833return err(make_syntax_error("toml::parse_floating: "14834"invalid hex floating: float must be like: 0xABCp-3f",14835syntax::floating(spec), loc));14836}14837str = reg.as_string();14838}14839else14840{14841reg = syntax::floating(spec).scan(loc);14842if( ! reg.is_ok())14843{14844return err(make_syntax_error("toml::parse_floating: "14845"invalid floating: float must be like: -3.14159_26535, 6.022e+23, "14846"inf, or nan (lowercase).", syntax::floating(spec), loc));14847}14848str = reg.as_string();14849}1485014851// ----------------------------------------------------------------------14852// it matches. gen value1485314854floating_format_info fmt;1485514856if(is_hex)14857{14858fmt.fmt = floating_format::hex;14859}14860else14861{14862// since we already checked that the string conforms the TOML standard.14863if(std::find(str.begin(), str.end(), 'e') != str.end() ||14864std::find(str.begin(), str.end(), 'E') != str.end())14865{14866fmt.fmt = floating_format::scientific; // use exponent part14867}14868else14869{14870fmt.fmt = floating_format::fixed; // do not use exponent part14871}14872}1487314874str.erase(std::remove(str.begin(), str.end(), '_'), str.end());1487514876floating_type val{0};1487714878if(str == "inf" || str == "+inf")14879{14880TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_infinity)14881{14882val = std::numeric_limits<floating_type>::infinity();14883}14884else14885{14886return err(make_error_info("toml::parse_floating: inf value found"14887" but the current environment does not support inf. Please"14888" make sure that the floating-point implementation conforms"14889" IEEE 754/ISO 60559 international standard.",14890source_location(region(loc)),14891"floating_type: inf is not supported"));14892}14893}14894else if(str == "-inf")14895{14896TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_infinity)14897{14898val = -std::numeric_limits<floating_type>::infinity();14899}14900else14901{14902return err(make_error_info("toml::parse_floating: inf value found"14903" but the current environment does not support inf. Please"14904" make sure that the floating-point implementation conforms"14905" IEEE 754/ISO 60559 international standard.",14906source_location(region(loc)),14907"floating_type: inf is not supported"));14908}14909}14910else if(str == "nan" || str == "+nan")14911{14912TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_quiet_NaN)14913{14914val = std::numeric_limits<floating_type>::quiet_NaN();14915}14916else TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_signaling_NaN)14917{14918val = std::numeric_limits<floating_type>::signaling_NaN();14919}14920else14921{14922return err(make_error_info("toml::parse_floating: NaN value found"14923" but the current environment does not support NaN. Please"14924" make sure that the floating-point implementation conforms"14925" IEEE 754/ISO 60559 international standard.",14926source_location(region(loc)),14927"floating_type: NaN is not supported"));14928}14929}14930else if(str == "-nan")14931{14932using std::copysign;14933TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_quiet_NaN)14934{14935val = copysign(std::numeric_limits<floating_type>::quiet_NaN(), floating_type(-1));14936}14937else TOML11_CONSTEXPR_IF(std::numeric_limits<floating_type>::has_signaling_NaN)14938{14939val = copysign(std::numeric_limits<floating_type>::signaling_NaN(), floating_type(-1));14940}14941else14942{14943return err(make_error_info("toml::parse_floating: NaN value found"14944" but the current environment does not support NaN. Please"14945" make sure that the floating-point implementation conforms"14946" IEEE 754/ISO 60559 international standard.",14947source_location(region(loc)),14948"floating_type: NaN is not supported"));14949}14950}14951else14952{14953// set precision14954const auto has_sign = ! str.empty() && (str.front() == '+' || str.front() == '-');14955const auto decpoint = std::find(str.begin(), str.end(), '.');14956const auto exponent = std::find_if(str.begin(), str.end(),14957[](const char c) { return c == 'e' || c == 'E'; });14958if(decpoint != str.end() && exponent != str.end())14959{14960assert(decpoint < exponent);14961}1496214963if(fmt.fmt == floating_format::scientific)14964{14965// total width14966fmt.prec = static_cast<std::size_t>(std::distance(str.begin(), exponent));14967if(has_sign)14968{14969fmt.prec -= 1;14970}14971if(decpoint != str.end())14972{14973fmt.prec -= 1;14974}14975}14976else if(fmt.fmt == floating_format::hex)14977{14978fmt.prec = std::numeric_limits<floating_type>::max_digits10;14979}14980else14981{14982// width after decimal point14983fmt.prec = static_cast<std::size_t>(std::distance(std::next(decpoint), exponent));14984}1498514986auto src = source_location(region(loc));14987const auto res = TC::parse_float(str, src, is_hex);14988if(res.is_ok())14989{14990val = res.as_ok();14991}14992else14993{14994return err(res.as_err());14995}14996}1499714998// ----------------------------------------------------------------------14999// parse suffix (extension)1500015001if(spec.ext_num_suffix && loc.current() == '_')15002{15003const auto sfx_reg = syntax::num_suffix(spec).scan(loc);15004if( ! sfx_reg.is_ok())15005{15006auto src = source_location(region(loc));15007loc = first;15008return err(make_error_info("toml::parse_floating: "15009"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",15010std::move(src), "here"));15011}15012auto sfx = sfx_reg.as_string();15013assert( ! sfx.empty() && sfx.front() == '_');15014sfx.erase(sfx.begin()); // remove the first `_`1501515016fmt.suffix = sfx;15017}1501815019return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));15020}1502115022/* ============================================================================15023* ___ _ _ _15024* | \ __ _| |_ ___| |_(_)_ __ ___15025* | |) / _` | _/ -_) _| | ' \/ -_)15026* |___/\__,_|\__\___|\__|_|_|_|_\___|15027*/1502815029// all the offset_datetime, local_datetime, local_date parses date part.15030template<typename TC>15031result<std::tuple<local_date, local_date_format_info, region>, error_info>15032parse_local_date_only(location& loc, const context<TC>& ctx)15033{15034const auto first = loc;15035const auto& spec = ctx.toml_spec();1503615037local_date_format_info fmt;1503815039// ----------------------------------------------------------------------15040// check syntax15041auto reg = syntax::local_date(spec).scan(loc);15042if( ! reg.is_ok())15043{15044return err(make_syntax_error("toml::parse_local_date: "15045"invalid date: date must be like: 1234-05-06, yyyy-mm-dd.",15046syntax::local_date(spec), loc));15047}1504815049// ----------------------------------------------------------------------15050// it matches. gen value15051const auto str = reg.as_string();1505215053// 012345678915054// yyyy-mm-dd15055const auto year_r = from_string<int>(str.substr(0, 4));15056const auto month_r = from_string<int>(str.substr(5, 2));15057const auto day_r = from_string<int>(str.substr(8, 2));1505815059if(year_r.is_err())15060{15061auto src = source_location(region(first));15062return err(make_error_info("toml::parse_local_date: "15063"failed to read year `" + str.substr(0, 4) + "`",15064std::move(src), "here"));15065}15066if(month_r.is_err())15067{15068auto src = source_location(region(first));15069return err(make_error_info("toml::parse_local_date: "15070"failed to read month `" + str.substr(5, 2) + "`",15071std::move(src), "here"));15072}15073if(day_r.is_err())15074{15075auto src = source_location(region(first));15076return err(make_error_info("toml::parse_local_date: "15077"failed to read day `" + str.substr(8, 2) + "`",15078std::move(src), "here"));15079}1508015081const auto year = year_r.unwrap();15082const auto month = month_r.unwrap();15083const auto day = day_r.unwrap();1508415085{15086// We briefly check whether the input date is valid or not.15087// Actually, because of the historical reasons, there are several15088// edge cases, such as 1582/10/5-1582/10/14 (only in several countries).15089// But here, we do not care about it.15090// It makes the code complicated and there is only low probability15091// that such a specific date is needed in practice. If someone need to15092// validate date accurately, that means that the one need a specialized15093// library for their purpose in another layer.1509415095const bool is_leap = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));15096const auto max_day = [month, is_leap]() {15097if(month == 2)15098{15099return is_leap ? 29 : 28;15100}15101if(month == 4 || month == 6 || month == 9 || month == 11)15102{15103return 30;15104}15105return 31;15106}();1510715108if((month < 1 || 12 < month) || (day < 1 || max_day < day))15109{15110auto src = source_location(region(first));15111return err(make_error_info("toml::parse_local_date: invalid date.",15112std::move(src), "month must be 01-12, day must be any of "15113"01-28,29,30,31 depending on the month/year."));15114}15115}1511615117return ok(std::make_tuple(15118local_date(year, static_cast<month_t>(month - 1), day),15119std::move(fmt), std::move(reg)15120));15121}1512215123template<typename TC>15124result<basic_value<TC>, error_info>15125parse_local_date(location& loc, const context<TC>& ctx)15126{15127auto val_fmt_reg = parse_local_date_only(loc, ctx);15128if(val_fmt_reg.is_err())15129{15130return err(val_fmt_reg.unwrap_err());15131}1513215133auto val = std::move(std::get<0>(val_fmt_reg.unwrap()));15134auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap()));15135auto reg = std::move(std::get<2>(val_fmt_reg.unwrap()));1513615137return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));15138}1513915140// all the offset_datetime, local_datetime, local_time parses date part.15141template<typename TC>15142result<std::tuple<local_time, local_time_format_info, region>, error_info>15143parse_local_time_only(location& loc, const context<TC>& ctx)15144{15145const auto first = loc;15146const auto& spec = ctx.toml_spec();1514715148local_time_format_info fmt;1514915150// ----------------------------------------------------------------------15151// check syntax15152auto reg = syntax::local_time(spec).scan(loc);15153if( ! reg.is_ok())15154{15155if(spec.v1_1_0_make_seconds_optional)15156{15157return err(make_syntax_error("toml::parse_local_time: "15158"invalid time: time must be HH:MM(:SS.sss) (seconds are optional)",15159syntax::local_time(spec), loc));15160}15161else15162{15163return err(make_syntax_error("toml::parse_local_time: "15164"invalid time: time must be HH:MM:SS(.sss) (subseconds are optional)",15165syntax::local_time(spec), loc));15166}15167}1516815169// ----------------------------------------------------------------------15170// it matches. gen value15171const auto str = reg.as_string();1517215173// at least we have HH:MM.15174// 0123415175// HH:MM15176const auto hour_r = from_string<int>(str.substr(0, 2));15177const auto minute_r = from_string<int>(str.substr(3, 2));1517815179if(hour_r.is_err())15180{15181auto src = source_location(region(first));15182return err(make_error_info("toml::parse_local_time: "15183"failed to read hour `" + str.substr(0, 2) + "`",15184std::move(src), "here"));15185}15186if(minute_r.is_err())15187{15188auto src = source_location(region(first));15189return err(make_error_info("toml::parse_local_time: "15190"failed to read minute `" + str.substr(3, 2) + "`",15191std::move(src), "here"));15192}1519315194const auto hour = hour_r.unwrap();15195const auto minute = minute_r.unwrap();1519615197if((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute))15198{15199auto src = source_location(region(first));15200return err(make_error_info("toml::parse_local_time: invalid time.",15201std::move(src), "hour must be 00-23, minute must be 00-59."));15202}1520315204// -----------------------------------------------------------------------15205// we have hour and minute.15206// Since toml v1.1.0, second and subsecond part becomes optional.15207// Check the version and return if second does not exist.1520815209if(str.size() == 5 && spec.v1_1_0_make_seconds_optional)15210{15211fmt.has_seconds = false;15212fmt.subsecond_precision = 0;15213return ok(std::make_tuple(local_time(hour, minute, 0), std::move(fmt), std::move(reg)));15214}15215assert(str.at(5) == ':');1521615217// we have at least `:SS` part. `.subseconds` are optional.1521815219// 0 115220// 01234567890123415221// HH:MM:SS.subsec15222const auto sec_r = from_string<int>(str.substr(6, 2));15223if(sec_r.is_err())15224{15225auto src = source_location(region(first));15226return err(make_error_info("toml::parse_local_time: "15227"failed to read second `" + str.substr(6, 2) + "`",15228std::move(src), "here"));15229}15230const auto sec = sec_r.unwrap();1523115232if(sec < 0 || 60 < sec) // :60 is allowed15233{15234auto src = source_location(region(first));15235return err(make_error_info("toml::parse_local_time: invalid time.",15236std::move(src), "second must be 00-60."));15237}1523815239if(str.size() == 8)15240{15241fmt.has_seconds = true;15242fmt.subsecond_precision = 0;15243return ok(std::make_tuple(local_time(hour, minute, sec), std::move(fmt), std::move(reg)));15244}1524515246assert(str.at(8) == '.');1524715248auto secfrac = str.substr(9, str.size() - 9);1524915250fmt.has_seconds = true;15251fmt.subsecond_precision = secfrac.size();1525215253while(secfrac.size() < 9)15254{15255secfrac += '0';15256}15257assert(9 <= secfrac.size());15258const auto ms_r = from_string<int>(secfrac.substr(0, 3));15259const auto us_r = from_string<int>(secfrac.substr(3, 3));15260const auto ns_r = from_string<int>(secfrac.substr(6, 3));1526115262if(ms_r.is_err())15263{15264auto src = source_location(region(first));15265return err(make_error_info("toml::parse_local_time: "15266"failed to read milliseconds `" + secfrac.substr(0, 3) + "`",15267std::move(src), "here"));15268}15269if(us_r.is_err())15270{15271auto src = source_location(region(first));15272return err(make_error_info("toml::parse_local_time: "15273"failed to read microseconds`" + str.substr(3, 3) + "`",15274std::move(src), "here"));15275}15276if(ns_r.is_err())15277{15278auto src = source_location(region(first));15279return err(make_error_info("toml::parse_local_time: "15280"failed to read nanoseconds`" + str.substr(6, 3) + "`",15281std::move(src), "here"));15282}15283const auto ms = ms_r.unwrap();15284const auto us = us_r.unwrap();15285const auto ns = ns_r.unwrap();1528615287return ok(std::make_tuple(local_time(hour, minute, sec, ms, us, ns), std::move(fmt), std::move(reg)));15288}1528915290template<typename TC>15291result<basic_value<TC>, error_info>15292parse_local_time(location& loc, const context<TC>& ctx)15293{15294const auto first = loc;1529515296auto val_fmt_reg = parse_local_time_only(loc, ctx);15297if(val_fmt_reg.is_err())15298{15299return err(val_fmt_reg.unwrap_err());15300}1530115302auto val = std::move(std::get<0>(val_fmt_reg.unwrap()));15303auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap()));15304auto reg = std::move(std::get<2>(val_fmt_reg.unwrap()));1530515306return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));15307}1530815309template<typename TC>15310result<basic_value<TC>, error_info>15311parse_local_datetime(location& loc, const context<TC>& ctx)15312{15313using char_type = location::char_type;1531415315const auto first = loc;1531615317local_datetime_format_info fmt;1531815319// ----------------------------------------------------------------------1532015321auto date_fmt_reg = parse_local_date_only(loc, ctx);15322if(date_fmt_reg.is_err())15323{15324return err(date_fmt_reg.unwrap_err());15325}1532615327if(loc.current() == char_type('T'))15328{15329loc.advance();15330fmt.delimiter = datetime_delimiter_kind::upper_T;15331}15332else if(loc.current() == char_type('t'))15333{15334loc.advance();15335fmt.delimiter = datetime_delimiter_kind::lower_t;15336}15337else if(loc.current() == char_type(' '))15338{15339loc.advance();15340fmt.delimiter = datetime_delimiter_kind::space;15341}15342else15343{15344auto src = source_location(region(loc));15345return err(make_error_info("toml::parse_local_datetime: "15346"expect date-time delimiter `T`, `t` or ` `(space).",15347std::move(src), "here"));15348}1534915350auto time_fmt_reg = parse_local_time_only(loc, ctx);15351if(time_fmt_reg.is_err())15352{15353return err(time_fmt_reg.unwrap_err());15354}1535515356fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds;15357fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision;1535815359// ----------------------------------------------------------------------1536015361region reg(first, loc);15362local_datetime val(std::get<0>(date_fmt_reg.unwrap()),15363std::get<0>(time_fmt_reg.unwrap()));1536415365return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));15366}1536715368template<typename TC>15369result<basic_value<TC>, error_info>15370parse_offset_datetime(location& loc, const context<TC>& ctx)15371{15372using char_type = location::char_type;1537315374const auto first = loc;15375const auto& spec = ctx.toml_spec();1537615377offset_datetime_format_info fmt;1537815379// ----------------------------------------------------------------------15380// date part1538115382auto date_fmt_reg = parse_local_date_only(loc, ctx);15383if(date_fmt_reg.is_err())15384{15385return err(date_fmt_reg.unwrap_err());15386}1538715388// ----------------------------------------------------------------------15389// delimiter1539015391if(loc.current() == char_type('T'))15392{15393loc.advance();15394fmt.delimiter = datetime_delimiter_kind::upper_T;15395}15396else if(loc.current() == char_type('t'))15397{15398loc.advance();15399fmt.delimiter = datetime_delimiter_kind::lower_t;15400}15401else if(loc.current() == char_type(' '))15402{15403loc.advance();15404fmt.delimiter = datetime_delimiter_kind::space;15405}15406else15407{15408auto src = source_location(region(loc));15409return err(make_error_info("toml::parse_offset_datetime: "15410"expect date-time delimiter `T` or ` `(space).", std::move(src), "here"15411));15412}1541315414// ----------------------------------------------------------------------15415// time part1541615417auto time_fmt_reg = parse_local_time_only(loc, ctx);15418if(time_fmt_reg.is_err())15419{15420return err(time_fmt_reg.unwrap_err());15421}1542215423fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds;15424fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision;1542515426// ----------------------------------------------------------------------15427// offset part1542815429const auto ofs_reg = syntax::time_offset(spec).scan(loc);15430if( ! ofs_reg.is_ok())15431{15432return err(make_syntax_error("toml::parse_offset_datetime: "15433"invalid offset: offset must be like: Z, +01:00, or -10:00.",15434syntax::time_offset(spec), loc));15435}1543615437const auto ofs_str = ofs_reg.as_string();1543815439time_offset offset(0, 0);1544015441assert(ofs_str.size() != 0);1544215443if(ofs_str.at(0) == char_type('+') || ofs_str.at(0) == char_type('-'))15444{15445const auto hour_r = from_string<int>(ofs_str.substr(1, 2));15446const auto minute_r = from_string<int>(ofs_str.substr(4, 2));15447if(hour_r.is_err())15448{15449auto src = source_location(region(loc));15450return err(make_error_info("toml::parse_offset_datetime: "15451"Failed to read offset hour part", std::move(src), "here"));15452}15453if(minute_r.is_err())15454{15455auto src = source_location(region(loc));15456return err(make_error_info("toml::parse_offset_datetime: "15457"Failed to read offset minute part", std::move(src), "here"));15458}15459const auto hour = hour_r.unwrap();15460const auto minute = minute_r.unwrap();1546115462if(ofs_str.at(0) == '+')15463{15464offset = time_offset(hour, minute);15465}15466else15467{15468offset = time_offset(-hour, -minute);15469}15470}15471else15472{15473assert(ofs_str.at(0) == char_type('Z') || ofs_str.at(0) == char_type('z'));15474}1547515476if (offset.hour < -24 || 24 < offset.hour ||15477offset.minute < -60 || 60 < offset.minute)15478{15479return err(make_error_info("toml::parse_offset_datetime: "15480"too large offset: |hour| <= 24, |minute| <= 60",15481source_location(region(first, loc)), "here"));15482}154831548415485// ----------------------------------------------------------------------1548615487region reg(first, loc);15488offset_datetime val(local_datetime(std::get<0>(date_fmt_reg.unwrap()),15489std::get<0>(time_fmt_reg.unwrap())),15490offset);1549115492return ok(basic_value<TC>(val, std::move(fmt), {}, std::move(reg)));15493}1549415495/* ============================================================================15496* ___ _ _15497* / __| |_ _ _(_)_ _ __ _15498* \__ \ _| '_| | ' \/ _` |15499* |___/\__|_| |_|_||_\__, |15500* |___/15501*/1550215503template<typename TC>15504result<typename basic_value<TC>::string_type, error_info>15505parse_utf8_codepoint(const region& reg)15506{15507using string_type = typename basic_value<TC>::string_type;15508using char_type = typename string_type::value_type;1550915510// assert(reg.as_lines().size() == 1); // XXX heavy check1551115512const auto str = reg.as_string();15513assert( ! str.empty());15514assert(str.front() == 'u' || str.front() == 'U' || str.front() == 'x');1551515516std::uint_least32_t codepoint;15517std::istringstream iss(str.substr(1));15518iss >> std::hex >> codepoint;1551915520const auto to_char = [](const std::uint_least32_t i) noexcept -> char_type {15521const auto uc = static_cast<unsigned char>(i & 0xFF);15522return cxx::bit_cast<char_type>(uc);15523};1552415525string_type character;15526if(codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII.15527{15528character += static_cast<char>(codepoint);15529}15530else if(codepoint < 0x800) //U+0080 ... U+07FF15531{15532// 110yyyyx 10xxxxxx; 0x3f == 0b0011'111115533character += to_char(0xC0|(codepoint >> 6 ));15534character += to_char(0x80|(codepoint & 0x3F));15535}15536else if(codepoint < 0x10000) // U+0800...U+FFFF15537{15538if(0xD800 <= codepoint && codepoint <= 0xDFFF)15539{15540auto src = source_location(reg);15541return err(make_error_info("toml::parse_utf8_codepoint: "15542"[0xD800, 0xDFFF] is not a valid UTF-8",15543std::move(src), "here"));15544}15545assert(codepoint < 0xD800 || 0xDFFF < codepoint);15546// 1110yyyy 10yxxxxx 10xxxxxx15547character += to_char(0xE0| (codepoint >> 12));15548character += to_char(0x80|((codepoint >> 6 ) & 0x3F));15549character += to_char(0x80|((codepoint ) & 0x3F));15550}15551else if(codepoint < 0x110000) // U+010000 ... U+10FFFF15552{15553// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx15554character += to_char(0xF0| (codepoint >> 18));15555character += to_char(0x80|((codepoint >> 12) & 0x3F));15556character += to_char(0x80|((codepoint >> 6 ) & 0x3F));15557character += to_char(0x80|((codepoint ) & 0x3F));15558}15559else // out of UTF-8 region15560{15561auto src = source_location(reg);15562return err(make_error_info("toml::parse_utf8_codepoint: "15563"input codepoint is too large.",15564std::move(src), "must be in range [0x00, 0x10FFFF]"));15565}15566return ok(character);15567}1556815569template<typename TC>15570result<typename basic_value<TC>::string_type, error_info>15571parse_escape_sequence(location& loc, const context<TC>& ctx)15572{15573using string_type = typename basic_value<TC>::string_type;15574using char_type = typename string_type::value_type;1557515576const auto& spec = ctx.toml_spec();1557715578assert( ! loc.eof());15579assert(loc.current() == '\\');15580loc.advance(); // consume the first backslash1558115582string_type retval;1558315584if (loc.current() == '\\') { retval += char_type('\\'); loc.advance(); }15585else if(loc.current() == '"') { retval += char_type('\"'); loc.advance(); }15586else if(loc.current() == 'b') { retval += char_type('\b'); loc.advance(); }15587else if(loc.current() == 'f') { retval += char_type('\f'); loc.advance(); }15588else if(loc.current() == 'n') { retval += char_type('\n'); loc.advance(); }15589else if(loc.current() == 'r') { retval += char_type('\r'); loc.advance(); }15590else if(loc.current() == 't') { retval += char_type('\t'); loc.advance(); }15591else if(spec.v1_1_0_add_escape_sequence_e && loc.current() == 'e')15592{15593retval += char_type('\x1b');15594loc.advance();15595}15596else if(spec.v1_1_0_add_escape_sequence_x && loc.current() == 'x')15597{15598const auto reg = syntax::escaped_x2(spec).scan(loc);15599if( ! reg.is_ok())15600{15601auto src = source_location(region(loc));15602return err(make_error_info("toml::parse_escape_sequence: "15603"invalid token found in UTF-8 codepoint \\xhh",15604std::move(src), "here"));15605}15606const auto utf8 = parse_utf8_codepoint<TC>(reg);15607if(utf8.is_err())15608{15609return err(utf8.as_err());15610}15611retval += utf8.unwrap();15612}15613else if(loc.current() == 'u')15614{15615const auto reg = syntax::escaped_u4(spec).scan(loc);15616if( ! reg.is_ok())15617{15618auto src = source_location(region(loc));15619return err(make_error_info("toml::parse_escape_sequence: "15620"invalid token found in UTF-8 codepoint \\uhhhh",15621std::move(src), "here"));15622}15623const auto utf8 = parse_utf8_codepoint<TC>(reg);15624if(utf8.is_err())15625{15626return err(utf8.as_err());15627}15628retval += utf8.unwrap();15629}15630else if(loc.current() == 'U')15631{15632const auto reg = syntax::escaped_U8(spec).scan(loc);15633if( ! reg.is_ok())15634{15635auto src = source_location(region(loc));15636return err(make_error_info("toml::parse_escape_sequence: "15637"invalid token found in UTF-8 codepoint \\Uhhhhhhhh",15638std::move(src), "here"));15639}15640const auto utf8 = parse_utf8_codepoint<TC>(reg);15641if(utf8.is_err())15642{15643return err(utf8.as_err());15644}15645retval += utf8.unwrap();15646}15647else15648{15649auto src = source_location(region(loc));15650std::string escape_seqs = "allowed escape seqs: \\\\, \\\", \\b, \\f, \\n, \\r, \\t";15651if(spec.v1_1_0_add_escape_sequence_e)15652{15653escape_seqs += ", \\e";15654}15655if(spec.v1_1_0_add_escape_sequence_x)15656{15657escape_seqs += ", \\xhh";15658}15659escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh";1566015661return err(make_error_info("toml::parse_escape_sequence: "15662"unknown escape sequence.", std::move(src), escape_seqs));15663}15664return ok(retval);15665}1566615667template<typename TC>15668result<basic_value<TC>, error_info>15669parse_ml_basic_string(location& loc, const context<TC>& ctx)15670{15671const auto first = loc;15672const auto& spec = ctx.toml_spec();1567315674string_format_info fmt;15675fmt.fmt = string_format::multiline_basic;1567615677auto reg = syntax::ml_basic_string(spec).scan(loc);15678if( ! reg.is_ok())15679{15680return err(make_syntax_error("toml::parse_ml_basic_string: "15681"invalid string format",15682syntax::ml_basic_string(spec), loc));15683}1568415685// ----------------------------------------------------------------------15686// it matches. gen value1568715688auto str = reg.as_string();1568915690// we already checked that it starts with """ and ends with """.15691assert(str.substr(0, 3) == "\"\"\"");15692str.erase(0, 3);1569315694assert(str.size() >= 3);15695assert(str.substr(str.size()-3, 3) == "\"\"\"");15696str.erase(str.size()-3, 3);1569715698// the first newline just after """ is trimmed15699if(str.size() >= 1 && str.at(0) == '\n')15700{15701str.erase(0, 1);15702fmt.start_with_newline = true;15703}15704else if(str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n')15705{15706str.erase(0, 2);15707fmt.start_with_newline = true;15708}1570915710using string_type = typename basic_value<TC>::string_type;15711string_type val;15712{15713auto iter = str.cbegin();15714while(iter != str.cend())15715{15716if(*iter == '\\') // remove whitespaces around escaped-newline15717{15718// we assume that the string is not too long to copy15719auto loc2 = make_temporary_location(make_string(iter, str.cend()));15720if(syntax::escaped_newline(spec).scan(loc2).is_ok())15721{15722std::advance(iter, loc2.get_location()); // skip escaped newline and indent15723// now iter points non-WS char15724assert(iter == str.end() || (*iter != ' ' && *iter != '\t'));15725}15726else // normal escape seq.15727{15728auto esc = parse_escape_sequence(loc2, ctx);1572915730// syntax does not check its value. the unicode codepoint may be15731// invalid, e.g. out-of-bound, [0xD800, 0xDFFF]15732if(esc.is_err())15733{15734return err(esc.unwrap_err());15735}1573615737val += esc.unwrap();15738std::advance(iter, loc2.get_location());15739}15740}15741else // we already checked the syntax. we don't need to check it again.15742{15743val += static_cast<typename string_type::value_type>(*iter);15744++iter;15745}15746}15747}1574815749return ok(basic_value<TC>(15750std::move(val), std::move(fmt), {}, std::move(reg)15751));15752}1575315754template<typename TC>15755result<std::pair<typename basic_value<TC>::string_type, region>, error_info>15756parse_basic_string_only(location& loc, const context<TC>& ctx)15757{15758const auto first = loc;15759const auto& spec = ctx.toml_spec();1576015761auto reg = syntax::basic_string(spec).scan(loc);15762if( ! reg.is_ok())15763{15764return err(make_syntax_error("toml::parse_basic_string: "15765"invalid string format",15766syntax::basic_string(spec), loc));15767}1576815769// ----------------------------------------------------------------------15770// it matches. gen value1577115772auto str = reg.as_string();1577315774assert(str.back() == '\"');15775str.pop_back();15776assert(str.at(0) == '\"');15777str.erase(0, 1);1577815779using string_type = typename basic_value<TC>::string_type;15780using char_type = typename string_type::value_type;15781string_type val;1578215783{15784auto iter = str.begin();15785while(iter != str.end())15786{15787if(*iter == '\\')15788{15789auto loc2 = make_temporary_location(make_string(iter, str.end()));1579015791auto esc = parse_escape_sequence(loc2, ctx);1579215793// syntax does not check its value. the unicode codepoint may be15794// invalid, e.g. out-of-bound, [0xD800, 0xDFFF]15795if(esc.is_err())15796{15797return err(esc.unwrap_err());15798}1579915800val += esc.unwrap();15801std::advance(iter, loc2.get_location());15802}15803else15804{15805val += char_type(*iter); // we already checked the syntax.15806++iter;15807}15808}15809}15810return ok(std::make_pair(val, reg));15811}1581215813template<typename TC>15814result<basic_value<TC>, error_info>15815parse_basic_string(location& loc, const context<TC>& ctx)15816{15817const auto first = loc;1581815819string_format_info fmt;15820fmt.fmt = string_format::basic;1582115822auto val_res = parse_basic_string_only(loc, ctx);15823if(val_res.is_err())15824{15825return err(std::move(val_res.unwrap_err()));15826}15827auto val = std::move(val_res.unwrap().first );15828auto reg = std::move(val_res.unwrap().second);1582915830return ok(basic_value<TC>(std::move(val), std::move(fmt), {}, std::move(reg)));15831}1583215833template<typename TC>15834result<basic_value<TC>, error_info>15835parse_ml_literal_string(location& loc, const context<TC>& ctx)15836{15837const auto first = loc;15838const auto& spec = ctx.toml_spec();1583915840string_format_info fmt;15841fmt.fmt = string_format::multiline_literal;1584215843auto reg = syntax::ml_literal_string(spec).scan(loc);15844if( ! reg.is_ok())15845{15846return err(make_syntax_error("toml::parse_ml_literal_string: "15847"invalid string format",15848syntax::ml_literal_string(spec), loc));15849}1585015851// ----------------------------------------------------------------------15852// it matches. gen value1585315854auto str = reg.as_string();1585515856assert(str.substr(0, 3) == "'''");15857assert(str.substr(str.size()-3, 3) == "'''");15858str.erase(0, 3);15859str.erase(str.size()-3, 3);1586015861// the first newline just after """ is trimmed15862if(str.size() >= 1 && str.at(0) == '\n')15863{15864str.erase(0, 1);15865fmt.start_with_newline = true;15866}15867else if(str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n')15868{15869str.erase(0, 2);15870fmt.start_with_newline = true;15871}1587215873using string_type = typename basic_value<TC>::string_type;15874string_type val(str.begin(), str.end());1587515876return ok(basic_value<TC>(15877std::move(val), std::move(fmt), {}, std::move(reg)15878));15879}1588015881template<typename TC>15882result<std::pair<typename basic_value<TC>::string_type, region>, error_info>15883parse_literal_string_only(location& loc, const context<TC>& ctx)15884{15885const auto first = loc;15886const auto& spec = ctx.toml_spec();1588715888auto reg = syntax::literal_string(spec).scan(loc);15889if( ! reg.is_ok())15890{15891return err(make_syntax_error("toml::parse_literal_string: "15892"invalid string format",15893syntax::literal_string(spec), loc));15894}1589515896// ----------------------------------------------------------------------15897// it matches. gen value1589815899auto str = reg.as_string();1590015901assert(str.back() == '\'');15902str.pop_back();15903assert(str.at(0) == '\'');15904str.erase(0, 1);1590515906using string_type = typename basic_value<TC>::string_type;15907string_type val(str.begin(), str.end());1590815909return ok(std::make_pair(std::move(val), std::move(reg)));15910}1591115912template<typename TC>15913result<basic_value<TC>, error_info>15914parse_literal_string(location& loc, const context<TC>& ctx)15915{15916const auto first = loc;1591715918string_format_info fmt;15919fmt.fmt = string_format::literal;1592015921auto val_res = parse_literal_string_only(loc, ctx);15922if(val_res.is_err())15923{15924return err(std::move(val_res.unwrap_err()));15925}15926auto val = std::move(val_res.unwrap().first );15927auto reg = std::move(val_res.unwrap().second);1592815929return ok(basic_value<TC>(15930std::move(val), std::move(fmt), {}, std::move(reg)15931));15932}1593315934template<typename TC>15935result<basic_value<TC>, error_info>15936parse_string(location& loc, const context<TC>& ctx)15937{15938const auto first = loc;1593915940if( ! loc.eof() && loc.current() == '"')15941{15942if(literal("\"\"\"").scan(loc).is_ok())15943{15944loc = first;15945return parse_ml_basic_string(loc, ctx);15946}15947else15948{15949loc = first;15950return parse_basic_string(loc, ctx);15951}15952}15953else if( ! loc.eof() && loc.current() == '\'')15954{15955if(literal("'''").scan(loc).is_ok())15956{15957loc = first;15958return parse_ml_literal_string(loc, ctx);15959}15960else15961{15962loc = first;15963return parse_literal_string(loc, ctx);15964}15965}15966else15967{15968auto src = source_location(region(loc));15969return err(make_error_info("toml::parse_string: "15970"not a string", std::move(src), "here"));15971}15972}1597315974template<typename TC>15975result<basic_value<TC>, error_info>15976parse_null(location& loc, const context<TC>& ctx)15977{15978const auto& spec = ctx.toml_spec();15979if( ! spec.ext_null_value)15980{15981return err(make_error_info("toml::parse_null: "15982"invalid spec: spec.ext_null_value must be true.",15983source_location(region(loc)), "here"));15984}1598515986// ----------------------------------------------------------------------15987// check syntax15988auto reg = syntax::null_value(spec).scan(loc);15989if( ! reg.is_ok())15990{15991return err(make_syntax_error("toml::parse_null: "15992"invalid null: null must be lowercase. ",15993syntax::null_value(spec), loc));15994}1599515996// ----------------------------------------------------------------------15997// it matches. gen value1599815999// ----------------------------------------------------------------------16000// no format info for boolean1600116002return ok(basic_value<TC>(detail::none_t{}, std::move(reg)));16003}1600416005/* ============================================================================16006* _ __16007* | |/ /___ _ _16008* | ' </ -_) || |16009* |_|\_\___|\_, |16010* |__/16011*/1601216013// non-dotted key.16014template<typename TC>16015result<typename basic_value<TC>::key_type, error_info>16016parse_simple_key(location& loc, const context<TC>& ctx)16017{16018using key_type = typename basic_value<TC>::key_type;16019const auto& spec = ctx.toml_spec();1602016021if(loc.current() == '\"')16022{16023auto str_res = parse_basic_string_only(loc, ctx);16024if(str_res.is_ok())16025{16026return ok(std::move(str_res.unwrap().first));16027}16028else16029{16030return err(std::move(str_res.unwrap_err()));16031}16032}16033else if(loc.current() == '\'')16034{16035auto str_res = parse_literal_string_only(loc, ctx);16036if(str_res.is_ok())16037{16038return ok(std::move(str_res.unwrap().first));16039}16040else16041{16042return err(std::move(str_res.unwrap_err()));16043}16044}1604516046// bare key.1604716048if(const auto bare = syntax::unquoted_key(spec).scan(loc))16049{16050return ok(string_conv<key_type>(bare.as_string()));16051}16052else16053{16054std::string postfix;16055if(spec.ext_allow_non_english_in_bare_keys)16056{16057postfix = "Hint: Not all Unicode characters are allowed as bare key.\n";16058}16059else16060{16061postfix = "Hint: non-ASCII scripts are allowed in toml v1.1.0, but not in v1.0.0.\n";16062}16063return err(make_syntax_error("toml::parse_simple_key: "16064"invalid key: key must be \"quoted\", 'quoted-literal', or bare key.",16065syntax::unquoted_key(spec), loc, postfix));16066}16067}1606816069// dotted key become vector of keys16070template<typename TC>16071result<std::pair<std::vector<typename basic_value<TC>::key_type>, region>, error_info>16072parse_key(location& loc, const context<TC>& ctx)16073{16074const auto first = loc;16075const auto& spec = ctx.toml_spec();1607616077using key_type = typename basic_value<TC>::key_type;16078std::vector<key_type> keys;16079while( ! loc.eof())16080{16081auto key = parse_simple_key(loc, ctx);16082if( ! key.is_ok())16083{16084return err(key.unwrap_err());16085}16086keys.push_back(std::move(key.unwrap()));1608716088auto reg = syntax::dot_sep(spec).scan(loc);16089if( ! reg.is_ok())16090{16091break;16092}16093}16094if(keys.empty())16095{16096auto src = source_location(region(first));16097return err(make_error_info("toml::parse_key: expected a new key, "16098"but got nothing", std::move(src), "reached EOF"));16099}1610016101return ok(std::make_pair(std::move(keys), region(first, loc)));16102}1610316104// ============================================================================1610516106// forward-decl to implement parse_array and parse_table16107template<typename TC>16108result<basic_value<TC>, error_info>16109parse_value(location&, context<TC>& ctx);1611016111template<typename TC>16112result<std::pair<16113std::pair<std::vector<typename basic_value<TC>::key_type>, region>,16114basic_value<TC>16115>, error_info>16116parse_key_value_pair(location& loc, context<TC>& ctx)16117{16118const auto first = loc;16119const auto& spec = ctx.toml_spec();1612016121auto key_res = parse_key(loc, ctx);16122if(key_res.is_err())16123{16124loc = first;16125return err(key_res.unwrap_err());16126}1612716128if( ! syntax::keyval_sep(spec).scan(loc).is_ok())16129{16130auto e = make_syntax_error("toml::parse_key_value_pair: "16131"invalid key value separator `=`", syntax::keyval_sep(spec), loc);16132loc = first;16133return err(std::move(e));16134}1613516136auto v_res = parse_value(loc, ctx);16137if(v_res.is_err())16138{16139// loc = first;16140return err(v_res.unwrap_err());16141}16142return ok(std::make_pair(std::move(key_res.unwrap()), std::move(v_res.unwrap())));16143}1614416145/* ============================================================================16146* __ _ _ _ _ _ __ _ _ _16147* / _` | '_| '_/ _` | || |16148* \__,_|_| |_| \__,_|\_, |16149* |__/16150*/1615116152// array(and multiline inline table with `{` and `}`) has the following format.16153// `[`16154// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,`16155// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,`16156// ...16157// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? (`,`)?16158// (ws|newline|comment-line)? `]`16159// it skips (ws|newline|comment-line) and returns the token.16160template<typename TC>16161struct multiline_spacer16162{16163using comment_type = typename TC::comment_type;16164bool newline_found;16165indent_char indent_type;16166std::int32_t indent;16167comment_type comments;16168};16169template<typename T>16170std::ostream& operator<<(std::ostream& os, const multiline_spacer<T>& sp)16171{16172os << "{newline=" << sp.newline_found << ", ";16173os << "indent_type=" << sp.indent_type << ", ";16174os << "indent=" << sp.indent << ", ";16175os << "comments=" << sp.comments.size() << "}";16176return os;16177}1617816179template<typename TC>16180cxx::optional<multiline_spacer<TC>>16181skip_multiline_spacer(location& loc, context<TC>& ctx, const bool newline_found = false)16182{16183const auto& spec = ctx.toml_spec();1618416185multiline_spacer<TC> spacer;16186spacer.newline_found = newline_found;16187spacer.indent_type = indent_char::none;16188spacer.indent = 0;16189spacer.comments.clear();1619016191bool spacer_found = false;16192while( ! loc.eof())16193{16194if(auto comm = sequence(syntax::comment(spec), syntax::newline(spec)).scan(loc))16195{16196spacer.newline_found = true;16197auto comment = comm.as_string();16198if( ! comment.empty() && comment.back() == '\n')16199{16200comment.pop_back();16201if (!comment.empty() && comment.back() == '\r')16202{16203comment.pop_back();16204}16205}1620616207spacer.comments.push_back(std::move(comment));16208spacer.indent_type = indent_char::none;16209spacer.indent = 0;16210spacer_found = true;16211}16212else if(auto nl = syntax::newline(spec).scan(loc))16213{16214spacer.newline_found = true;16215spacer.comments.clear();16216spacer.indent_type = indent_char::none;16217spacer.indent = 0;16218spacer_found = true;16219}16220else if(auto sp = repeat_at_least(1, character(cxx::bit_cast<location::char_type>(' '))).scan(loc))16221{16222spacer.indent_type = indent_char::space;16223spacer.indent = static_cast<std::int32_t>(sp.length());16224spacer_found = true;16225}16226else if(auto tabs = repeat_at_least(1, character(cxx::bit_cast<location::char_type>('\t'))).scan(loc))16227{16228spacer.indent_type = indent_char::tab;16229spacer.indent = static_cast<std::int32_t>(tabs.length());16230spacer_found = true;16231}16232else16233{16234break; // done16235}16236}16237if( ! spacer_found)16238{16239return cxx::make_nullopt();16240}16241return spacer;16242}1624316244// not an [[array.of.tables]]. It parses ["this", "type"]16245template<typename TC>16246result<basic_value<TC>, error_info>16247parse_array(location& loc, context<TC>& ctx)16248{16249const auto num_errors = ctx.errors().size();1625016251const auto first = loc;1625216253if(loc.eof() || loc.current() != '[')16254{16255auto src = source_location(region(loc));16256return err(make_error_info("toml::parse_array: "16257"The next token is not an array", std::move(src), "here"));16258}16259loc.advance();1626016261typename basic_value<TC>::array_type val;1626216263array_format_info fmt;16264fmt.fmt = array_format::oneline;16265fmt.indent_type = indent_char::none;1626616267auto spacer = skip_multiline_spacer(loc, ctx);16268if(spacer.has_value() && spacer.value().newline_found)16269{16270fmt.fmt = array_format::multiline;16271}1627216273bool comma_found = true;16274while( ! loc.eof())16275{16276if(loc.current() == location::char_type(']'))16277{16278if(spacer.has_value() && spacer.value().newline_found &&16279spacer.value().indent_type != indent_char::none)16280{16281fmt.indent_type = spacer.value().indent_type;16282fmt.closing_indent = spacer.value().indent;16283}16284break;16285}1628616287if( ! comma_found)16288{16289auto src = source_location(region(loc));16290return err(make_error_info("toml::parse_array: "16291"expected value-separator `,` or closing `]`",16292std::move(src), "here"));16293}1629416295if(spacer.has_value() && spacer.value().newline_found &&16296spacer.value().indent_type != indent_char::none)16297{16298fmt.indent_type = spacer.value().indent_type;16299fmt.body_indent = spacer.value().indent;16300}1630116302if(auto elem_res = parse_value(loc, ctx))16303{16304auto elem = std::move(elem_res.unwrap());1630516306if(spacer.has_value()) // copy previous comments to value16307{16308elem.comments() = std::move(spacer.value().comments);16309}1631016311// parse spaces between a value and a comma16312// array = [16313// 42 , # the answer16314// ^^^^16315// 3.14 # pi16316// , 2.71 ^^^^16317// ^^16318spacer = skip_multiline_spacer(loc, ctx);16319if(spacer.has_value())16320{16321for(std::size_t i=0; i<spacer.value().comments.size(); ++i)16322{16323elem.comments().push_back(std::move(spacer.value().comments.at(i)));16324}16325if(spacer.value().newline_found)16326{16327fmt.fmt = array_format::multiline;16328}16329}1633016331comma_found = character(',').scan(loc).is_ok();1633216333// parse comment after a comma16334// array = [16335// 42 , # the answer16336// ^^^^^^^^^^^^16337// 3.14 # pi16338// ^^^^16339// ]16340auto com_res = parse_comment_line(loc, ctx);16341if(com_res.is_err())16342{16343ctx.report_error(com_res.unwrap_err());16344}1634516346const bool comment_found = com_res.is_ok() && com_res.unwrap().has_value();16347if(comment_found)16348{16349fmt.fmt = array_format::multiline;16350elem.comments().push_back(com_res.unwrap().value());16351}16352if(comma_found)16353{16354spacer = skip_multiline_spacer(loc, ctx, comment_found);16355if(spacer.has_value() && spacer.value().newline_found)16356{16357fmt.fmt = array_format::multiline;16358}16359}16360val.push_back(std::move(elem));16361}16362else16363{16364// if err, push error to ctx and try recovery.16365ctx.report_error(std::move(elem_res.unwrap_err()));1636616367// if it looks like some value, then skip the value.16368// otherwise, it may be a new key-value pair or a new table and16369// the error is "missing closing ]". stop parsing.1637016371const auto before_skip = loc.get_location();16372skip_value(loc, ctx);16373if(before_skip == loc.get_location()) // cannot skip! break...16374{16375break;16376}16377}16378}1637916380if(loc.current() != ']')16381{16382auto src = source_location(region(loc));16383return err(make_error_info("toml::parse_array: missing closing bracket `]`",16384std::move(src), "expected `]`, reached EOF"));16385}16386else16387{16388loc.advance();16389}16390// any error reported from this function16391if(num_errors != ctx.errors().size())16392{16393assert(ctx.has_error()); // already reported16394return err(ctx.errors().back());16395}1639616397return ok(basic_value<TC>(16398std::move(val), std::move(fmt), {}, region(first, loc)16399));16400}1640116402/* ============================================================================16403* _ _ _ _ _ _16404* (_)_ _ | (_)_ _ ___ | |_ __ _| |__| |___16405* | | ' \| | | ' \/ -_) | _/ _` | '_ \ / -_)16406* |_|_||_|_|_|_||_\___| \__\__,_|_.__/_\___|16407*/1640816409// ----------------------------------------------------------------------------16410// insert_value is the most complicated part of the toml spec.16411//16412// To parse a toml file correctly, we sometimes need to check an exising value16413// is appendable or not.16414//16415// For example while parsing an inline array of tables,16416//16417// ```toml16418// aot = [16419// {a = "foo"},16420// {a = "bar", b = "baz"},16421// ]16422// ```16423//16424// this `aot` is appendable until parser reaches to `]`. After that, it becomes16425// non-appendable.16426//16427// On the other hand, a normal array of tables, such as16428//16429// ```toml16430// [[aot]]16431// a = "foo"16432//16433// [[aot]]16434// a = "bar"16435// b = "baz"16436// ```16437// This `[[aot]]` is appendable until the parser reaches to the EOF.16438//16439//16440// It becomes a bit more difficult in case of dotted keys.16441// In TOML, it is allowed to append a key-value pair to a table that is16442// *implicitly* defined by a subtable definitino.16443//16444// ```toml16445// [x.y.z]16446// w = 12316447//16448// [x]16449// a = "foo" # OK. x is defined implicitly by `[x.y.z]`.16450// ```16451//16452// But if the table is defined by a dotted keys, it is not appendable.16453//16454// ```toml16455// [x]16456// y.z.w = 12316457//16458// [x.y]16459// # ERROR. x.y is already defined by a dotted table in the previous table.16460// ```16461//16462// Also, reopening a table using dotted keys is invalid.16463//16464// ```toml16465// [x.y.z]16466// w = 12316467//16468// [x]16469// y.z.v = 42 # ERROR. [x.y.z] is already defined.16470// ```16471//16472//16473// ```toml16474// [a]16475// b.c = "foo"16476// b.d = "bar"16477// ```16478//16479//16480// ```toml16481// a.b = "foo"16482// [a]16483// c = "bar" # ERROR16484// ```16485//16486// In summary,16487// - a table must be defined only once.16488// - assignment to an exising table is possible only when:16489// - defining a subtable [x.y] to an existing table [x].16490// - defining supertable [x] explicitly after [x.y].16491// - adding dotted keys in the same table.1649216493enum class inserting_value_kind : std::uint8_t16494{16495std_table, // insert [standard.table]16496array_table, // insert [[array.of.tables]]16497dotted_keys // insert a.b.c = "this"16498};1649916500template<typename TC>16501result<basic_value<TC>*, error_info>16502insert_value(const inserting_value_kind kind,16503typename basic_value<TC>::table_type* current_table_ptr,16504const std::vector<typename basic_value<TC>::key_type>& keys, region key_reg,16505basic_value<TC> val)16506{16507using value_type = basic_value<TC>;16508using array_type = typename basic_value<TC>::array_type;16509using table_type = typename basic_value<TC>::table_type;1651016511auto key_loc = source_location(key_reg);1651216513assert( ! keys.empty());1651416515// dotted key can insert to dotted key tables defined at the same level.16516// dotted key can NOT reopen a table even if it is implcitly-defined one.16517//16518// [x.y.z] # define x and x.y implicitly.16519// a = 4216520//16521// [x] # reopening implcitly defined table16522// r.s.t = 3.14 # VALID r and r.s are new tables.16523// r.s.u = 2.71 # VALID r and r.s are dotted-key tables. valid.16524//16525// y.z.b = "foo" # INVALID x.y.z are multiline table, not a dotted key.16526// y.c = "bar" # INVALID x.y is implicit multiline table, not a dotted key.1652716528// a table cannot reopen dotted-key tables.16529//16530// [t1]16531// t2.t3.v = 016532// [t1.t2] # INVALID t1.t2 is defined as a dotted-key table.1653316534for(std::size_t i=0; i<keys.size(); ++i)16535{16536const auto& key = keys.at(i);16537table_type& current_table = *current_table_ptr;1653816539if(i+1 < keys.size()) // there are more keys. go down recursively...16540{16541const auto found = current_table.find(key);16542if(found == current_table.end()) // not found. add new table16543{16544table_format_info fmt;16545fmt.indent_type = indent_char::none;16546if(kind == inserting_value_kind::dotted_keys)16547{16548fmt.fmt = table_format::dotted;16549}16550else // table / array of tables16551{16552fmt.fmt = table_format::implicit;16553}16554current_table.emplace(key, value_type(16555table_type{}, fmt, std::vector<std::string>{}, key_reg));1655616557assert(current_table.at(key).is_table());16558current_table_ptr = std::addressof(current_table.at(key).as_table());16559}16560else if (found->second.is_table())16561{16562const auto fmt = found->second.as_table_fmt().fmt;16563if(fmt == table_format::oneline || fmt == table_format::multiline_oneline)16564{16565// foo = {bar = "baz"} or foo = { \n bar = "baz" \n }16566return err(make_error_info("toml::insert_value: "16567"failed to insert a value: inline table is immutable",16568key_loc, "inserting this",16569found->second.location(), "to this table"));16570}16571// dotted key cannot reopen a table.16572if(kind ==inserting_value_kind::dotted_keys && fmt != table_format::dotted)16573{16574return err(make_error_info("toml::insert_value: "16575"reopening a table using dotted keys",16576key_loc, "dotted key cannot reopen a table",16577found->second.location(), "this table is already closed"));16578}16579assert(found->second.is_table());16580current_table_ptr = std::addressof(found->second.as_table());16581}16582else if(found->second.is_array_of_tables())16583{16584// aot = [{this = "type", of = "aot"}] # cannot be reopened16585if(found->second.as_array_fmt().fmt != array_format::array_of_tables)16586{16587return err(make_error_info("toml::insert_value:"16588"inline array of tables are immutable",16589key_loc, "inserting this",16590found->second.location(), "inline array of tables"));16591}16592// appending to [[aot]]1659316594if(kind == inserting_value_kind::dotted_keys)16595{16596// [[array.of.tables]]16597// [array.of] # reopening supertable is okay16598// tables.x = "foo" # appending `x` to the first table16599return err(make_error_info("toml::insert_value:"16600"dotted key cannot reopen an array-of-tables",16601key_loc, "inserting this",16602found->second.location(), "to this array-of-tables."));16603}1660416605// insert_value_by_dotkeys::std_table16606// [[array.of.tables]]16607// [array.of.tables.subtable] # appending to the last aot16608//16609// insert_value_by_dotkeys::array_table16610// [[array.of.tables]]16611// [[array.of.tables.subtable]] # appending to the last aot16612auto& current_array_table = found->second.as_array().back();1661316614assert(current_array_table.is_table());16615current_table_ptr = std::addressof(current_array_table.as_table());16616}16617else16618{16619return err(make_error_info("toml::insert_value: "16620"failed to insert a value, value already exists",16621key_loc, "while inserting this",16622found->second.location(), "non-table value already exists"));16623}16624}16625else // this is the last key. insert a new value.16626{16627switch(kind)16628{16629case inserting_value_kind::dotted_keys:16630{16631if(current_table.find(key) != current_table.end())16632{16633return err(make_error_info("toml::insert_value: "16634"failed to insert a value, value already exists",16635key_loc, "inserting this",16636current_table.at(key).location(), "but value already exists"));16637}16638current_table.emplace(key, std::move(val));16639return ok(std::addressof(current_table.at(key)));16640}16641case inserting_value_kind::std_table:16642{16643// defining a new table or reopening supertable16644auto found = current_table.find(key);16645if(found == current_table.end()) // define a new aot16646{16647current_table.emplace(key, std::move(val));16648return ok(std::addressof(current_table.at(key)));16649}16650else // the table is already defined, reopen it16651{16652// assigning a [std.table]. it must be an implicit table.16653auto& target = found->second;16654if( ! target.is_table() || // could be an array-of-tables16655target.as_table_fmt().fmt != table_format::implicit)16656{16657return err(make_error_info("toml::insert_value: "16658"failed to insert a table, table already defined",16659key_loc, "inserting this",16660target.location(), "this table is explicitly defined"));16661}1666216663// merge table16664for(const auto& kv : val.as_table())16665{16666if(target.contains(kv.first))16667{16668// [x.y.z]16669// w = "foo"16670// [x]16671// y = "bar"16672return err(make_error_info("toml::insert_value: "16673"failed to insert a table, table keys conflict to each other",16674key_loc, "inserting this table",16675kv.second.location(), "having this value",16676target.at(kv.first).location(), "already defined here"));16677}16678else16679{16680target[kv.first] = kv.second;16681}16682}16683// change implicit -> explicit16684target.as_table_fmt().fmt = table_format::multiline;16685// change definition region16686change_region_of_value(target, val);1668716688return ok(std::addressof(current_table.at(key)));16689}16690}16691case inserting_value_kind::array_table:16692{16693auto found = current_table.find(key);16694if(found == current_table.end()) // define a new aot16695{16696array_format_info fmt;16697fmt.fmt = array_format::array_of_tables;16698fmt.indent_type = indent_char::none;1669916700current_table.emplace(key, value_type(16701array_type{ std::move(val) }, std::move(fmt),16702std::vector<std::string>{}, std::move(key_reg)16703));1670416705assert( ! current_table.at(key).as_array().empty());16706return ok(std::addressof(current_table.at(key).as_array().back()));16707}16708else // the array is already defined, append to it16709{16710if( ! found->second.is_array_of_tables())16711{16712return err(make_error_info("toml::insert_value: "16713"failed to insert an array of tables, value already exists",16714key_loc, "while inserting this",16715found->second.location(), "non-table value already exists"));16716}16717if(found->second.as_array_fmt().fmt != array_format::array_of_tables)16718{16719return err(make_error_info("toml::insert_value: "16720"failed to insert a table, inline array of tables is immutable",16721key_loc, "while inserting this",16722found->second.location(), "this is inline array-of-tables"));16723}16724found->second.as_array().push_back(std::move(val));16725assert( ! current_table.at(key).as_array().empty());16726return ok(std::addressof(current_table.at(key).as_array().back()));16727}16728}16729default: {assert(false);}16730}16731}16732}16733return err(make_error_info("toml::insert_key: no keys found",16734std::move(key_loc), "here"));16735}1673616737// ----------------------------------------------------------------------------1673816739template<typename TC>16740result<basic_value<TC>, error_info>16741parse_inline_table(location& loc, context<TC>& ctx)16742{16743using table_type = typename basic_value<TC>::table_type;1674416745const auto num_errors = ctx.errors().size();1674616747const auto first = loc;16748const auto& spec = ctx.toml_spec();1674916750if(loc.eof() || loc.current() != '{')16751{16752auto src = source_location(region(loc));16753return err(make_error_info("toml::parse_inline_table: "16754"The next token is not an inline table", std::move(src), "here"));16755}16756loc.advance();1675716758table_type table;16759table_format_info fmt;16760fmt.fmt = table_format::oneline;16761fmt.indent_type = indent_char::none;1676216763cxx::optional<multiline_spacer<TC>> spacer(cxx::make_nullopt());1676416765if(spec.v1_1_0_allow_newlines_in_inline_tables)16766{16767spacer = skip_multiline_spacer(loc, ctx);16768if(spacer.has_value() && spacer.value().newline_found)16769{16770fmt.fmt = table_format::multiline_oneline;16771}16772}16773else16774{16775skip_whitespace(loc, ctx);16776}1677716778bool still_empty = true;16779bool comma_found = false;16780while( ! loc.eof())16781{16782// closing!16783if(loc.current() == '}')16784{16785if(comma_found && ! spec.v1_1_0_allow_trailing_comma_in_inline_tables)16786{16787auto src = source_location(region(loc));16788return err(make_error_info("toml::parse_inline_table: trailing "16789"comma is not allowed in TOML-v1.0.0)", std::move(src), "here"));16790}1679116792if(spec.v1_1_0_allow_newlines_in_inline_tables)16793{16794if(spacer.has_value() && spacer.value().newline_found &&16795spacer.value().indent_type != indent_char::none)16796{16797fmt.indent_type = spacer.value().indent_type;16798fmt.closing_indent = spacer.value().indent;16799}16800}16801break;16802}1680316804// if we already found a value and didn't found `,` nor `}`, error.16805if( ! comma_found && ! still_empty)16806{16807auto src = source_location(region(loc));16808return err(make_error_info("toml::parse_inline_table: "16809"expected value-separator `,` or closing `}`",16810std::move(src), "here"));16811}1681216813// parse indent.16814if(spacer.has_value() && spacer.value().newline_found &&16815spacer.value().indent_type != indent_char::none)16816{16817fmt.indent_type = spacer.value().indent_type;16818fmt.body_indent = spacer.value().indent;16819}1682016821still_empty = false; // parsing a value...16822if(auto kv_res = parse_key_value_pair<TC>(loc, ctx))16823{16824auto keys = std::move(kv_res.unwrap().first.first);16825auto key_reg = std::move(kv_res.unwrap().first.second);16826auto val = std::move(kv_res.unwrap().second);1682716828auto ins_res = insert_value(inserting_value_kind::dotted_keys,16829std::addressof(table), keys, std::move(key_reg), std::move(val));16830if(ins_res.is_err())16831{16832ctx.report_error(std::move(ins_res.unwrap_err()));16833// we need to skip until the next value (or end of the table)16834// because we don't have valid kv pair.16835while( ! loc.eof())16836{16837const auto c = loc.current();16838if(c == ',' || c == '\n' || c == '}')16839{16840comma_found = (c == ',');16841break;16842}16843loc.advance();16844}16845continue;16846}1684716848// if comment line follows immediately(without newline) after `,`, then16849// the comment is for the elem. we need to check if comment follows `,`.16850//16851// (key) = (val) (ws|newline|comment-line)? `,` (ws)? (comment)?1685216853if(spec.v1_1_0_allow_newlines_in_inline_tables)16854{16855if(spacer.has_value()) // copy previous comments to value16856{16857for(std::size_t i=0; i<spacer.value().comments.size(); ++i)16858{16859ins_res.unwrap()->comments().push_back(spacer.value().comments.at(i));16860}16861}16862spacer = skip_multiline_spacer(loc, ctx);16863if(spacer.has_value())16864{16865for(std::size_t i=0; i<spacer.value().comments.size(); ++i)16866{16867ins_res.unwrap()->comments().push_back(spacer.value().comments.at(i));16868}16869if(spacer.value().newline_found)16870{16871fmt.fmt = table_format::multiline_oneline;16872if(spacer.value().indent_type != indent_char::none)16873{16874fmt.indent_type = spacer.value().indent_type;16875fmt.body_indent = spacer.value().indent;16876}16877}16878}16879}16880else16881{16882skip_whitespace(loc, ctx);16883}1688416885comma_found = character(',').scan(loc).is_ok();1688616887if(spec.v1_1_0_allow_newlines_in_inline_tables)16888{16889auto com_res = parse_comment_line(loc, ctx);16890if(com_res.is_err())16891{16892ctx.report_error(com_res.unwrap_err());16893}16894const bool comment_found = com_res.is_ok() && com_res.unwrap().has_value();16895if(comment_found)16896{16897fmt.fmt = table_format::multiline_oneline;16898ins_res.unwrap()->comments().push_back(com_res.unwrap().value());16899}16900if(comma_found)16901{16902spacer = skip_multiline_spacer(loc, ctx, comment_found);16903if(spacer.has_value() && spacer.value().newline_found)16904{16905fmt.fmt = table_format::multiline_oneline;16906}16907}16908}16909else16910{16911skip_whitespace(loc, ctx);16912}16913}16914else16915{16916ctx.report_error(std::move(kv_res.unwrap_err()));16917while( ! loc.eof())16918{16919if(loc.current() == '}')16920{16921break;16922}16923if( ! spec.v1_1_0_allow_newlines_in_inline_tables && loc.current() == '\n')16924{16925break;16926}16927loc.advance();16928}16929break;16930}16931}1693216933if(loc.current() != '}')16934{16935auto src = source_location(region(loc));16936return err(make_error_info("toml::parse_inline_table: "16937"missing closing bracket `}`",16938std::move(src), "expected `}`, reached line end"));16939}16940else16941{16942loc.advance(); // skip }16943}1694416945// any error reported from this function16946if(num_errors < ctx.errors().size())16947{16948assert(ctx.has_error()); // already reported16949return err(ctx.pop_last_error());16950}1695116952basic_value<TC> retval(16953std::move(table), std::move(fmt), {}, region(first, loc));1695416955return ok(std::move(retval));16956}1695716958/* ============================================================================16959* _16960* __ ____ _| |_ _ ___16961* \ V / _` | | || / -_)16962* \_/\__,_|_|\_,_\___|16963*/1696416965template<typename TC>16966result<value_t, error_info>16967guess_number_type(const location& first, const context<TC>& ctx)16968{16969const auto& spec = ctx.toml_spec();16970location loc = first;1697116972if(syntax::offset_datetime(spec).scan(loc).is_ok())16973{16974return ok(value_t::offset_datetime);16975}16976loc = first;1697716978if(syntax::local_datetime(spec).scan(loc).is_ok())16979{16980const auto curr = loc.current();16981// if offset_datetime contains bad offset, it syntax::offset_datetime16982// fails to scan it.16983if(curr == '+' || curr == '-')16984{16985return err(make_syntax_error("bad offset: must be [+-]HH:MM or Z",16986syntax::time_offset(spec), loc, std::string(16987"Hint: valid : +09:00, -05:30\n"16988"Hint: invalid: +9:00, -5:30\n")));16989}16990return ok(value_t::local_datetime);16991}16992loc = first;1699316994if(syntax::local_date(spec).scan(loc).is_ok())16995{16996// bad time may appear after this.1699716998if( ! loc.eof())16999{17000const auto c = loc.current();17001if(c == 'T' || c == 't')17002{17003loc.advance();1700417005return err(make_syntax_error("bad time: must be HH:MM:SS.subsec",17006syntax::local_time(spec), loc, std::string(17007"Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n"17008"Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n")));17009}17010if(c == ' ')17011{17012// A space is allowed as a delimiter between local time.17013// But there is a case where bad time follows a space.17014// - invalid: 2019-06-16 7:00:0017015// - valid : 2019-06-16 07:00:0017016loc.advance();17017if( ! loc.eof() && ('0' <= loc.current() && loc.current() <= '9'))17018{17019return err(make_syntax_error("bad time: must be HH:MM:SS.subsec",17020syntax::local_time(spec), loc, std::string(17021"Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n"17022"Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n")));17023}17024}17025if('0' <= c && c <= '9')17026{17027return err(make_syntax_error("bad datetime: missing T or space",17028character_either("Tt "), loc, std::string(17029"Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n"17030"Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n")));17031}17032}17033return ok(value_t::local_date);17034}17035loc = first;1703617037if(syntax::local_time(spec).scan(loc).is_ok())17038{17039return ok(value_t::local_time);17040}17041loc = first;1704217043if(syntax::floating(spec).scan(loc).is_ok())17044{17045if( ! loc.eof() && loc.current() == '_')17046{17047if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok())17048{17049return ok(value_t::floating);17050}17051auto src = source_location(region(loc));17052return err(make_error_info(17053"bad float: `_` must be surrounded by digits",17054std::move(src), "invalid underscore",17055"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"17056"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"));17057}17058return ok(value_t::floating);17059}17060loc = first;1706117062if(spec.ext_hex_float)17063{17064if(syntax::hex_floating(spec).scan(loc).is_ok())17065{17066if( ! loc.eof() && loc.current() == '_')17067{17068if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok())17069{17070return ok(value_t::floating);17071}17072auto src = source_location(region(loc));17073return err(make_error_info(17074"bad float: `_` must be surrounded by digits",17075std::move(src), "invalid underscore",17076"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"17077"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"));17078}17079return ok(value_t::floating);17080}17081loc = first;17082}1708317084if(auto int_reg = syntax::integer(spec).scan(loc))17085{17086if( ! loc.eof())17087{17088const auto c = loc.current();17089if(c == '_')17090{17091if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok())17092{17093return ok(value_t::integer);17094}1709517096if(int_reg.length() <= 2 && (int_reg.as_string() == "0" ||17097int_reg.as_string() == "-0" || int_reg.as_string() == "+0"))17098{17099auto src = source_location(region(loc));17100return err(make_error_info(17101"bad integer: leading zero is not allowed in decimal int",17102std::move(src), "leading zero",17103"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"17104"Hint: invalid: _42, 1__000, 0123\n"));17105}17106else17107{17108auto src = source_location(region(loc));17109return err(make_error_info(17110"bad integer: `_` must be surrounded by digits",17111std::move(src), "invalid underscore",17112"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"17113"Hint: invalid: _42, 1__000, 0123\n"));17114}17115}17116if('0' <= c && c <= '9')17117{17118if(loc.current() == '0')17119{17120loc.retrace();17121return err(make_error_info(17122"bad integer: leading zero",17123source_location(region(loc)), "leading zero is not allowed",17124std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"17125"Hint: invalid: _42, 1__000, 0123\n")17126));17127}17128else // invalid digits, especially in oct/bin ints.17129{17130return err(make_error_info(17131"bad integer: invalid digit after an integer",17132source_location(region(loc)), "this digit is not allowed",17133std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"17134"Hint: invalid: _42, 1__000, 0123\n")17135));17136}17137}17138if(c == ':' || c == '-')17139{17140auto src = source_location(region(loc));17141return err(make_error_info("bad datetime: invalid format",17142std::move(src), "here",17143std::string("Hint: valid : 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z\n"17144"Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30")17145));17146}17147if(c == '.' || c == 'e' || c == 'E')17148{17149auto src = source_location(region(loc));17150return err(make_error_info("bad float: invalid format",17151std::move(src), "here", std::string(17152"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"17153"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")));17154}17155}17156return ok(value_t::integer);17157}17158if( ! loc.eof() && loc.current() == '.')17159{17160auto src = source_location(region(loc));17161return err(make_error_info("bad float: integer part is required before decimal point",17162std::move(src), "missing integer part", std::string(17163"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"17164"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")17165));17166}17167if( ! loc.eof() && loc.current() == '_')17168{17169auto src = source_location(region(loc));17170return err(make_error_info("bad number: `_` must be surrounded by digits",17171std::move(src), "digits required before `_`", std::string(17172"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"17173"Hint: invalid: _42, 1__000, 0123\n")17174));17175}1717617177auto src = source_location(region(loc));17178return err(make_error_info("bad format: unknown value appeared",17179std::move(src), "here"));17180}1718117182template<typename TC>17183result<value_t, error_info>17184guess_value_type(const location& loc, const context<TC>& ctx)17185{17186const auto& sp = ctx.toml_spec();17187location inner(loc);1718817189switch(loc.current())17190{17191case '"' : {return ok(value_t::string); }17192case '\'': {return ok(value_t::string); }17193case '[' : {return ok(value_t::array); }17194case '{' : {return ok(value_t::table); }17195case 't' :17196{17197return ok(value_t::boolean);17198}17199case 'f' :17200{17201return ok(value_t::boolean);17202}17203case 'T' : // invalid boolean.17204{17205return err(make_syntax_error("toml::parse_value: "17206"`true` must be in lowercase. "17207"A string must be surrounded by quotes.",17208syntax::boolean(sp), inner));17209}17210case 'F' :17211{17212return err(make_syntax_error("toml::parse_value: "17213"`false` must be in lowercase. "17214"A string must be surrounded by quotes.",17215syntax::boolean(sp), inner));17216}17217case 'i' : // inf or string without quotes(syntax error).17218{17219if(literal("inf").scan(inner).is_ok())17220{17221return ok(value_t::floating);17222}17223else17224{17225return err(make_syntax_error("toml::parse_value: "17226"`inf` must be in lowercase. "17227"A string must be surrounded by quotes.",17228syntax::floating(sp), inner));17229}17230}17231case 'I' : // Inf or string without quotes(syntax error).17232{17233return err(make_syntax_error("toml::parse_value: "17234"`inf` must be in lowercase. "17235"A string must be surrounded by quotes.",17236syntax::floating(sp), inner));17237}17238case 'n' : // nan or null-extension17239{17240if(sp.ext_null_value)17241{17242if(literal("nan").scan(inner).is_ok())17243{17244return ok(value_t::floating);17245}17246else if(literal("null").scan(inner).is_ok())17247{17248return ok(value_t::empty);17249}17250else17251{17252return err(make_syntax_error("toml::parse_value: "17253"Both `nan` and `null` must be in lowercase. "17254"A string must be surrounded by quotes.",17255syntax::floating(sp), inner));17256}17257}17258else // must be nan.17259{17260if(literal("nan").scan(inner).is_ok())17261{17262return ok(value_t::floating);17263}17264else17265{17266return err(make_syntax_error("toml::parse_value: "17267"`nan` must be in lowercase. "17268"A string must be surrounded by quotes.",17269syntax::floating(sp), inner));17270}17271}17272}17273case 'N' : // nan or null-extension17274{17275if(sp.ext_null_value)17276{17277return err(make_syntax_error("toml::parse_value: "17278"Both `nan` and `null` must be in lowercase. "17279"A string must be surrounded by quotes.",17280syntax::floating(sp), inner));17281}17282else17283{17284return err(make_syntax_error("toml::parse_value: "17285"`nan` must be in lowercase. "17286"A string must be surrounded by quotes.",17287syntax::floating(sp), inner));17288}17289}17290default :17291{17292return guess_number_type(loc, ctx);17293}17294}17295}1729617297template<typename TC>17298result<basic_value<TC>, error_info>17299parse_value(location& loc, context<TC>& ctx)17300{17301const auto ty_res = guess_value_type(loc, ctx);17302if(ty_res.is_err())17303{17304return err(ty_res.unwrap_err());17305}1730617307switch(ty_res.unwrap())17308{17309case value_t::empty:17310{17311if(ctx.toml_spec().ext_null_value)17312{17313return parse_null(loc, ctx);17314}17315else17316{17317auto src = source_location(region(loc));17318return err(make_error_info("toml::parse_value: unknown value appeared",17319std::move(src), "here"));17320}17321}17322case value_t::boolean : {return parse_boolean (loc, ctx);}17323case value_t::integer : {return parse_integer (loc, ctx);}17324case value_t::floating : {return parse_floating (loc, ctx);}17325case value_t::string : {return parse_string (loc, ctx);}17326case value_t::offset_datetime: {return parse_offset_datetime(loc, ctx);}17327case value_t::local_datetime : {return parse_local_datetime (loc, ctx);}17328case value_t::local_date : {return parse_local_date (loc, ctx);}17329case value_t::local_time : {return parse_local_time (loc, ctx);}17330case value_t::array : {return parse_array (loc, ctx);}17331case value_t::table : {return parse_inline_table (loc, ctx);}17332default:17333{17334auto src = source_location(region(loc));17335return err(make_error_info("toml::parse_value: unknown value appeared",17336std::move(src), "here"));17337}17338}17339}1734017341/* ============================================================================17342* _____ _ _17343* |_ _|_ _| |__| |___17344* | |/ _` | '_ \ / -_)17345* |_|\__,_|_.__/_\___|17346*/1734717348template<typename TC>17349result<std::pair<std::vector<typename basic_value<TC>::key_type>, region>, error_info>17350parse_table_key(location& loc, context<TC>& ctx)17351{17352const auto first = loc;17353const auto& spec = ctx.toml_spec();1735417355auto reg = syntax::std_table(spec).scan(loc);17356if(!reg.is_ok())17357{17358return err(make_syntax_error("toml::parse_table_key: invalid table key",17359syntax::std_table(spec), loc));17360}1736117362loc = first;17363loc.advance(); // skip [17364skip_whitespace(loc, ctx);1736517366auto keys_res = parse_key(loc, ctx);17367if(keys_res.is_err())17368{17369return err(std::move(keys_res.unwrap_err()));17370}1737117372skip_whitespace(loc, ctx);17373loc.advance(); // ]1737417375return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg)));17376}1737717378template<typename TC>17379result<std::pair<std::vector<typename basic_value<TC>::key_type>, region>, error_info>17380parse_array_table_key(location& loc, context<TC>& ctx)17381{17382const auto first = loc;17383const auto& spec = ctx.toml_spec();1738417385auto reg = syntax::array_table(spec).scan(loc);17386if(!reg.is_ok())17387{17388return err(make_syntax_error("toml::parse_array_table_key: invalid array-of-tables key",17389syntax::array_table(spec), loc));17390}1739117392loc = first;17393loc.advance(); // [17394loc.advance(); // [17395skip_whitespace(loc, ctx);1739617397auto keys_res = parse_key(loc, ctx);17398if(keys_res.is_err())17399{17400return err(std::move(keys_res.unwrap_err()));17401}1740217403skip_whitespace(loc, ctx);17404loc.advance(); // ]17405loc.advance(); // ]1740617407return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg)));17408}1740917410// called after reading [table.keys] and comments around it.17411// Since table may already contain a subtable ([x.y.z] can be defined before [x]),17412// the table that is being parsed is passed as an argument.17413template<typename TC>17414result<none_t, error_info>17415parse_table(location& loc, context<TC>& ctx, basic_value<TC>& table)17416{17417assert(table.is_table());1741817419const auto num_errors = ctx.errors().size();17420const auto& spec = ctx.toml_spec();1742117422// clear indent info17423table.as_table_fmt().indent_type = indent_char::none;1742417425bool newline_found = true;17426while( ! loc.eof())17427{17428const auto start = loc;1742917430auto sp = skip_multiline_spacer(loc, ctx, newline_found);1743117432// if reached to EOF, the table ends here. return.17433if(loc.eof())17434{17435break;17436}17437// if next table is comming, return.17438if(sequence(syntax::ws(spec), character('[')).scan(loc).is_ok())17439{17440loc = start;17441break;17442}17443// otherwise, it should be a key-value pair.17444newline_found = newline_found || (sp.has_value() && sp.value().newline_found);17445if( ! newline_found)17446{17447return err(make_error_info("toml::parse_table: "17448"newline (LF / CRLF) or EOF is expected",17449source_location(region(loc)), "here"));17450}17451if(sp.has_value() && sp.value().indent_type != indent_char::none)17452{17453table.as_table_fmt().indent_type = sp.value().indent_type;17454table.as_table_fmt().body_indent = sp.value().indent;17455}1745617457newline_found = false; // reset17458if(auto kv_res = parse_key_value_pair(loc, ctx))17459{17460auto keys = std::move(kv_res.unwrap().first.first);17461auto key_reg = std::move(kv_res.unwrap().first.second);17462auto val = std::move(kv_res.unwrap().second);1746317464if(sp.has_value())17465{17466for(const auto& com : sp.value().comments)17467{17468val.comments().push_back(com);17469}17470}1747117472if(auto com_res = parse_comment_line(loc, ctx))17473{17474if(auto com_opt = com_res.unwrap())17475{17476val.comments().push_back(com_opt.value());17477newline_found = true; // comment includes newline at the end17478}17479}17480else17481{17482ctx.report_error(std::move(com_res.unwrap_err()));17483}1748417485auto ins_res = insert_value(inserting_value_kind::dotted_keys,17486std::addressof(table.as_table()),17487keys, std::move(key_reg), std::move(val));17488if(ins_res.is_err())17489{17490ctx.report_error(std::move(ins_res.unwrap_err()));17491}17492}17493else17494{17495ctx.report_error(std::move(kv_res.unwrap_err()));17496skip_key_value_pair(loc, ctx);17497}17498}1749917500if(num_errors < ctx.errors().size())17501{17502assert(ctx.has_error()); // already reported17503return err(ctx.pop_last_error());17504}17505return ok();17506}1750717508template<typename TC>17509result<basic_value<TC>, std::vector<error_info>>17510parse_file(location& loc, context<TC>& ctx)17511{17512using value_type = basic_value<TC>;17513using table_type = typename value_type::table_type;1751417515const auto first = loc;17516const auto& spec = ctx.toml_spec();1751717518if(loc.eof())17519{17520return ok(value_type(table_type(), table_format_info{}, {}, region(loc)));17521}1752217523value_type root(table_type(), table_format_info{}, {}, region(loc));17524root.as_table_fmt().fmt = table_format::multiline;17525root.as_table_fmt().indent_type = indent_char::none;1752617527// parse top comment.17528//17529// ```toml17530// # this is a comment for the top-level table.17531//17532// key = "the first value"17533// ```17534//17535// ```toml17536// # this is a comment for "the first value".17537// key = "the first value"17538// ```17539while( ! loc.eof())17540{17541if(auto com_res = parse_comment_line(loc, ctx))17542{17543if(auto com_opt = com_res.unwrap())17544{17545root.comments().push_back(std::move(com_opt.value()));17546}17547else // no comment found.17548{17549// if it is not an empty line, clear the root comment.17550if( ! sequence(syntax::ws(spec), syntax::newline(spec)).scan(loc).is_ok())17551{17552loc = first;17553root.comments().clear();17554}17555break;17556}17557}17558else17559{17560ctx.report_error(std::move(com_res.unwrap_err()));17561skip_comment_block(loc, ctx);17562}17563}1756417565// parse root table17566{17567const auto res = parse_table(loc, ctx, root);17568if(res.is_err())17569{17570ctx.report_error(std::move(res.unwrap_err()));17571skip_until_next_table(loc, ctx);17572}17573}1757417575// parse tables1757617577while( ! loc.eof())17578{17579auto sp = skip_multiline_spacer(loc, ctx, /*newline_found=*/true);1758017581if(auto key_res = parse_array_table_key(loc, ctx))17582{17583auto key = std::move(std::get<0>(key_res.unwrap()));17584auto reg = std::move(std::get<1>(key_res.unwrap()));1758517586std::vector<std::string> com;17587if(sp.has_value())17588{17589for(std::size_t i=0; i<sp.value().comments.size(); ++i)17590{17591com.push_back(std::move(sp.value().comments.at(i)));17592}17593}1759417595// [table.def] must be followed by one of17596// - a comment line17597// - whitespace + newline17598// - EOF17599if(auto com_res = parse_comment_line(loc, ctx))17600{17601if(auto com_opt = com_res.unwrap())17602{17603com.push_back(com_opt.value());17604}17605else // if there is no comment, ws+newline must exist (or EOF)17606{17607skip_whitespace(loc, ctx);17608if( ! loc.eof() && ! syntax::newline(ctx.toml_spec()).scan(loc).is_ok())17609{17610ctx.report_error(make_syntax_error("toml::parse_file: "17611"newline (or EOF) expected",17612syntax::newline(ctx.toml_spec()), loc));17613skip_until_next_table(loc, ctx);17614continue;17615}17616}17617}17618else // comment syntax error (rare)17619{17620ctx.report_error(com_res.unwrap_err());17621skip_until_next_table(loc, ctx);17622continue;17623}1762417625table_format_info fmt;17626fmt.fmt = table_format::multiline;17627fmt.indent_type = indent_char::none;17628auto tab = value_type(table_type{}, std::move(fmt), std::move(com), reg);1762917630auto inserted = insert_value(inserting_value_kind::array_table,17631std::addressof(root.as_table()),17632key, std::move(reg), std::move(tab));1763317634if(inserted.is_err())17635{17636ctx.report_error(inserted.unwrap_err());1763717638// check errors in the table17639auto tmp = basic_value<TC>(table_type());17640auto res = parse_table(loc, ctx, tmp);17641if(res.is_err())17642{17643ctx.report_error(res.unwrap_err());17644skip_until_next_table(loc, ctx);17645}17646continue;17647}1764817649auto tab_ptr = inserted.unwrap();17650assert(tab_ptr);1765117652const auto tab_res = parse_table(loc, ctx, *tab_ptr);17653if(tab_res.is_err())17654{17655ctx.report_error(tab_res.unwrap_err());17656skip_until_next_table(loc, ctx);17657}1765817659// parse_table first clears `indent_type`.17660// to keep header indent info, we must store it later.17661if(sp.has_value() && sp.value().indent_type != indent_char::none)17662{17663tab_ptr->as_table_fmt().indent_type = sp.value().indent_type;17664tab_ptr->as_table_fmt().name_indent = sp.value().indent;17665}17666continue;17667}17668if(auto key_res = parse_table_key(loc, ctx))17669{17670auto key = std::move(std::get<0>(key_res.unwrap()));17671auto reg = std::move(std::get<1>(key_res.unwrap()));1767217673std::vector<std::string> com;17674if(sp.has_value())17675{17676for(std::size_t i=0; i<sp.value().comments.size(); ++i)17677{17678com.push_back(std::move(sp.value().comments.at(i)));17679}17680}1768117682// [table.def] must be followed by one of17683// - a comment line17684// - whitespace + newline17685// - EOF17686if(auto com_res = parse_comment_line(loc, ctx))17687{17688if(auto com_opt = com_res.unwrap())17689{17690com.push_back(com_opt.value());17691}17692else // if there is no comment, ws+newline must exist (or EOF)17693{17694skip_whitespace(loc, ctx);17695if( ! loc.eof() && ! syntax::newline(ctx.toml_spec()).scan(loc).is_ok())17696{17697ctx.report_error(make_syntax_error("toml::parse_file: "17698"newline (or EOF) expected",17699syntax::newline(ctx.toml_spec()), loc));17700skip_until_next_table(loc, ctx);17701continue;17702}17703}17704}17705else // comment syntax error (rare)17706{17707ctx.report_error(com_res.unwrap_err());17708skip_until_next_table(loc, ctx);17709continue;17710}1771117712table_format_info fmt;17713fmt.fmt = table_format::multiline;17714fmt.indent_type = indent_char::none;17715auto tab = value_type(table_type{}, std::move(fmt), std::move(com), reg);1771617717auto inserted = insert_value(inserting_value_kind::std_table,17718std::addressof(root.as_table()),17719key, std::move(reg), std::move(tab));1772017721if(inserted.is_err())17722{17723ctx.report_error(inserted.unwrap_err());1772417725// check errors in the table17726auto tmp = basic_value<TC>(table_type());17727auto res = parse_table(loc, ctx, tmp);17728if(res.is_err())17729{17730ctx.report_error(res.unwrap_err());17731skip_until_next_table(loc, ctx);17732}17733continue;17734}1773517736auto tab_ptr = inserted.unwrap();17737assert(tab_ptr);1773817739const auto tab_res = parse_table(loc, ctx, *tab_ptr);17740if(tab_res.is_err())17741{17742ctx.report_error(tab_res.unwrap_err());17743skip_until_next_table(loc, ctx);17744}17745if(sp.has_value() && sp.value().indent_type != indent_char::none)17746{17747tab_ptr->as_table_fmt().indent_type = sp.value().indent_type;17748tab_ptr->as_table_fmt().name_indent = sp.value().indent;17749}17750continue;17751}1775217753// does not match array_table nor std_table. report an error.17754const auto keytop = loc;17755const auto maybe_array_of_tables = literal("[[").scan(loc).is_ok();17756loc = keytop;1775717758if(maybe_array_of_tables)17759{17760ctx.report_error(make_syntax_error("toml::parse_file: invalid array-table key",17761syntax::array_table(spec), loc));17762}17763else17764{17765ctx.report_error(make_syntax_error("toml::parse_file: invalid table key",17766syntax::std_table(spec), loc));17767}17768skip_until_next_table(loc, ctx);17769}1777017771if( ! ctx.errors().empty())17772{17773return err(std::move(ctx.errors()));17774}1777517776#ifdef TOML11_ENABLE_ACCESS_CHECK17777detail::unset_access_flag_recursively(root);17778#endif1777917780return ok(std::move(root));17781}1778217783template<typename TC>17784result<basic_value<TC>, std::vector<error_info>>17785parse_impl(std::vector<location::char_type> cs, std::string fname, const spec& s)17786{17787using value_type = basic_value<TC>;17788using table_type = typename value_type::table_type;1778917790// an empty file is a valid toml file.17791if(cs.empty())17792{17793auto src = std::make_shared<std::vector<location::char_type>>(std::move(cs));17794location loc(std::move(src), std::move(fname));17795return ok(value_type(table_type(), table_format_info{}, std::vector<std::string>{}, region(loc)));17796}1779717798// to simplify parser, add newline at the end if there is no LF.17799// But, if it has raw CR, the file is invalid (in TOML, CR is not a valid17800// newline char). if it ends with CR, do not add LF and report it.17801if(cs.back() != '\n' && cs.back() != '\r')17802{17803cs.push_back('\n');17804}1780517806auto src = std::make_shared<std::vector<location::char_type>>(std::move(cs));1780717808location loc(std::move(src), std::move(fname));1780917810// skip BOM if found17811if(loc.source()->size() >= 3)17812{17813auto first = loc;1781417815const auto c0 = loc.current(); loc.advance();17816const auto c1 = loc.current(); loc.advance();17817const auto c2 = loc.current(); loc.advance();1781817819const auto bom_found = (c0 == 0xEF) && (c1 == 0xBB) && (c2 == 0xBF);17820if( ! bom_found)17821{17822loc = first;17823}17824}1782517826context<TC> ctx(s);1782717828return parse_file(loc, ctx);17829}1783017831} // detail1783217833// -----------------------------------------------------------------------------17834// parse(byte array)1783517836template<typename TC = type_config>17837result<basic_value<TC>, std::vector<error_info>>17838try_parse(std::vector<unsigned char> content, std::string filename,17839spec s = spec::default_version())17840{17841return detail::parse_impl<TC>(std::move(content), std::move(filename), std::move(s));17842}17843template<typename TC = type_config>17844basic_value<TC>17845parse(std::vector<unsigned char> content, std::string filename,17846spec s = spec::default_version())17847{17848auto res = try_parse<TC>(std::move(content), std::move(filename), std::move(s));17849if(res.is_ok())17850{17851return res.unwrap();17852}17853else17854{17855std::string msg;17856for(const auto& err : res.unwrap_err())17857{17858msg += format_error(err);17859}17860throw syntax_error(std::move(msg), std::move(res.unwrap_err()));17861}17862}1786317864// -----------------------------------------------------------------------------17865// parse(istream)1786617867template<typename TC = type_config>17868result<basic_value<TC>, std::vector<error_info>>17869try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::default_version())17870{17871const auto beg = is.tellg();17872is.seekg(0, std::ios::end);17873const auto end = is.tellg();17874const auto fsize = end - beg;17875is.seekg(beg);1787617877// read whole file as a sequence of char17878assert(fsize >= 0);17879std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');17880is.read(reinterpret_cast<char*>(letters.data()), static_cast<std::streamsize>(fsize));1788117882return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));17883}1788417885template<typename TC = type_config>17886basic_value<TC> parse(std::istream& is, std::string fname = "unknown file", spec s = spec::default_version())17887{17888auto res = try_parse<TC>(is, std::move(fname), std::move(s));17889if(res.is_ok())17890{17891return res.unwrap();17892}17893else17894{17895std::string msg;17896for(const auto& err : res.unwrap_err())17897{17898msg += format_error(err);17899}17900throw syntax_error(std::move(msg), std::move(res.unwrap_err()));17901}17902}1790317904// -----------------------------------------------------------------------------17905// parse(filename)1790617907template<typename TC = type_config>17908result<basic_value<TC>, std::vector<error_info>>17909try_parse(std::string fname, spec s = spec::default_version())17910{17911std::ifstream ifs(fname, std::ios_base::binary);17912if(!ifs.good())17913{17914std::vector<error_info> e;17915e.push_back(error_info("toml::parse: Error opening file \"" + fname + "\"", {}));17916return err(std::move(e));17917}17918ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);1791917920return try_parse<TC>(ifs, std::move(fname), std::move(s));17921}1792217923template<typename TC = type_config>17924basic_value<TC> parse(std::string fname, spec s = spec::default_version())17925{17926std::ifstream ifs(fname, std::ios_base::binary);17927if(!ifs.good())17928{17929throw file_io_error("toml::parse: error opening file", fname);17930}17931ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);1793217933return parse<TC>(ifs, std::move(fname), std::move(s));17934}1793517936template<typename TC = type_config, std::size_t N>17937result<basic_value<TC>, std::vector<error_info>>17938try_parse(const char (&fname)[N], spec s = spec::default_version())17939{17940return try_parse<TC>(std::string(fname), std::move(s));17941}1794217943template<typename TC = type_config, std::size_t N>17944basic_value<TC> parse(const char (&fname)[N], spec s = spec::default_version())17945{17946return parse<TC>(std::string(fname), std::move(s));17947}1794817949// ----------------------------------------------------------------------------17950// parse_str1795117952template<typename TC = type_config>17953result<basic_value<TC>, std::vector<error_info>>17954try_parse_str(std::string content, spec s = spec::default_version(),17955cxx::source_location loc = cxx::source_location::current())17956{17957std::istringstream iss(std::move(content));17958std::string name("internal string" + cxx::to_string(loc));17959return try_parse<TC>(iss, std::move(name), std::move(s));17960}1796117962template<typename TC = type_config>17963basic_value<TC> parse_str(std::string content, spec s = spec::default_version(),17964cxx::source_location loc = cxx::source_location::current())17965{17966auto res = try_parse_str<TC>(std::move(content), std::move(s), std::move(loc));17967if(res.is_ok())17968{17969return res.unwrap();17970}17971else17972{17973std::string msg;17974for(const auto& err : res.unwrap_err())17975{17976msg += format_error(err);17977}17978throw syntax_error(std::move(msg), std::move(res.unwrap_err()));17979}17980}1798117982// ----------------------------------------------------------------------------17983// filesystem1798417985#if defined(TOML11_HAS_FILESYSTEM)1798617987template<typename TC = type_config, typename FSPATH>17988cxx::enable_if_t<std::is_same<FSPATH, std::filesystem::path>::value,17989result<basic_value<TC>, std::vector<error_info>>>17990try_parse(const FSPATH& fpath, spec s = spec::default_version())17991{17992std::ifstream ifs(fpath, std::ios_base::binary);17993if(!ifs.good())17994{17995std::vector<error_info> e;17996e.push_back(error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", {}));17997return err(std::move(e));17998}17999ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);1800018001return try_parse<TC>(ifs, fpath.string(), std::move(s));18002}1800318004template<typename TC = type_config, typename FSPATH>18005cxx::enable_if_t<std::is_same<FSPATH, std::filesystem::path>::value,18006basic_value<TC>>18007parse(const FSPATH& fpath, spec s = spec::default_version())18008{18009std::ifstream ifs(fpath, std::ios_base::binary);18010if(!ifs.good())18011{18012throw file_io_error("toml::parse: error opening file", fpath.string());18013}18014ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);1801518016return parse<TC>(ifs, fpath.string(), std::move(s));18017}18018#endif1801918020// -----------------------------------------------------------------------------18021// FILE*1802218023template<typename TC = type_config>18024result<basic_value<TC>, std::vector<error_info>>18025try_parse(FILE* fp, std::string filename, spec s = spec::default_version())18026{18027const long beg = std::ftell(fp);18028if (beg == -1L)18029{18030return err(std::vector<error_info>{error_info(18031std::string("Failed to access: \"") + filename +18032"\", errno = " + std::to_string(errno), {}18033)});18034}1803518036const int res_seekend = std::fseek(fp, 0, SEEK_END);18037if (res_seekend != 0)18038{18039return err(std::vector<error_info>{error_info(18040std::string("Failed to seek: \"") + filename +18041"\", errno = " + std::to_string(errno), {}18042)});18043}1804418045const long end = std::ftell(fp);18046if (end == -1L)18047{18048return err(std::vector<error_info>{error_info(18049std::string("Failed to access: \"") + filename +18050"\", errno = " + std::to_string(errno), {}18051)});18052}1805318054const auto fsize = end - beg;1805518056const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET);18057if (res_seekbeg != 0)18058{18059return err(std::vector<error_info>{error_info(18060std::string("Failed to seek: \"") + filename +18061"\", errno = " + std::to_string(errno), {}18062)});1806318064}1806518066// read whole file as a sequence of char18067assert(fsize >= 0);18068std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));18069const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);18070if(actual != static_cast<std::size_t>(fsize))18071{18072return err(std::vector<error_info>{error_info(18073std::string("File size changed: \"") + filename +18074std::string("\" make sure that FILE* is in binary mode "18075"to avoid LF <-> CRLF conversion"), {}18076)});18077}1807818079return detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));18080}1808118082template<typename TC = type_config>18083basic_value<TC>18084parse(FILE* fp, std::string filename, spec s = spec::default_version())18085{18086const long beg = std::ftell(fp);18087if (beg == -1L)18088{18089throw file_io_error(errno, "Failed to access", filename);18090}1809118092const int res_seekend = std::fseek(fp, 0, SEEK_END);18093if (res_seekend != 0)18094{18095throw file_io_error(errno, "Failed to seek", filename);18096}1809718098const long end = std::ftell(fp);18099if (end == -1L)18100{18101throw file_io_error(errno, "Failed to access", filename);18102}1810318104const auto fsize = end - beg;1810518106const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET);18107if (res_seekbeg != 0)18108{18109throw file_io_error(errno, "Failed to seek", filename);18110}1811118112// read whole file as a sequence of char18113assert(fsize >= 0);18114std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));18115const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);18116if(actual != static_cast<std::size_t>(fsize))18117{18118throw file_io_error(errno, "File size changed; make sure that "18119"FILE* is in binary mode to avoid LF <-> CRLF conversion", filename);18120}1812118122auto res = detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));18123if(res.is_ok())18124{18125return res.unwrap();18126}18127else18128{18129std::string msg;18130for(const auto& err : res.unwrap_err())18131{18132msg += format_error(err);18133}18134throw syntax_error(std::move(msg), std::move(res.unwrap_err()));18135}18136}1813718138} // TOML11_INLINE_VERSION_NAMESPACE18139} // namespace toml1814018141#if defined(TOML11_COMPILE_SOURCES)18142namespace toml18143{18144inline namespace TOML11_INLINE_VERSION_NAMESPACE18145{18146struct type_config;18147struct ordered_type_config;1814818149extern template result<basic_value<type_config>, std::vector<error_info>> try_parse<type_config>(std::vector<unsigned char>, std::string, spec);18150extern template result<basic_value<type_config>, std::vector<error_info>> try_parse<type_config>(std::istream&, std::string, spec);18151extern template result<basic_value<type_config>, std::vector<error_info>> try_parse<type_config>(std::string, spec);18152extern template result<basic_value<type_config>, std::vector<error_info>> try_parse<type_config>(FILE*, std::string, spec);18153extern template result<basic_value<type_config>, std::vector<error_info>> try_parse_str<type_config>(std::string, spec, cxx::source_location);1815418155extern template basic_value<type_config> parse<type_config>(std::vector<unsigned char>, std::string, spec);18156extern template basic_value<type_config> parse<type_config>(std::istream&, std::string, spec);18157extern template basic_value<type_config> parse<type_config>(std::string, spec);18158extern template basic_value<type_config> parse<type_config>(FILE*, std::string, spec);18159extern template basic_value<type_config> parse_str<type_config>(std::string, spec, cxx::source_location);1816018161extern template result<basic_value<ordered_type_config>, std::vector<error_info>> try_parse<ordered_type_config>(std::vector<unsigned char>, std::string, spec);18162extern template result<basic_value<ordered_type_config>, std::vector<error_info>> try_parse<ordered_type_config>(std::istream&, std::string, spec);18163extern template result<basic_value<ordered_type_config>, std::vector<error_info>> try_parse<ordered_type_config>(std::string, spec);18164extern template result<basic_value<ordered_type_config>, std::vector<error_info>> try_parse<ordered_type_config>(FILE*, std::string, spec);18165extern template result<basic_value<ordered_type_config>, std::vector<error_info>> try_parse_str<ordered_type_config>(std::string, spec, cxx::source_location);1816618167extern template basic_value<ordered_type_config> parse<ordered_type_config>(std::vector<unsigned char>, std::string, spec);18168extern template basic_value<ordered_type_config> parse<ordered_type_config>(std::istream&, std::string, spec);18169extern template basic_value<ordered_type_config> parse<ordered_type_config>(std::string, spec);18170extern template basic_value<ordered_type_config> parse<ordered_type_config>(FILE*, std::string, spec);18171extern template basic_value<ordered_type_config> parse_str<ordered_type_config>(std::string, spec, cxx::source_location);1817218173#if defined(TOML11_HAS_FILESYSTEM)18174extern template cxx::enable_if_t<std::is_same<std::filesystem::path, std::filesystem::path>::value, result<basic_value<type_config>, std::vector<error_info>>> try_parse<type_config, std::filesystem::path>(const std::filesystem::path&, spec);18175extern template cxx::enable_if_t<std::is_same<std::filesystem::path, std::filesystem::path>::value, result<basic_value<ordered_type_config>, std::vector<error_info>>> try_parse<ordered_type_config, std::filesystem::path>(const std::filesystem::path&, spec);18176extern template cxx::enable_if_t<std::is_same<std::filesystem::path, std::filesystem::path>::value, basic_value<type_config> > parse <type_config, std::filesystem::path>(const std::filesystem::path&, spec);18177extern template cxx::enable_if_t<std::is_same<std::filesystem::path, std::filesystem::path>::value, basic_value<ordered_type_config> > parse <ordered_type_config, std::filesystem::path>(const std::filesystem::path&, spec);18178#endif // filesystem1817918180} // TOML11_INLINE_VERSION_NAMESPACE18181} // toml18182#endif // TOML11_COMPILE_SOURCES1818318184#endif // TOML11_PARSER_HPP18185#ifndef TOML11_LITERAL_HPP18186#define TOML11_LITERAL_HPP1818718188#ifndef TOML11_LITERAL_FWD_HPP18189#define TOML11_LITERAL_FWD_HPP181901819118192namespace toml18193{18194inline namespace TOML11_INLINE_VERSION_NAMESPACE18195{1819618197namespace detail18198{18199// implementation18200::toml::value literal_internal_impl(location loc);18201} // detail1820218203inline namespace literals18204{18205inline namespace toml_literals18206{1820718208::toml::value operator""_toml(const char* str, std::size_t len);1820918210#if defined(TOML11_HAS_CHAR8_T)18211// value of u8"" literal has been changed from char to char8_t and char8_t is18212// NOT compatible to char18213::toml::value operator"" _toml(const char8_t* str, std::size_t len);18214#endif1821518216} // toml_literals18217} // literals18218} // TOML11_INLINE_VERSION_NAMESPACE18219} // toml18220#endif // TOML11_LITERAL_FWD_HPP1822118222#if ! defined(TOML11_COMPILE_SOURCES)18223#ifndef TOML11_LITERAL_IMPL_HPP18224#define TOML11_LITERAL_IMPL_HPP182251822618227namespace toml18228{18229inline namespace TOML11_INLINE_VERSION_NAMESPACE18230{1823118232namespace detail18233{18234// implementation18235TOML11_INLINE ::toml::value literal_internal_impl(location loc)18236{18237const auto s = ::toml::spec::default_version();18238context<type_config> ctx(s);1823918240const auto front = loc;1824118242// ------------------------------------------------------------------------18243// check if it is a raw value.1824418245// skip empty lines and comment lines18246auto sp = skip_multiline_spacer(loc, ctx);18247if(loc.eof())18248{18249::toml::value val;18250if(sp.has_value())18251{18252for(std::size_t i=0; i<sp.value().comments.size(); ++i)18253{18254val.comments().push_back(std::move(sp.value().comments.at(i)));18255}18256}18257return val;18258}1825918260// to distinguish arrays and tables, first check it is a table or not.18261//18262// "[1,2,3]"_toml; // json: [1, 2, 3]18263// "[table]"_toml; // json: {"table": {}}18264// "[[1,2,3]]"_toml; // json: [[1, 2, 3]]18265// "[[table]]"_toml; // json: {"table": [{}]}18266//18267// "[[1]]"_toml; // json: {"1": [{}]}18268// "1 = [{}]"_toml; // json: {"1": [{}]}18269// "[[1,]]"_toml; // json: [[1]]18270// "[[1],]"_toml; // json: [[1]]18271const auto val_start = loc;1827218273const bool is_table_key = syntax::std_table(s).scan(loc).is_ok();18274loc = val_start;18275const bool is_aots_key = syntax::array_table(s).scan(loc).is_ok();18276loc = val_start;1827718278// If it is neither a table-key or a array-of-table-key, it may be a value.18279if(!is_table_key && !is_aots_key)18280{18281auto data = parse_value(loc, ctx);18282if(data.is_ok())18283{18284auto val = std::move(data.unwrap());18285if(sp.has_value())18286{18287for(std::size_t i=0; i<sp.value().comments.size(); ++i)18288{18289val.comments().push_back(std::move(sp.value().comments.at(i)));18290}18291}18292auto com_res = parse_comment_line(loc, ctx);18293if(com_res.is_ok() && com_res.unwrap().has_value())18294{18295val.comments().push_back(com_res.unwrap().value());18296}18297return val;18298}18299}1830018301// -------------------------------------------------------------------------18302// Note that still it can be a table, because the literal might be something18303// like the following.18304// ```cpp18305// // c++11 raw-string literal18306// const auto val = R"(18307// key = "value"18308// int = 4218309// )"_toml;18310// ```18311// It is a valid toml file.18312// It should be parsed as if we parse a file with this content.1831318314loc = front;18315auto data = parse_file(loc, ctx);18316if(data.is_ok())18317{18318return data.unwrap();18319}18320else // not a value && not a file. error.18321{18322std::string msg;18323for(const auto& err : data.unwrap_err())18324{18325msg += format_error(err);18326}18327throw ::toml::syntax_error(std::move(msg), std::move(data.unwrap_err()));18328}18329}1833018331} // detail1833218333inline namespace literals18334{18335inline namespace toml_literals18336{1833718338TOML11_INLINE ::toml::value18339operator""_toml(const char* str, std::size_t len)18340{18341if(len == 0)18342{18343return ::toml::value{};18344}1834518346::toml::detail::location::container_type c(len);18347std::copy(reinterpret_cast<const ::toml::detail::location::char_type*>(str),18348reinterpret_cast<const ::toml::detail::location::char_type*>(str + len),18349c.begin());18350if( ! c.empty() && c.back())18351{18352c.push_back('\n'); // to make it easy to parse comment, we add newline18353}1835418355return literal_internal_impl(::toml::detail::location(18356std::make_shared<const toml::detail::location::container_type>(std::move(c)),18357"TOML literal encoded in a C++ code"));18358}1835918360#if defined(__cpp_char8_t)18361# if __cpp_char8_t >= 201811L18362# define TOML11_HAS_CHAR8_T 118363# endif18364#endif1836518366#if defined(TOML11_HAS_CHAR8_T)18367// value of u8"" literal has been changed from char to char8_t and char8_t is18368// NOT compatible to char18369TOML11_INLINE ::toml::value18370operator"" _toml(const char8_t* str, std::size_t len)18371{18372if(len == 0)18373{18374return ::toml::value{};18375}1837618377::toml::detail::location::container_type c(len);18378std::copy(reinterpret_cast<const ::toml::detail::location::char_type*>(str),18379reinterpret_cast<const ::toml::detail::location::char_type*>(str + len),18380c.begin());18381if( ! c.empty() && c.back())18382{18383c.push_back('\n'); // to make it easy to parse comment, we add newline18384}1838518386return literal_internal_impl(::toml::detail::location(18387std::make_shared<const toml::detail::location::container_type>(std::move(c)),18388"TOML literal encoded in a C++ code"));18389}18390#endif1839118392} // toml_literals18393} // literals18394} // TOML11_INLINE_VERSION_NAMESPACE18395} // toml18396#endif // TOML11_LITERAL_IMPL_HPP18397#endif1839818399#endif // TOML11_LITERAL_HPP18400#ifndef TOML11_TOML_HPP18401#define TOML11_TOML_HPP1840218403// The MIT License (MIT)18404//18405// Copyright (c) 2017-now Toru Niina18406//18407// Permission is hereby granted, free of charge, to any person obtaining a copy18408// of this software and associated documentation files (the "Software"), to deal18409// in the Software without restriction, including without limitation the rights18410// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell18411// copies of the Software, and to permit persons to whom the Software is18412// furnished to do so, subject to the following conditions:18413//18414// The above copyright notice and this permission notice shall be included in18415// all copies or substantial portions of the Software.18416//18417// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18418// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18419// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE18420// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18421// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,18422// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN18423// THE SOFTWARE.1842418425// IWYU pragma: begin_exports18426// IWYU pragma: end_exports1842718428#endif// TOML11_TOML_HPP184291843018431