diff --git a/README.md b/README.md index 766c01d..61cd7be 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ toml++. | `TOML_ASSERT(expr)` | function macro | `assert(expr)`
(or undefined) | Sets the assert function used by the library. | | `TOML_CHAR_8_STRINGS` | boolean | `0` | Uses C++20 [char8_t]-based strings as the toml string data type. | | `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. | +| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). | | `TOML_UNDEF_MACROS` | boolean | `1` | `#undefs` the library's internal macros at the end of the header. | | `TOML_UNRELEASED_FEATURES` | boolean | `1` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. | diff --git a/examples/example.toml b/examples/example.toml index c7ad462..e9102d1 100644 --- a/examples/example.toml +++ b/examples/example.toml @@ -10,6 +10,7 @@ int2 = 9223372036854775807 flt1 = 0.00000000001 flt2 = 1e-11 flt3 = 11.0 +flt4 = +1.0 # hexadecimal with prefix `0x` hex1 = 0xDEADBEEF diff --git a/examples/toml_to_json_transcoder.cpp b/examples/toml_to_json_transcoder.cpp index 254fcf8..5a17cc2 100644 --- a/examples/toml_to_json_transcoder.cpp +++ b/examples/toml_to_json_transcoder.cpp @@ -27,7 +27,7 @@ int main(int argc, char** argv) try { const auto table = toml::parse(file, std::move(path)); - std::cout << table << std::endl; + std::cout << toml::json_formatter{ table } << std::endl; } catch (const toml::parse_error & err) { @@ -49,7 +49,7 @@ int main(int argc, char** argv) const auto table = toml::parse(std::cin); std::cout << toml::json_formatter{ table } << std::endl; } - catch (const toml::parse_error & err) + catch (const toml::parse_error& err) { std::cerr << "Error parsing stdin:\n"sv << err.what() diff --git a/include/toml++/toml.h b/include/toml++/toml.h index 4351f2e..70d9323 100644 --- a/include/toml++/toml.h +++ b/include/toml++/toml.h @@ -5,6 +5,7 @@ //# is used as the source for generate_single_header.py. #include "toml_common.h" +#include "toml_print_to_stream.h" #include "toml_node.h" #include "toml_table.h" #include "toml_array.h" @@ -20,10 +21,10 @@ #if TOML_UNDEF_MACROS #undef TOML_EXCEPTIONS #undef TOML_USE_STREAMS_FOR_FLOATS + #undef TOML_GCC_ATTR #undef TOML_PUSH_WARNINGS - #undef TOML_DISABLE_SWITCH_WARNING - #undef TOML_DISABLE_FIELD_INIT_WARNING - #undef TOML_DISABLE_VAR_INIT_WARNING + #undef TOML_DISABLE_SWITCH_WARNINGS + #undef TOML_DISABLE_INIT_WARNINGS #undef TOML_DISABLE_ALL_WARNINGS #undef TOML_POP_WARNINGS #undef TOML_ALWAYS_INLINE @@ -31,6 +32,7 @@ #undef TOML_UNREACHABLE #undef TOML_INTERFACE #undef TOML_EMPTY_BASES + #undef TOML_CPP_VERSION #undef TOML_CPP #undef TOML_CONDITIONAL_NOEXCEPT #undef TOML_MAY_THROW diff --git a/include/toml++/toml_array.h b/include/toml++/toml_array.h index c82e4ca..f37618a 100644 --- a/include/toml++/toml_array.h +++ b/include/toml++/toml_array.h @@ -1,6 +1,82 @@ #pragma once #include "toml_node.h" +namespace toml::impl +{ + template + class array_iterator final + { + private: + friend class toml::array; + + using raw_iterator = std::conditional_t< + is_const, + std::vector>::const_iterator, + std::vector>::iterator + >; + + mutable raw_iterator raw_; + + array_iterator(const raw_iterator& raw) noexcept + : raw_{ raw } + {} + + array_iterator(raw_iterator&& raw) noexcept + : raw_{ std::move(raw) } + {} + + public: + + array_iterator() noexcept = default; + + using reference = std::conditional_t; + + array_iterator& operator++() noexcept // ++pre + { + ++raw_; + return *this; + } + + array_iterator operator++(int) noexcept // post++ + { + array_iterator out{ raw_ }; + ++raw_; + return out; + } + + array_iterator& operator--() noexcept // --pre + { + --raw_; + return *this; + } + + array_iterator operator--(int) noexcept // post-- + { + array_iterator out{ raw_ }; + --raw_; + return out; + } + + [[nodiscard]] + reference operator* () const noexcept + { + return *raw_->get(); + } + + [[nodiscard]] + friend constexpr bool operator == (const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ == rhs.raw_; + } + + [[nodiscard]] + friend constexpr bool operator != (const array_iterator& lhs, const array_iterator& rhs) noexcept + { + return lhs.raw_ != rhs.raw_; + } + }; +} + namespace toml { class array final @@ -12,6 +88,9 @@ namespace toml public: + using iterator = impl::array_iterator; + using const_iterator = impl::array_iterator; + TOML_NODISCARD_CTOR array() noexcept = default; @@ -27,8 +106,12 @@ namespace toml values = std::move(rhs.values); return *this; } + + [[nodiscard]] node_type type() const noexcept override { return node_type::array; } + [[nodiscard]] bool is_table() const noexcept override { return false; } [[nodiscard]] bool is_array() const noexcept override { return true; } + [[nodiscard]] bool is_value() const noexcept override { return false; } [[nodiscard]] bool is_array_of_tables() const noexcept override { @@ -42,40 +125,56 @@ namespace toml return true; } + template [[nodiscard]] bool is_homogeneous() const noexcept { - if (values.size() <= 1_sz) - return true; + if (values.empty()) + return false; - const auto type = values[0]->type(); - for (size_t i = 1; i < values.size(); i++) - if (values[i]->type() != type) - return false; + if constexpr (std::is_same_v) + { + const auto type = values[0]->type(); + for (size_t i = 1; i < values.size(); i++) + if (values[i]->type() != type) + return false; + } + else + { + for (auto& v : values) + if (!v->is()) + return false; + } return true; } [[nodiscard]] array* as_array() noexcept override { return this; } [[nodiscard]] const array* as_array() const noexcept override { return this; } - [[nodiscard]] node_type type() const noexcept override { return node_type::array; } - [[nodiscard]] bool empty() const noexcept { return values.empty(); } - [[nodiscard]] size_t size() const noexcept { return values.size(); } - [[nodiscard]] node* get(size_t index) noexcept { return values[index].get(); } - [[nodiscard]] const node* get(size_t index) const noexcept { return values[index].get(); } + [[nodiscard]] node& operator[] (size_t index) & noexcept { return *values[index].get(); } + [[nodiscard]] node&& operator[] (size_t index) && noexcept { return std::move(*values[index].get()); } + [[nodiscard]] const node& operator[] (size_t index) const& noexcept { return *values[index].get(); } template [[nodiscard]] node_of* get_as(size_t index) noexcept { - return get(index)->as(); + return values[index]->as(); } template [[nodiscard]] const node_of* get_as(size_t index) const noexcept { - return get(index)->as(); + return values[index]->as(); } + + [[nodiscard]] iterator begin() noexcept { return { values.begin() }; } + [[nodiscard]] const_iterator begin() const noexcept { return { values.begin() }; } + [[nodiscard]] const_iterator cbegin() const noexcept { return { values.cbegin() }; } + + [[nodiscard]] iterator end() noexcept { return { values.end() }; } + [[nodiscard]] const_iterator end() const noexcept { return { values.end() }; } + [[nodiscard]] const_iterator cend() const noexcept { return { values.cend() }; } }; } diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index ed44f40..94f4341 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -16,6 +16,10 @@ #define TOML_UNRELEASED_FEATURES 1 #endif +#ifndef TOML_LARGE_FILES + #define TOML_LARGE_FILES 0 +#endif + #ifndef TOML_ASSERT #ifdef assert #define TOML_ASSERT(expr) assert(expr) @@ -34,6 +38,12 @@ #error toml++ is a C++ library. #endif +#if defined(__clang__) or defined(__GNUC__) + #define TOML_GCC_ATTR(attr) __attribute__((attr)) +#else + #define TOML_GCC_ATTR(attr) +#endif + #ifdef __clang__ #ifndef __cpp_exceptions @@ -41,11 +51,11 @@ #endif #define TOML_PUSH_WARNINGS _Pragma("clang diagnostic push") - #define TOML_DISABLE_SWITCH_WARNING _Pragma("clang diagnostic ignored \"-Wswitch\"") - #define TOML_DISABLE_FIELD_INIT_WARNING _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") + #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("clang diagnostic ignored \"-Wswitch\"") + #define TOML_DISABLE_INIT_WARNINGS _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") #define TOML_DISABLE_ALL_WARNINGS _Pragma("clang diagnostic ignored \"-Weverything\"") #define TOML_POP_WARNINGS _Pragma("clang diagnostic pop") - #define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline + #define TOML_ALWAYS_INLINE TOML_GCC_ATTR(__always_inline__) inline #define TOML_ASSUME(cond) __builtin_assume(cond) #define TOML_UNREACHABLE __builtin_unreachable() @@ -70,7 +80,7 @@ #define TOML_CPP_VERSION _MSVC_LANG #define TOML_PUSH_WARNINGS __pragma(warning(push)) - #define TOML_DISABLE_SWITCH_WARNING __pragma(warning(disable: 4063)) + #define TOML_DISABLE_SWITCH_WARNINGS __pragma(warning(disable: 4063)) #define TOML_DISABLE_ALL_WARNINGS __pragma(warning(pop)) \ __pragma(warning(push, 0)) #define TOML_POP_WARNINGS __pragma(warning(pop)) @@ -87,16 +97,16 @@ #endif #define TOML_PUSH_WARNINGS _Pragma("GCC diagnostic push") - #define TOML_DISABLE_SWITCH_WARNING _Pragma("GCC diagnostic ignored \"-Wswitch\"") - #define TOML_DISABLE_FIELD_INIT_WARNING _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") - #define TOML_DISABLE_VAR_INIT_WARNING _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") - #define TOML_DISABLE_ALL_WARNINGS _Pragma("GCC diagnostic ignored \"-Wall\"") \ - _Pragma("GCC diagnostic ignored \"-Wextra\"") \ - _Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \ + #define TOML_DISABLE_SWITCH_WARNINGS _Pragma("GCC diagnostic ignored \"-Wswitch\"") + #define TOML_DISABLE_INIT_WARNINGS _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \ + _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \ + _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") + #define TOML_DISABLE_ALL_WARNINGS _Pragma("GCC diagnostic ignored \"-Wall\"") \ + _Pragma("GCC diagnostic ignored \"-Wextra\"") \ + _Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") - #define TOML_POP_WARNINGS _Pragma("GCC diagnostic pop") - #define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline + #define TOML_ALWAYS_INLINE TOML_GCC_ATTR(__always_inline__) inline #define TOML_UNREACHABLE __builtin_unreachable() //floating-point from_chars and to_chars are not implemented in any version of gcc as of 1/1/2020 @@ -109,7 +119,11 @@ #ifndef TOML_CPP_VERSION #define TOML_CPP_VERSION __cplusplus #endif -#if TOML_CPP_VERSION >= 202600L +#if TOML_CPP_VERSION < 201103L + #error toml++ requires C++17 or higher. For a TOML parser supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml +#elif TOML_CPP_VERSION < 201703L + #error toml++ requires C++17 or higher. For a TOML parser supporting C++11 see https://github.com/skystrife/cpptoml +#elif TOML_CPP_VERSION >= 202600L #define TOML_CPP 26 #elif TOML_CPP_VERSION >= 202300L #define TOML_CPP 23 @@ -117,12 +131,7 @@ #define TOML_CPP 20 #elif TOML_CPP_VERSION >= 201703L #define TOML_CPP 17 -#elif TOML_CPP_VERSION >= 201100L - #error toml++ requires C++17 or higher. For a TOML parser supporting C++11 see https://github.com/skystrife/cpptoml -#else - #error toml++ requires C++17 or higher. For a TOML parser supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml #endif -#undef TOML_CPP_VERSION #ifndef TOML_EXCEPTIONS #define TOML_EXCEPTIONS 1 @@ -135,11 +144,8 @@ #define TOML_MAY_THROW noexcept #endif -#ifndef TOML_DISABLE_FIELD_INIT_WARNING - #define TOML_DISABLE_FIELD_INIT_WARNING -#endif -#ifndef TOML_DISABLE_VAR_INIT_WARNING - #define TOML_DISABLE_VAR_INIT_WARNING +#ifndef TOML_DISABLE_INIT_WARNINGS + #define TOML_DISABLE_INIT_WARNINGS #endif #ifndef TOML_USE_STREAMS_FOR_FLOATS #define TOML_USE_STREAMS_FOR_FLOATS 0 @@ -282,98 +288,6 @@ namespace toml } } - struct date final - { - uint16_t year; - uint8_t month; - uint8_t day; - - [[nodiscard]] - friend constexpr bool operator == (date lhs, date rhs) noexcept - { - return lhs.year == rhs.year - && lhs.month == rhs.month - && lhs.day == rhs.day; - } - - [[nodiscard]] - friend constexpr bool operator != (date lhs, date rhs) noexcept - { - return lhs.year != rhs.year - || lhs.month != rhs.month - || lhs.day != rhs.day; - } - }; - - struct time final - { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint32_t nanosecond; - - [[nodiscard]] - friend constexpr bool operator == (time lhs, time rhs) noexcept - { - return lhs.hour == rhs.hour - && lhs.minute == rhs.minute - && lhs.second == rhs.second - && lhs.nanosecond == rhs.nanosecond; - } - - [[nodiscard]] - friend constexpr bool operator != (time lhs, time rhs) noexcept - { - return lhs.hour != rhs.hour - || lhs.minute != rhs.minute - || lhs.second != rhs.second - || lhs.nanosecond != rhs.nanosecond; - } - }; - - struct time_offset final - { - int8_t hours; - int8_t minutes; - - [[nodiscard]] - friend constexpr bool operator == (time_offset lhs, time_offset rhs) noexcept - { - return lhs.hours == rhs.hours - && lhs.minutes == rhs.minutes; - } - - [[nodiscard]] - friend constexpr bool operator != (time_offset lhs, time_offset rhs) noexcept - { - return lhs.hours != rhs.hours - || lhs.minutes != rhs.minutes; - } - }; - - struct date_time final - { - toml::date date; - toml::time time; - std::optional time_offset; - - [[nodiscard]] - friend constexpr bool operator == (const date_time& lhs, const date_time& rhs) noexcept - { - return lhs.date == rhs.date - && lhs.time == rhs.time - && lhs.time_offset == rhs.time_offset; - } - - [[nodiscard]] - friend constexpr bool operator != (const date_time& lhs, const date_time& rhs) noexcept - { - return lhs.date != rhs.date - || lhs.time != rhs.time - || lhs.time_offset != rhs.time_offset; - } - }; - #if TOML_CHAR_8_STRINGS using string_char = char8_t; @@ -392,125 +306,43 @@ namespace toml using string_map = std::map>; //heterogeneous lookup class node; - template - class node_view; - template - class value; + template class node_view; + template class value; class array; class table; - class default_formatter; - class json_formatter; - - namespace impl + enum class node_type : uint8_t { - #if defined(__cpp_lib_remove_cvref) || (defined(_MSC_VER) && defined(_HAS_CXX20)) + table, + array, + string, + integer, + floating_point, + boolean, + date, + time, + date_time + }; - template - using remove_cvref_t = std::remove_cvref_t; + #if TOML_LARGE_FILES - #else + using source_index = uint32_t; - template - using remove_cvref_t = std::remove_cv_t>; + #else - #endif + using source_index = uint16_t; - template - struct is_generic_invocable - { - template - static constexpr auto test(U&&) -> decltype(std::declval()(std::declval()), std::true_type{}); - static constexpr std::false_type test(...); + #endif - struct tester {}; - static constexpr auto value = decltype(test(tester{}))::value; - }; - - - template - inline constexpr bool is_generic_invocable_v = is_generic_invocable::value; - - class parser; - class formatter; - - template - inline constexpr bool is_value = - std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v; - - template - inline constexpr bool is_value_or_promotable = - is_value - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v; - - template - inline constexpr bool is_value_or_node = - is_value - || std::is_same_v - || std::is_same_v; - - template struct node_wrapper { using type = T; }; - template <> struct node_wrapper { using type = value; }; - template <> struct node_wrapper { using type = value; }; - template <> struct node_wrapper { using type = value; }; - template <> struct node_wrapper { using type = value; }; - template <> struct node_wrapper { using type = value; }; - template <> struct node_wrapper