diff --git a/.circleci/config.yml b/.circleci/config.yml index 26f52c9..6c2068d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,10 @@ jobs: resource_class: large steps: - checkout + - run: + name: Installing dependencies + command: | + pip3 install --upgrade -r tools/requirements.txt - run: name: Checking toml.hpp command: | @@ -28,10 +32,6 @@ jobs: resource_class: large steps: - checkout - - run: - name: Checking toml.hpp - command: | - cd tools && python3 ci_single_header_check.py - run: name: Pulling submodules command: | @@ -83,7 +83,7 @@ jobs: - run: name: Installing dependencies command: | - pip3 install -r tools/requirements.txt + pip3 install --upgrade -r tools/requirements.txt - run: name: Generating documentation command: | diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6d5f29d --- /dev/null +++ b/.clang-format @@ -0,0 +1,185 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: Consecutive +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveBitFields: Consecutive +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - TOML_ABSTRACT_BASE + - TOML_EMPTY_BASES + - TOML_TRIVIAL_ABI +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^([/*!#]|\s*(===|---|clang-format))' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DeriveLineEnding: false +DerivePointerAlignment: false +DisableFormat: false +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +StatementAttributeLikeMacros: + - Q_EMIT +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: BeforeHash +IndentExternBlock: Indent +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 1 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000000 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortJavaStaticImport: Before +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementMacros: + - TOML_ALWAYS_INLINE + - TOML_API + - TOML_ATTR + - TOML_CONSTEVAL + - TOML_EXTERNAL_LINKAGE + - TOML_INTERNAL_LINKAGE + - TOML_MEMBER_ATTR + - TOML_NEVER_INLINE + - TOML_NODISCARD + - TOML_NODISCARD_CTOR + - TOML_RETURNS_BY_THROWING +TabWidth: 4 +TypenameMacros: +UseCRLF: false +UseTab: Always +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - TOML_ATTR + - TOML_CONCAT + - TOML_LIKELY + - TOML_MAKE_RAW_STRING + - TOML_MAKE_STRING + - TOML_MAKE_STRING_VIEW + - TOML_PRAGMA_CLANG + - TOML_PRAGMA_GCC + - TOML_PRAGMA_MSVC + - TOML_UNLIKELY +... + diff --git a/CMakeLists.txt b/CMakeLists.txt index 854f456..a8e414d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.14) project( tomlplusplus - VERSION 2.5.0 + VERSION 2.6.0 DESCRIPTION "Header-only TOML config file parser and serializer for C++17 (and later!)" HOMEPAGE_URL "https://marzer.github.io/tomlplusplus/" LANGUAGES CXX diff --git a/cpp.hint b/cpp.hint index 111e53f..81a2d7f 100644 --- a/cpp.hint +++ b/cpp.hint @@ -7,8 +7,10 @@ #define TOML_EMPTY_BASES #define TOML_MAY_THROW #define TOML_CONSTEVAL constexpr -#define TOML_LIKELY(...) (__VA_ARGS__) -#define TOML_UNLIKELY(...) (__VA_ARGS__) +#define TOML_CONSTRAINED_TEMPLATE(condition, ...) template <__VA_ARGS__> +#define TOML_LIKELY(...) (__VA_ARGS__) +#define TOML_UNLIKELY(...) (__VA_ARGS__) +#define TOML_NODISCARD #define TOML_NODISCARD_CTOR #define TOML_EXTERNAL_LINKAGE #define TOML_INTERNAL_LINKAGE diff --git a/include/toml++/impl/array.h b/include/toml++/impl/array.h new file mode 100644 index 0000000..7a1654c --- /dev/null +++ b/include/toml++/impl/array.h @@ -0,0 +1,1116 @@ +//# This file is a part of toml++ and is subject to the the terms of the MIT license. +//# Copyright (c) Mark Gillard +//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + +#pragma once +#include "value.h" + +/// \cond +TOML_IMPL_NAMESPACE_START +{ + template + class TOML_TRIVIAL_ABI array_iterator final + { + private: + template + friend class array_iterator; + friend class TOML_NAMESPACE::array; + + using raw_mutable_iterator = std::vector>::iterator; + using raw_const_iterator = std::vector>::const_iterator; + using raw_iterator = std::conditional_t; + + mutable raw_iterator raw_; + + TOML_NODISCARD_CTOR + array_iterator(raw_mutable_iterator raw) noexcept // + : raw_{ raw } + {} + + TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst) + TOML_NODISCARD_CTOR + array_iterator(raw_const_iterator raw) noexcept // + : raw_{ raw } + {} + + public: + using value_type = std::conditional_t; + using reference = value_type&; + using pointer = value_type*; + using difference_type = ptrdiff_t; + using iterator_category = typename std::iterator_traits::iterator_category; + + TOML_NODISCARD_CTOR + array_iterator() noexcept = default; + + TOML_NODISCARD_CTOR + array_iterator(const array_iterator&) noexcept = default; + + array_iterator& operator=(const array_iterator&) noexcept = default; + + array_iterator& operator++() noexcept // ++pre + { + ++raw_; + return *this; + } + + array_iterator operator++(int) noexcept // post++ + { + array_iterator out{ raw_ }; + ++raw_; + return out; + } + + array_iterator& operator--() noexcept // --pre + { + --raw_; + return *this; + } + + array_iterator operator--(int) noexcept // post-- + { + array_iterator out{ raw_ }; + --raw_; + return out; + } + + TOML_NODISCARD + reference operator*() const noexcept + { + return *raw_->get(); + } + + TOML_NODISCARD + pointer operator->() const noexcept + { + return raw_->get(); + } + + array_iterator& operator+=(ptrdiff_t rhs) noexcept + { + raw_ += rhs; + return *this; + } + + array_iterator& operator-=(ptrdiff_t rhs) noexcept + { + raw_ -= rhs; + return *this; + } + + TOML_NODISCARD + friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept + { + return { lhs.raw_ + rhs }; + } + + TOML_NODISCARD + friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept + { + return { rhs.raw_ + lhs }; + } + + TOML_NODISCARD + friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept + { + return { lhs.raw_ - rhs }; + } + + TOML_NODISCARD + friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ - rhs.raw_; + } + + TOML_NODISCARD + friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ == rhs.raw_; + } + + TOML_NODISCARD + friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ != rhs.raw_; + } + + TOML_NODISCARD + friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ < rhs.raw_; + } + + TOML_NODISCARD + friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ <= rhs.raw_; + } + + TOML_NODISCARD + friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ > rhs.raw_; + } + + TOML_NODISCARD + friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ >= rhs.raw_; + } + + TOML_NODISCARD + reference operator[](ptrdiff_t idx) const noexcept + { + return *(raw_ + idx)->get(); + } + + TOML_DISABLE_WARNINGS; + + TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst) + TOML_NODISCARD + operator array_iterator() const noexcept + { + return array_iterator{ raw_ }; + } + + TOML_ENABLE_WARNINGS; + }; +} +TOML_IMPL_NAMESPACE_END; +/// \endcond + +TOML_NAMESPACE_START +{ + /// \brief A RandomAccessIterator for iterating over elements in a toml::array. + using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator); + + /// \brief A RandomAccessIterator for iterating over const elements in a toml::array. + using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator); + + /// \brief A TOML array. + /// + /// \detail The interface of this type is modeled after std::vector, with some + /// additional considerations made for the heterogeneous nature of a + /// TOML array. + /// + /// \godbolt{sjK4da} + /// + /// \cpp + /// + /// toml::table tbl = toml::parse(R"( + /// arr = [1, 2, 3, 4, 'five'] + /// )"sv); + /// + /// // get the element as an array + /// toml::array& arr = *tbl.get_as("arr"); + /// std::cout << arr << "\n"; + /// + /// // increment each element with visit() + /// for (auto&& elem : arr) + /// { + /// elem.visit([](auto&& el) noexcept + /// { + /// if constexpr (toml::is_number) + /// (*el)++; + /// else if constexpr (toml::is_string) + /// el = "six"sv; + /// }); + /// } + /// std::cout << arr << "\n"; + /// + /// // add and remove elements + /// arr.push_back(7); + /// arr.push_back(8.0f); + /// arr.push_back("nine"sv); + /// arr.erase(arr.cbegin()); + /// std::cout << arr << "\n"; + /// + /// // emplace elements + /// arr.emplace_back("ten"); + /// arr.emplace_back(11, 12.0); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, 3, 4, 'five' ] + /// [ 2, 3, 4, 5, 'six' ] + /// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ] + /// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ] + /// \eout + class TOML_API array final : public node + { + private: + /// \cond + + friend class TOML_PARSER_TYPENAME; + std::vector> elements; + + void preinsertion_resize(size_t idx, size_t count) noexcept; + + template + void emplace_back_if_not_empty_view(T&& val) noexcept + { + if constexpr (is_node_view) + { + if (!val) + return; + } + elements.emplace_back(impl::make_node(static_cast(val))); + } + + TOML_NODISCARD + size_t total_leaf_count() const noexcept; + + void flatten_child(array&& child, size_t& dest_index) noexcept; + /// \endcond + + public: + using value_type = node; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = node&; + using const_reference = const node&; + + /// \brief A RandomAccessIterator for iterating over elements in a toml::array. + using iterator = array_iterator; + /// \brief A RandomAccessIterator for iterating over const elements in a toml::array. + using const_iterator = const_array_iterator; + + /// \brief Default constructor. + TOML_NODISCARD_CTOR + array() noexcept; + + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + array(const array&) noexcept; + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + array(array&& other) noexcept; + + /// \brief Copy-assignment operator. + array& operator=(const array&) noexcept; + + /// \brief Move-assignment operator. + array& operator=(array&& rhs) noexcept; + +#if TOML_LIFETIME_HOOKS + ~array() noexcept override + { + TOML_ARRAY_DESTROYED; + } +#endif + + /// \brief Constructs an array with one or more initial elements. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } }; + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2.0, 'three', [ 4, 5 ] ] + /// \eout + /// + /// \remark \parblock If you need to construct an array with one child array element, the array's move constructor + /// will take precedence and perform a move-construction instead. You can use toml::inserter to + /// suppress this behaviour: \cpp + /// // desired result: [ [ 42 ] ] + /// auto bad = toml::array{ toml::array{ 42 } } + /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } } + /// std::cout << "bad: " << bad << "\n"; + /// std::cout << "good:" << good << "\n"; + /// \ecpp + /// + /// \out + /// bad: [ 42 ] + /// good: [ [ 42 ] ] + /// \eout + /// + /// \endparblock + /// + /// \tparam ElemType One of the TOML node or value types (or a type promotable to one). + /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one). + /// \param val The node or value used to initialize element 0. + /// \param vals The nodes or values used to initialize elements 1...N. + TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0_sz + || !std::is_same_v, array>), + typename ElemType, + typename... ElemTypes) + TOML_NODISCARD_CTOR + explicit array(ElemType&& val, ElemTypes&&... vals) + { + elements.reserve(sizeof...(ElemTypes) + 1_sz); + emplace_back_if_not_empty_view(static_cast(val)); + if constexpr (sizeof...(ElemTypes) > 0) + { + (emplace_back_if_not_empty_view(static_cast(vals)), ...); + } + +#if TOML_LIFETIME_HOOKS + TOML_ARRAY_CREATED; +#endif + } + + /// \name Type checks + /// @{ + + TOML_NODISCARD + node_type type() const noexcept override + { + return node_type::array; + } + + TOML_NODISCARD + bool is_table() const noexcept override + { + return false; + } + + TOML_NODISCARD + bool is_array() const noexcept override + { + return true; + } + + TOML_NODISCARD + bool is_value() const noexcept override + { + return false; + } + + TOML_NODISCARD + array* as_array() noexcept override + { + return this; + } + + TOML_NODISCARD + const array* as_array() const noexcept override + { + return this; + } + + TOML_NODISCARD + bool is_homogeneous(node_type ntype) const noexcept override; + TOML_NODISCARD + bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override; + TOML_NODISCARD + bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override; + + template + TOML_NODISCARD + bool is_homogeneous() const noexcept + { + using type = impl::unwrap_node; + static_assert( + std::is_void_v< + type> || ((impl::is_native || impl::is_one_of)&&!impl::is_cvref), + "The template type argument of array::is_homogeneous() must be void or one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + return is_homogeneous(impl::node_type_of); + } + + TOML_NODISCARD + bool is_array_of_tables() const noexcept override + { + return is_homogeneous(node_type::table); + } + + /// @} + + /// \name Array operations + /// @{ + + /// \brief Gets a reference to the element at a specific index. + TOML_NODISCARD + node& operator[](size_t index) noexcept; + + /// \brief Gets a reference to the element at a specific index. + TOML_NODISCARD + const node& operator[](size_t index) const noexcept; + + /// \brief Returns a reference to the first element in the array. + TOML_NODISCARD + node& front() noexcept + { + return *elements.front(); + } + + /// \brief Returns a reference to the first element in the array. + TOML_NODISCARD + const node& front() const noexcept + { + return *elements.front(); + } + + /// \brief Returns a reference to the last element in the array. + TOML_NODISCARD + node& back() noexcept + { + return *elements.back(); + } + + /// \brief Returns a reference to the last element in the array. + TOML_NODISCARD + const node& back() const noexcept + { + return *elements.back(); + } + + /// \brief Returns an iterator to the first element. + TOML_NODISCARD + iterator begin() noexcept + { + return { elements.begin() }; + } + + /// \brief Returns an iterator to the first element. + TOML_NODISCARD + const_iterator begin() const noexcept + { + return { elements.cbegin() }; + } + + /// \brief Returns an iterator to the first element. + TOML_NODISCARD + const_iterator cbegin() const noexcept + { + return { elements.cbegin() }; + } + + /// \brief Returns an iterator to one-past-the-last element. + TOML_NODISCARD + iterator end() noexcept + { + return { elements.end() }; + } + + /// \brief Returns an iterator to one-past-the-last element. + TOML_NODISCARD + const_iterator end() const noexcept + { + return { elements.cend() }; + } + + /// \brief Returns an iterator to one-past-the-last element. + TOML_NODISCARD + const_iterator cend() const noexcept + { + return { elements.cend() }; + } + + /// \brief Returns true if the array is empty. + TOML_NODISCARD + bool empty() const noexcept + { + return elements.empty(); + } + + /// \brief Returns the number of elements in the array. + TOML_NODISCARD + size_t size() const noexcept + { + return elements.size(); + } + + /// \brief Reserves internal storage capacity up to a pre-determined number of elements. + void reserve(size_t new_capacity) + { + elements.reserve(new_capacity); + } + + /// \brief Removes all elements from the array. + void clear() noexcept + { + elements.clear(); + } + + /// \brief Returns the maximum number of elements that can be stored in an array on the current platform. + TOML_NODISCARD + size_t max_size() const noexcept + { + return elements.max_size(); + } + + /// \brief Returns the current max number of elements that may be held in the array's internal storage. + TOML_NODISCARD + size_t capacity() const noexcept + { + return elements.capacity(); + } + + /// \brief Requests the removal of any unused internal storage capacity. + void shrink_to_fit() + { + elements.shrink_to_fit(); + } + + /// \brief Inserts a new element at a specific position in the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 3 }; + /// arr.insert(arr.cbegin() + 1, "two"); + /// arr.insert(arr.cend(), toml::array{ 4, 5 }); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 'two', 3, [ 4, 5 ] ] + /// \eout + /// + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). + /// \param pos The insertion position. + /// \param val The node or value being inserted. + /// + /// \returns \conditional_return{Valid input} + /// An iterator to the newly-inserted element. + /// \conditional_return{Input is an empty toml::node_view} + /// end() + /// + /// \attention The return value will always be `end()` if the input value was an empty toml::node_view, + /// because no insertion can take place. This is the only circumstance in which this can occur. + template + iterator insert(const_iterator pos, ElemType&& val) noexcept + { + if constexpr (is_node_view) + { + if (!val) + return end(); + } + return { elements.emplace(pos.raw_, impl::make_node(static_cast(val))) }; + } + + /// \brief Repeatedly inserts a new element starting at a specific position in the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ + /// "with an evil twinkle in its eye the goose said", + /// "and immediately we knew peace was never an option." + /// }; + /// arr.insert(arr.cbegin() + 1, 3, "honk"); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ + /// 'with an evil twinkle in its eye the goose said', + /// 'honk', + /// 'honk', + /// 'honk', + /// 'and immediately we knew peace was never an option.' + /// ] + /// \eout + /// + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). + /// \param pos The insertion position. + /// \param count The number of times the node or value should be inserted. + /// \param val The node or value being inserted. + /// + /// \returns \conditional_return{Valid input} + /// An iterator to the newly-inserted element. + /// \conditional_return{count == 0} + /// A copy of pos + /// \conditional_return{Input is an empty toml::node_view} + /// end() + /// + /// \attention The return value will always be `end()` if the input value was an empty toml::node_view, + /// because no insertion can take place. This is the only circumstance in which this can occur. + template + iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept + { + if constexpr (is_node_view) + { + if (!val) + return end(); + } + switch (count) + { + case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; + case 1: return insert(pos, static_cast(val)); + default: + { + const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); + preinsertion_resize(start_idx, count); + size_t i = start_idx; + for (size_t e = start_idx + count - 1_sz; i < e; i++) + elements[i].reset(impl::make_node(val)); + + //# potentially move the initial value into the last element + elements[i].reset(impl::make_node(static_cast(val))); + return { elements.begin() + static_cast(start_idx) }; + } + } + } + + /// \brief Inserts a range of elements into the array at a specific position. + /// + /// \tparam Iter An iterator type. Must satisfy ForwardIterator. + /// \param pos The insertion position. + /// \param first Iterator to the first node or value being inserted. + /// \param last Iterator to the one-past-the-last node or value being inserted. + /// + /// \returns \conditional_return{Valid input} + /// An iterator to the first newly-inserted element. + /// \conditional_return{first >= last} + /// A copy of pos + /// \conditional_return{All objects in the range were empty toml::node_views} + /// A copy of pos + template + iterator insert(const_iterator pos, Iter first, Iter last) noexcept + { + const auto distance = std::distance(first, last); + if (distance <= 0) + return { elements.begin() + (pos.raw_ - elements.cbegin()) }; + else + { + auto count = distance; + using deref_type = decltype(*first); + if constexpr (is_node_view) + { + for (auto it = first; it != last; it++) + if (!(*it)) + count--; + if (!count) + return { elements.begin() + (pos.raw_ - elements.cbegin()) }; + } + const auto start_idx = static_cast(pos.raw_ - elements.cbegin()); + preinsertion_resize(start_idx, static_cast(count)); + size_t i = start_idx; + for (auto it = first; it != last; it++) + { + if constexpr (is_node_view) + { + if (!(*it)) + continue; + } + if constexpr (std::is_rvalue_reference_v) + elements[i++].reset(impl::make_node(std::move(*it))); + else + elements[i++].reset(impl::make_node(*it)); + } + return { elements.begin() + static_cast(start_idx) }; + } + } + + /// \brief Inserts a range of elements into the array at a specific position. + /// + /// \tparam ElemType toml::node_view, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). + /// \param pos The insertion position. + /// \param ilist An initializer list containing the values to be inserted. + /// + /// \returns \conditional_return{Valid input} + /// An iterator to the first newly-inserted element. + /// \conditional_return{Input list is empty} + /// A copy of pos + /// \conditional_return{All objects in the list were empty toml::node_views} + /// A copy of pos + template + iterator insert(const_iterator pos, std::initializer_list ilist) noexcept + { + return insert(pos, ilist.begin(), ilist.end()); + } + + /// \brief Emplaces a new element at a specific position in the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2 }; + /// + /// //add a string using std::string's substring constructor + /// arr.emplace(arr.cbegin() + 1, "this is not a drill"sv, 14, 5); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 'drill', 2 ] + /// \eout + /// + /// \tparam ElemType toml::table, toml::array, or any native TOML value type. + /// \tparam Args Value constructor argument types. + /// \param pos The insertion position. + /// \param args Arguments to forward to the value's constructor. + /// + /// \returns An iterator to the inserted element. + /// + /// \remarks There is no difference between insert() and emplace() + /// for trivial value types (floats, ints, bools). + template + iterator emplace(const_iterator pos, Args&&... args) noexcept + { + using type = impl::unwrap_node; + static_assert((impl::is_native || impl::is_one_of)&&!impl::is_cvref, + "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + return { elements.emplace(pos.raw_, new impl::wrap_node{ static_cast(args)... }) }; + } + + /// \brief Removes the specified element from the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2, 3 }; + /// std::cout << arr << "\n"; + /// + /// arr.erase(arr.cbegin() + 1); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, 3 ] + /// [ 1, 3 ] + /// \eout + /// + /// \param pos Iterator to the element being erased. + /// + /// \returns Iterator to the first element immediately following the removed element. + iterator erase(const_iterator pos) noexcept + { + return { elements.erase(pos.raw_) }; + } + + /// \brief Removes the elements in the range [first, last) from the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, "bad", "karma" 2 }; + /// std::cout << arr << "\n"; + /// + /// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 'bad', 'karma', 3 ] + /// [ 1, 3 ] + /// \eout + /// + /// \param first Iterator to the first element being erased. + /// \param last Iterator to the one-past-the-last element being erased. + /// + /// \returns Iterator to the first element immediately following the last removed element. + iterator erase(const_iterator first, const_iterator last) noexcept + { + return { elements.erase(first.raw_, last.raw_) }; + } + + /// \brief Resizes the array. + /// + /// \detail \godbolt{W5zqx3} + /// + /// \cpp + /// auto arr = toml::array{ 1, 2, 3 }; + /// std::cout << arr << "\n"; + /// + /// arr.resize(6, 42); + /// std::cout << arr << "\n"; + /// + /// arr.resize(2, 0); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, 3 ] + /// [ 1, 2, 3, 42, 42, 42 ] + /// [ 1, 2 ] + /// \eout + /// + /// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML value type + /// (or a type promotable to one). + /// + /// \param new_size The number of elements the array will have after resizing. + /// \param default_init_val The node or value used to initialize new elements if the array needs to grow. + template + void resize(size_t new_size, ElemType&& default_init_val) noexcept + { + static_assert(!is_node_view, + "The default element type argument to toml::array::resize may not be toml::node_view."); + + if (!new_size) + elements.clear(); + else if (new_size < elements.size()) + elements.resize(new_size); + else if (new_size > elements.size()) + insert(cend(), new_size - elements.size(), static_cast(default_init_val)); + } + + /// \brief Shrinks the array to the given size. + /// + /// \detail \godbolt{rxEzK5} + /// + /// \cpp + /// auto arr = toml::array{ 1, 2, 3 }; + /// std::cout << arr << "\n"; + /// + /// arr.truncate(5); // no-op + /// std::cout << arr << "\n"; + /// + /// arr.truncate(1); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, 3 ] + /// [ 1, 2, 3 ] + /// [ 1] + /// \eout + /// + /// \remarks Does nothing if the requested size is larger than or equal to the current size. + void truncate(size_t new_size) + { + if (new_size < elements.size()) + elements.resize(new_size); + } + + /// \brief Appends a new element to the end of the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2 }; + /// arr.push_back(3); + /// arr.push_back(4.0); + /// arr.push_back(toml::array{ 5, "six"sv }); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ] + /// \eout + /// + /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type + /// \param val The node or value being added. + /// + /// \attention No insertion takes place if the input value is an empty toml::node_view. + /// This is the only circumstance in which this can occur. + template + void push_back(ElemType&& val) noexcept + { + emplace_back_if_not_empty_view(static_cast(val)); + } + + /// \brief Emplaces a new element at the end of the array. + /// + /// \detail \cpp + /// auto arr = toml::array{ 1, 2 }; + /// arr.emplace_back(3, "four"sv); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, [ 3, 'four' ] ] + /// \eout + /// + /// \tparam ElemType toml::table, toml::array, or a native TOML value type + /// \tparam Args Value constructor argument types. + /// \param args Arguments to forward to the value's constructor. + /// + /// \returns A reference to the newly-constructed element. + /// + /// \remarks There is no difference between push_back() and emplace_back() + /// For trivial value types (floats, ints, bools). + template + decltype(auto) emplace_back(Args&&... args) noexcept + { + using type = impl::unwrap_node; + static_assert((impl::is_native || impl::is_one_of)&&!impl::is_cvref, + "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + auto nde = new impl::wrap_node{ static_cast(args)... }; + elements.emplace_back(nde); + return *nde; + } + + /// \brief Removes the last element from the array. + void pop_back() noexcept + { + elements.pop_back(); + } + + /// \brief Gets the element at a specific index. + /// + /// \detail \cpp + /// auto arr = toml::array{ 99, "bottles of beer on the wall" }; + /// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n"; + /// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n"; + /// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n"; + /// if (toml::node* val = arr.get(0)) + /// std::cout << "element [0] is an "sv << val->type() << "\n"; + /// + /// \ecpp + /// + /// \out + /// element [0] exists: true + /// element [1] exists: true + /// element [2] exists: false + /// element [0] is an integer + /// \eout + /// + /// \param index The element's index. + /// + /// \returns A pointer to the element at the specified index if one existed, or nullptr. + TOML_NODISCARD + node* get(size_t index) noexcept; + + /// \brief Gets the element at a specific index (const overload). + /// + /// \param index The element's index. + /// + /// \returns A pointer to the element at the specified index if one existed, or nullptr. + TOML_NODISCARD + const node* get(size_t index) const noexcept; + + /// \brief Gets the element at a specific index if it is a particular type. + /// + /// \detail \cpp + /// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv }; + /// if (toml::value* val = arr.get_as(0)) + /// std::cout << "element [0] is an integer with value "sv << *val << "\n"; + /// + /// \ecpp + /// + /// \out + /// element [0] is an integer with value 42 + /// \eout + /// + /// \tparam ElemType toml::table, toml::array, or a native TOML value type + /// \param index The element's index. + /// + /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr. + template + TOML_NODISCARD + impl::wrap_node* get_as(size_t index) noexcept + { + if (auto val = get(index)) + return val->as(); + return nullptr; + } + + /// \brief Gets the element at a specific index if it is a particular type (const overload). + /// + /// \tparam ElemType toml::table, toml::array, or a native TOML value type + /// \param index The element's index. + /// + /// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr. + template + TOML_NODISCARD + const impl::wrap_node* get_as(size_t index) const noexcept + { + if (auto val = get(index)) + return val->as(); + return nullptr; + } + + /// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself. + /// + /// \detail \cpp + /// + /// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} }; + /// std::cout << arr << "\n"; + /// + /// arr.flatten(); + /// std::cout << arr << "\n"; + /// + /// \ecpp + /// + /// \out + /// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ] + /// [ 1, 2, 3, 4, 5, 6 ] + /// \eout + /// + /// \remarks Arrays inside child tables are not flattened. + /// + /// \returns A reference to the array. + array& flatten() &; + + /// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload). + /// \returns An rvalue reference to the array. + array&& flatten() && + { + return static_cast(this->flatten()); + } + + /// @} + + /// \name Equality + /// @{ + + /// \brief Equality operator. + /// + /// \param lhs The LHS array. + /// \param rhs The RHS array. + /// + /// \returns True if the arrays contained the same elements. + friend bool operator==(const array& lhs, const array& rhs) noexcept; + + /// \brief Inequality operator. + /// + /// \param lhs The LHS array. + /// \param rhs The RHS array. + /// + /// \returns True if the arrays did not contain the same elements. + friend bool operator!=(const array& lhs, const array& rhs) noexcept; + + private: + template + TOML_NODISCARD + static bool container_equality(const array& lhs, const T& rhs) noexcept + { + using element_type = std::remove_const_t; + static_assert(impl::is_native || impl::is_losslessly_convertible_to_native, + "Container element type must be (or be promotable to) one of the TOML value types"); + + if (lhs.size() != rhs.size()) + return false; + if (rhs.size() == 0_sz) + return true; + + size_t i{}; + for (auto& list_elem : rhs) + { + const auto elem = lhs.get_as>(i++); + if (!elem || *elem != list_elem) + return false; + } + + return true; + } + + public: + /// \brief Initializer list equality operator. + template + TOML_NODISCARD + friend bool operator==(const array& lhs, const std::initializer_list& rhs) noexcept + { + return container_equality(lhs, rhs); + } + TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list&, template ); + + /// \brief Vector equality operator. + template + TOML_NODISCARD + friend bool operator==(const array& lhs, const std::vector& rhs) noexcept + { + return container_equality(lhs, rhs); + } + TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector&, template ); + + /// @} + + /// \brief Prints the array out to a stream as formatted TOML. + template + friend std::basic_ostream& operator<<(std::basic_ostream&, const array&); + // implemented in toml_default_formatter.h + }; +} +TOML_NAMESPACE_END; diff --git a/include/toml++/impl/array_impl.h b/include/toml++/impl/array_impl.h new file mode 100644 index 0000000..bfa17ef --- /dev/null +++ b/include/toml++/impl/array_impl.h @@ -0,0 +1,283 @@ +//# This file is a part of toml++ and is subject to the the terms of the MIT license. +//# Copyright (c) Mark Gillard +//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT + +#pragma once +//# {{ +#include "preprocessor.h" +#if !TOML_IMPLEMENTATION + #error This is an implementation-only header. +#endif +//# }} + +#include "array.h" + +/// \cond + +TOML_NAMESPACE_START +{ + TOML_EXTERNAL_LINKAGE + array::array() noexcept + { +#if TOML_LIFETIME_HOOKS + TOML_ARRAY_CREATED; +#endif + } + + TOML_EXTERNAL_LINKAGE + array::array(const array& other) noexcept // + : node(other) + { + elements.reserve(other.elements.size()); + for (const auto& elem : other) + elements.emplace_back(impl::make_node(elem)); + +#if TOML_LIFETIME_HOOKS + TOML_ARRAY_CREATED; +#endif + } + + TOML_EXTERNAL_LINKAGE + array::array(array && other) noexcept // + : node(std::move(other)), + elements{ std::move(other.elements) } + { +#if TOML_LIFETIME_HOOKS + TOML_ARRAY_CREATED; +#endif + } + + TOML_EXTERNAL_LINKAGE + array& array::operator=(const array& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(rhs); + elements.clear(); + elements.reserve(rhs.elements.size()); + for (const auto& elem : rhs) + elements.emplace_back(impl::make_node(elem)); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + array& array::operator=(array&& rhs) noexcept + { + if (&rhs != this) + { + node::operator=(std::move(rhs)); + elements = std::move(rhs.elements); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + void array::preinsertion_resize(size_t idx, size_t count) noexcept + { + TOML_ASSERT(idx <= elements.size()); + TOML_ASSERT(count >= 1_sz); + const auto old_size = elements.size(); + const auto new_size = old_size + count; + const auto inserting_at_end = idx == old_size; + elements.resize(new_size); + if (!inserting_at_end) + { + for (size_t left = old_size, right = new_size - 1_sz; left-- > idx; right--) + elements[right] = std::move(elements[left]); + } + } + + TOML_EXTERNAL_LINKAGE + TOML_ATTR(pure) + const node& array::operator[](size_t index) const noexcept + { + return *elements[index]; + } + + TOML_EXTERNAL_LINKAGE + TOML_ATTR(pure) + node& array::operator[](size_t index) noexcept + { + return *elements[index]; + } + + TOML_EXTERNAL_LINKAGE + bool array::is_homogeneous(node_type ntype) const noexcept + { + if (elements.empty()) + return false; + + if (ntype == node_type::none) + ntype = elements[0]->type(); + + for (const auto& val : elements) + if (val->type() != ntype) + return false; + + return true; + } + + namespace impl + { + template + TOML_INTERNAL_LINKAGE + bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept + { + if (elements.empty()) + { + first_nonmatch = {}; + return false; + } + if (ntype == node_type::none) + ntype = elements[0]->type(); + for (const auto& val : elements) + { + if (val->type() != ntype) + { + first_nonmatch = val.get(); + return false; + } + } + return true; + } + } + + TOML_EXTERNAL_LINKAGE + bool array::is_homogeneous(node_type ntype, toml::node * &first_nonmatch) noexcept + { + return impl::array_is_homogeneous(elements, ntype, first_nonmatch); + } + + TOML_EXTERNAL_LINKAGE + bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept + { + return impl::array_is_homogeneous(elements, ntype, first_nonmatch); + } + + TOML_EXTERNAL_LINKAGE + TOML_ATTR(pure) + node* array::get(size_t index) noexcept + { + return index < elements.size() ? elements[index].get() : nullptr; + } + + TOML_EXTERNAL_LINKAGE + TOML_ATTR(pure) + const node* array::get(size_t index) const noexcept + { + return index < elements.size() ? elements[index].get() : nullptr; + } + + TOML_EXTERNAL_LINKAGE + bool operator==(const array& lhs, const array& rhs) noexcept + { + if (&lhs == &rhs) + return true; + if (lhs.elements.size() != rhs.elements.size()) + return false; + for (size_t i = 0, e = lhs.elements.size(); i < e; i++) + { + const auto lhs_type = lhs.elements[i]->type(); + const node& rhs_ = *rhs.elements[i]; + const auto rhs_type = rhs_.type(); + if (lhs_type != rhs_type) + return false; + + const bool equal = lhs.elements[i]->visit( + [&](const auto& lhs_) noexcept + { return lhs_ == *reinterpret_cast*>(&rhs_); }); + if (!equal) + return false; + } + return true; + } + + TOML_EXTERNAL_LINKAGE + bool operator!=(const array& lhs, const array& rhs) noexcept + { + return !(lhs == rhs); + } + + TOML_EXTERNAL_LINKAGE + size_t array::total_leaf_count() const noexcept + { + size_t leaves{}; + for (size_t i = 0, e = elements.size(); i < e; i++) + { + auto arr = elements[i]->as_array(); + leaves += arr ? arr->total_leaf_count() : 1_sz; + } + return leaves; + } + + TOML_EXTERNAL_LINKAGE + void array::flatten_child(array && child, size_t & dest_index) noexcept + { + for (size_t i = 0, e = child.size(); i < e; i++) + { + auto type = child.elements[i]->type(); + if (type == node_type::array) + { + array& arr = *reinterpret_cast(child.elements[i].get()); + if (!arr.empty()) + flatten_child(std::move(arr), dest_index); + } + else + elements[dest_index++] = std::move(child.elements[i]); + } + } + + TOML_EXTERNAL_LINKAGE + array& array::flatten()& + { + if (elements.empty()) + return *this; + + bool requires_flattening = false; + size_t size_after_flattening = elements.size(); + for (size_t i = elements.size(); i-- > 0_sz;) + { + auto arr = elements[i]->as_array(); + if (!arr) + continue; + size_after_flattening--; // discount the array itself + const auto leaf_count = arr->total_leaf_count(); + if (leaf_count > 0_sz) + { + requires_flattening = true; + size_after_flattening += leaf_count; + } + else + elements.erase(elements.cbegin() + static_cast(i)); + } + + if (!requires_flattening) + return *this; + + elements.reserve(size_after_flattening); + + size_t i = 0; + while (i < elements.size()) + { + auto arr = elements[i]->as_array(); + if (!arr) + { + i++; + continue; + } + + std::unique_ptr arr_storage = std::move(elements[i]); + const auto leaf_count = arr->total_leaf_count(); + if (leaf_count > 1_sz) + preinsertion_resize(i + 1_sz, leaf_count - 1_sz); + flatten_child(std::move(*arr), i); // increments i + } + + return *this; + } +} +TOML_NAMESPACE_END; + +/// \endcond diff --git a/include/toml++/toml_common.h b/include/toml++/impl/common.h similarity index 59% rename from include/toml++/toml_common.h rename to include/toml++/impl/common.h index 4050881..e33c9c4 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/impl/common.h @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT #pragma once -#include "toml_preprocessor.h" +#include "preprocessor.h" //#==================================================================================================================== //# INCLUDES @@ -16,6 +16,7 @@ TOML_DISABLE_WARNINGS; #include #include #include +#include #include #include #include @@ -28,16 +29,29 @@ TOML_DISABLE_WARNINGS; #if !TOML_HAS_CUSTOM_OPTIONAL_TYPE #include #endif +#if TOML_EXCEPTIONS + #include +#endif +#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV + #include +#endif +#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV + #include +#endif +#if !TOML_INT_CHARCONV + #include +#endif TOML_ENABLE_WARNINGS; #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 - #define TOML_LAUNDER(x) std::launder(x) + #define TOML_LAUNDER(x) std::launder(x) #else - #define TOML_LAUNDER(x) x + #define TOML_LAUNDER(x) x #endif -#if defined(DOXYGEN) || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 \ - && defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201907) +#if defined(DOXYGEN) \ + || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \ + && __cpp_lib_char8_t >= 201907) #define TOML_HAS_CHAR8 1 #else #define TOML_HAS_CHAR8 0 @@ -49,12 +63,13 @@ TOML_ENABLE_WARNINGS; /// \cond #ifndef TOML_DISABLE_ENVIRONMENT_CHECKS -#define TOML_ENV_MESSAGE \ - "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ - "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ - "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ - "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ - "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. Thanks!" + #define TOML_ENV_MESSAGE \ + "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ + "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ + "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ + "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ + "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \ + "Thanks!" static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE); static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE); @@ -64,7 +79,7 @@ static_assert(std::numeric_limits::is_iec559, TOML_ENV_MESSAGE); static_assert(std::numeric_limits::digits == 53, TOML_ENV_MESSAGE); static_assert(std::numeric_limits::digits10 == 15, TOML_ENV_MESSAGE); -#undef TOML_ENV_MESSAGE + #undef TOML_ENV_MESSAGE #endif // !TOML_DISABLE_ENVIRONMENT_CHECKS /// \endcond @@ -97,7 +112,7 @@ namespace toml // non-abi namespace; this is not an error // legacy typedefs using string_char = char; - using string = std::string; + using string = std::string; using string_view = std::string_view; } @@ -115,39 +130,61 @@ TOML_NAMESPACE_START // abi namespace class array; class table; - template class node_view; - template class value; - template class default_formatter; - template class json_formatter; + template + class node_view; + template + class value; + template + class default_formatter; + template + class json_formatter; - [[nodiscard]] TOML_API bool operator == (const array& lhs, const array& rhs) noexcept; - [[nodiscard]] TOML_API bool operator != (const array& lhs, const array& rhs) noexcept; - [[nodiscard]] TOML_API bool operator == (const table& lhs, const table& rhs) noexcept; - [[nodiscard]] TOML_API bool operator != (const table& lhs, const table& rhs) noexcept; + TOML_NODISCARD + TOML_API + bool operator==(const array& lhs, const array& rhs) noexcept; + + TOML_NODISCARD + TOML_API + bool operator!=(const array& lhs, const array& rhs) noexcept; + + TOML_NODISCARD + TOML_API + bool operator==(const table& lhs, const table& rhs) noexcept; + + TOML_NODISCARD + TOML_API + bool operator!=(const table& lhs, const table& rhs) noexcept; template - std::basic_ostream& operator << (std::basic_ostream&, const array&); + std::basic_ostream& operator<<(std::basic_ostream&, const array&); + template - std::basic_ostream& operator << (std::basic_ostream&, const value&); + std::basic_ostream& operator<<(std::basic_ostream&, const value&); + template - std::basic_ostream& operator << (std::basic_ostream&, const table&); + std::basic_ostream& operator<<(std::basic_ostream&, const table&); + template - std::basic_ostream& operator << (std::basic_ostream&, default_formatter&); + std::basic_ostream& operator<<(std::basic_ostream&, default_formatter&); + template - std::basic_ostream& operator << (std::basic_ostream&, default_formatter&&); + std::basic_ostream& operator<<(std::basic_ostream&, default_formatter&&); + template - std::basic_ostream& operator << (std::basic_ostream&, json_formatter&); + std::basic_ostream& operator<<(std::basic_ostream&, json_formatter&); + template - std::basic_ostream& operator << (std::basic_ostream&, json_formatter&&); + std::basic_ostream& operator<<(std::basic_ostream&, json_formatter&&); + template - inline std::basic_ostream& operator << (std::basic_ostream&, const node_view&); + inline std::basic_ostream& operator<<(std::basic_ostream&, const node_view&); TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); - #if TOML_EXCEPTIONS +#if TOML_EXCEPTIONS using parse_result = table; - #else +#else class parse_result; - #endif // TOML_EXCEPTIONS +#endif TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS namespace impl @@ -165,38 +202,42 @@ TOML_NAMESPACE_START // abi namespace inline constexpr bool is_cvref = std::is_reference_v || std::is_const_v || std::is_volatile_v; template - inline constexpr bool is_wide_string = is_one_of< - std::decay_t, - const wchar_t*, - wchar_t*, - std::wstring_view, - std::wstring - >; + inline constexpr bool is_wide_string = + is_one_of, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>; template inline constexpr bool dependent_false = false; - #if TOML_WINDOWS_COMPAT - [[nodiscard]] TOML_API std::string narrow(std::wstring_view) noexcept; - [[nodiscard]] TOML_API std::wstring widen(std::string_view) noexcept; - #if TOML_HAS_CHAR8 - [[nodiscard]] TOML_API std::wstring widen(std::u8string_view) noexcept; - #endif - #endif // TOML_WINDOWS_COMPAT +#if TOML_WINDOWS_COMPAT + + TOML_NODISCARD + TOML_API + std::string narrow(std::wstring_view) noexcept; + + TOML_NODISCARD + TOML_API + std::wstring widen(std::string_view) noexcept; + + #if TOML_HAS_CHAR8 + TOML_NODISCARD + TOML_API + std::wstring widen(std::u8string_view) noexcept; + #endif +#endif // TOML_WINDOWS_COMPAT TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); class parser; TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS - #if TOML_ABI_NAMESPACES - #if TOML_EXCEPTIONS - #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::ex::parser - #else - #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::noex::parser - #endif - #else - #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser - #endif +#if TOML_ABI_NAMESPACES + #if TOML_EXCEPTIONS + #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::ex::parser + #else + #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::noex::parser + #endif +#else + #define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser +#endif } } TOML_NAMESPACE_END; @@ -208,15 +249,17 @@ TOML_NAMESPACE_END; //#==================================================================================================================== /// \brief The root namespace for all toml++ functions and types. -namespace toml { } +namespace toml +{ +} TOML_NAMESPACE_START // abi namespace { /// \brief Convenience literal operators for working with toml++. - /// + /// /// \detail This namespace exists so you can safely hoist the toml++ literal operators into another scope /// without dragging in everything from the toml namespace: \cpp - /// + /// /// #include /// using namespace toml::literals; /// @@ -230,33 +273,35 @@ TOML_NAMESPACE_START // abi namespace /// } /// \ecpp /// - inline namespace literals {} + inline namespace literals + { + } - #if TOML_HAS_CUSTOM_OPTIONAL_TYPE +#if TOML_HAS_CUSTOM_OPTIONAL_TYPE template using optional = TOML_OPTIONAL_TYPE; - #else +#else /// \brief The 'optional' type used throughout the library. - /// + /// /// \remarks By default this will be an alias for std::optional, but you can change the optional type /// used by the library by defining #TOML_OPTIONAL_TYPE. template using optional = std::optional; - #endif +#endif /// \brief TOML node type identifiers. enum class node_type : uint8_t { - none, ///< Not-a-node. - table, ///< The node is a toml::table. - array, ///< The node is a toml::array. - string, ///< The node is a toml::value. - integer, ///< The node is a toml::value. - floating_point, ///< The node is a toml::value. - boolean, ///< The node is a toml::value. - date, ///< The node is a toml::value. - time, ///< The node is a toml::value