From f1c96281a9b9d0bc02a7680ffa49557446c44298 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 18 Nov 2024 22:53:55 +0100 Subject: [PATCH] update toml11. fixes bug with FPS settings corrupting config file --- cmake/toml11Config.cmake__ | 2 + res/icon/melon_192x192.png | Bin 0 -> 100714 bytes res/icon/splash.xcf | Bin 0 -> 246892 bytes src/frontend/qt_sdl/Config.cpp | 2 +- src/frontend/qt_sdl/Config.h | 2 +- src/frontend/qt_sdl/toml/toml.hpp | 94 +- src/frontend/qt_sdl/toml/toml/color.hpp | 64 - src/frontend/qt_sdl/toml/toml/combinator.hpp | 306 -- src/frontend/qt_sdl/toml/toml/datetime.hpp | 631 --- src/frontend/qt_sdl/toml/toml/exception.hpp | 65 - src/frontend/qt_sdl/toml/toml/get.hpp | 1119 ----- src/frontend/qt_sdl/toml/toml/lexer.hpp | 293 -- src/frontend/qt_sdl/toml/toml/literal.hpp | 113 - src/frontend/qt_sdl/toml/toml/parser.hpp | 2416 ----------- src/frontend/qt_sdl/toml/toml/region.hpp | 417 -- src/frontend/qt_sdl/toml/toml/result.hpp | 717 --- src/frontend/qt_sdl/toml/toml/serializer.hpp | 922 ---- .../qt_sdl/toml/toml/source_location.hpp | 233 - src/frontend/qt_sdl/toml/toml/storage.hpp | 43 - src/frontend/qt_sdl/toml/toml/string.hpp | 228 - src/frontend/qt_sdl/toml/toml/traits.hpp | 328 -- src/frontend/qt_sdl/toml/toml/types.hpp | 173 - src/frontend/qt_sdl/toml/toml/utility.hpp | 150 - src/frontend/qt_sdl/toml/toml/value.hpp | 2035 --------- src/frontend/qt_sdl/toml/toml/version.hpp | 42 - src/frontend/qt_sdl/toml/toml11/color.hpp | 10 + src/frontend/qt_sdl/toml/toml11/comments.hpp | 10 + src/frontend/qt_sdl/toml/toml11/compat.hpp | 751 ++++ src/frontend/qt_sdl/toml/toml11/context.hpp | 68 + .../macros.hpp => toml11/conversion.hpp} | 138 +- src/frontend/qt_sdl/toml/toml11/datetime.hpp | 10 + .../qt_sdl/toml/toml11/error_info.hpp | 10 + src/frontend/qt_sdl/toml/toml11/exception.hpp | 17 + src/frontend/qt_sdl/toml/toml11/find.hpp | 377 ++ src/frontend/qt_sdl/toml/toml11/format.hpp | 10 + .../qt_sdl/toml/{toml => toml11}/from.hpp | 2 - .../qt_sdl/toml/toml11/fwd/color_fwd.hpp | 88 + .../fwd/comments_fwd.hpp} | 115 +- .../qt_sdl/toml/toml11/fwd/datetime_fwd.hpp | 261 ++ .../qt_sdl/toml/toml11/fwd/error_info_fwd.hpp | 97 + .../qt_sdl/toml/toml11/fwd/format_fwd.hpp | 250 ++ .../qt_sdl/toml/toml11/fwd/literal_fwd.hpp | 33 + .../qt_sdl/toml/toml11/fwd/location_fwd.hpp | 145 + .../qt_sdl/toml/toml11/fwd/region_fwd.hpp | 104 + .../qt_sdl/toml/toml11/fwd/scanner_fwd.hpp | 391 ++ .../toml/toml11/fwd/source_location_fwd.hpp | 115 + .../qt_sdl/toml/toml11/fwd/syntax_fwd.hpp | 357 ++ .../qt_sdl/toml/toml11/fwd/value_t_fwd.hpp | 117 + src/frontend/qt_sdl/toml/toml11/get.hpp | 632 +++ .../qt_sdl/toml/toml11/impl/color_impl.hpp | 76 + .../qt_sdl/toml/toml11/impl/comments_impl.hpp | 46 + .../qt_sdl/toml/toml11/impl/datetime_impl.hpp | 518 +++ .../toml/toml11/impl/error_info_impl.hpp | 75 + .../qt_sdl/toml/toml11/impl/format_impl.hpp | 297 ++ .../qt_sdl/toml/toml11/impl/literal_impl.hpp | 174 + .../qt_sdl/toml/toml11/impl/location_impl.hpp | 226 + .../qt_sdl/toml/toml11/impl/region_impl.hpp | 188 + .../qt_sdl/toml/toml11/impl/scanner_impl.hpp | 473 ++ .../toml/toml11/impl/source_location_impl.hpp | 197 + .../qt_sdl/toml/toml11/impl/syntax_impl.hpp | 732 ++++ .../qt_sdl/toml/toml11/impl/value_t_impl.hpp | 40 + .../qt_sdl/toml/{toml => toml11}/into.hpp | 2 - src/frontend/qt_sdl/toml/toml11/literal.hpp | 10 + src/frontend/qt_sdl/toml/toml11/location.hpp | 10 + .../qt_sdl/toml/toml11/ordered_map.hpp | 265 ++ src/frontend/qt_sdl/toml/toml11/parser.hpp | 3829 +++++++++++++++++ src/frontend/qt_sdl/toml/toml11/region.hpp | 10 + src/frontend/qt_sdl/toml/toml11/result.hpp | 486 +++ src/frontend/qt_sdl/toml/toml11/scanner.hpp | 10 + .../qt_sdl/toml/toml11/serializer.hpp | 1275 ++++++ src/frontend/qt_sdl/toml/toml11/skip.hpp | 392 ++ .../qt_sdl/toml/toml11/source_location.hpp | 10 + src/frontend/qt_sdl/toml/toml11/spec.hpp | 121 + src/frontend/qt_sdl/toml/toml11/storage.hpp | 49 + src/frontend/qt_sdl/toml/toml11/syntax.hpp | 10 + src/frontend/qt_sdl/toml/toml11/traits.hpp | 240 ++ src/frontend/qt_sdl/toml/toml11/types.hpp | 397 ++ src/frontend/qt_sdl/toml/toml11/utility.hpp | 170 + src/frontend/qt_sdl/toml/toml11/value.hpp | 2257 ++++++++++ src/frontend/qt_sdl/toml/toml11/value_t.hpp | 10 + src/frontend/qt_sdl/toml/toml11/version.hpp | 121 + src/frontend/qt_sdl/toml/toml11/visit.hpp | 81 + src/frontend/qt_sdl/toml/toml_fwd.hpp | 88 + 83 files changed, 16956 insertions(+), 10432 deletions(-) create mode 100644 cmake/toml11Config.cmake__ create mode 100644 res/icon/melon_192x192.png create mode 100644 res/icon/splash.xcf delete mode 100644 src/frontend/qt_sdl/toml/toml/color.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/combinator.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/datetime.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/exception.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/get.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/lexer.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/literal.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/parser.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/region.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/result.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/serializer.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/source_location.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/storage.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/string.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/traits.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/types.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/utility.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/value.hpp delete mode 100644 src/frontend/qt_sdl/toml/toml/version.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/color.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/comments.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/compat.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/context.hpp rename src/frontend/qt_sdl/toml/{toml/macros.hpp => toml11/conversion.hpp} (77%) create mode 100644 src/frontend/qt_sdl/toml/toml11/datetime.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/error_info.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/exception.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/find.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/format.hpp rename src/frontend/qt_sdl/toml/{toml => toml11}/from.hpp (78%) create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/color_fwd.hpp rename src/frontend/qt_sdl/toml/{toml/comments.hpp => toml11/fwd/comments_fwd.hpp} (86%) create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/datetime_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/error_info_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/format_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/literal_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/location_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/region_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/scanner_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/source_location_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/syntax_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/fwd/value_t_fwd.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/get.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/color_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/comments_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/datetime_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/error_info_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/format_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/literal_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/location_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/region_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/scanner_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/source_location_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/syntax_impl.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/impl/value_t_impl.hpp rename src/frontend/qt_sdl/toml/{toml => toml11}/into.hpp (79%) create mode 100644 src/frontend/qt_sdl/toml/toml11/literal.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/location.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/ordered_map.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/parser.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/region.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/result.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/scanner.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/serializer.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/skip.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/source_location.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/spec.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/storage.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/syntax.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/traits.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/types.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/utility.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/value.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/value_t.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/version.hpp create mode 100644 src/frontend/qt_sdl/toml/toml11/visit.hpp create mode 100644 src/frontend/qt_sdl/toml/toml_fwd.hpp diff --git a/cmake/toml11Config.cmake__ b/cmake/toml11Config.cmake__ new file mode 100644 index 00000000..edc73f69 --- /dev/null +++ b/cmake/toml11Config.cmake__ @@ -0,0 +1,2 @@ +@PACKAGE_INIT@ +include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake") diff --git a/res/icon/melon_192x192.png b/res/icon/melon_192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d4da5d278a8f6c78495ba1fe01074f2c050543 GIT binary patch literal 100714 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%0DfW}+kqE&hshwtk|CFaoolz3DPSG28d@tL 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[C; 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 literal 0 HcmV?d00001 diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 02be5b65..7d5331fc 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -816,7 +816,7 @@ Table GetLocalTable(int instance) std::string key = "Instance" + std::to_string(instance); toml::value& tbl = RootTable[key]; - if (tbl.is_uninitialized()) + if (tbl.is_empty()) RootTable[key] = RootTable["Instance0"]; return Table(tbl, key); diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h index 9e6d3ea4..39278c36 100644 --- a/src/frontend/qt_sdl/Config.h +++ b/src/frontend/qt_sdl/Config.h @@ -25,7 +25,7 @@ #include #include -#include "toml/toml/value.hpp" +#include "toml/toml11/types.hpp" namespace Config { diff --git a/src/frontend/qt_sdl/toml/toml.hpp b/src/frontend/qt_sdl/toml/toml.hpp index 6b0ca1ed..75cc95be 100644 --- a/src/frontend/qt_sdl/toml/toml.hpp +++ b/src/frontend/qt_sdl/toml/toml.hpp @@ -1,38 +1,62 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2017 Toru Niina - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ +#ifndef TOML11_TOML_HPP +#define TOML11_TOML_HPP -#ifndef TOML_FOR_MODERN_CPP -#define TOML_FOR_MODERN_CPP +// The MIT License (MIT) +// +// Copyright (c) 2017-now Toru Niina +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. -#define TOML11_VERSION_MAJOR 3 -#define TOML11_VERSION_MINOR 7 -#define TOML11_VERSION_PATCH 1 +// IWYU pragma: begin_exports +#include "toml11/color.hpp" +#include "toml11/comments.hpp" +#include "toml11/compat.hpp" +#include "toml11/context.hpp" +#include "toml11/conversion.hpp" +#include "toml11/datetime.hpp" +#include "toml11/error_info.hpp" +#include "toml11/exception.hpp" +#include "toml11/find.hpp" +#include "toml11/format.hpp" +#include "toml11/from.hpp" +#include "toml11/get.hpp" +#include "toml11/into.hpp" +#include "toml11/literal.hpp" +#include "toml11/location.hpp" +#include "toml11/ordered_map.hpp" +#include "toml11/parser.hpp" +#include "toml11/region.hpp" +#include "toml11/result.hpp" +#include "toml11/scanner.hpp" +#include "toml11/serializer.hpp" +#include "toml11/skip.hpp" +#include "toml11/source_location.hpp" +#include "toml11/spec.hpp" +#include "toml11/storage.hpp" +#include "toml11/syntax.hpp" +#include "toml11/traits.hpp" +#include "toml11/types.hpp" +#include "toml11/utility.hpp" +#include "toml11/value.hpp" +#include "toml11/value_t.hpp" +#include "toml11/version.hpp" +#include "toml11/visit.hpp" +// IWYU pragma: end_exports -#include "toml/parser.hpp" -#include "toml/literal.hpp" -#include "toml/serializer.hpp" -#include "toml/get.hpp" -#include "toml/macros.hpp" - -#endif// TOML_FOR_MODERN_CPP +#endif// TOML11_TOML_HPP diff --git a/src/frontend/qt_sdl/toml/toml/color.hpp b/src/frontend/qt_sdl/toml/toml/color.hpp deleted file mode 100644 index 4cb572cb..00000000 --- a/src/frontend/qt_sdl/toml/toml/color.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TOML11_COLOR_HPP -#define TOML11_COLOR_HPP -#include -#include - -#ifdef TOML11_COLORIZE_ERROR_MESSAGE -#define TOML11_ERROR_MESSAGE_COLORIZED true -#else -#define TOML11_ERROR_MESSAGE_COLORIZED false -#endif - -namespace toml -{ - -// put ANSI escape sequence to ostream -namespace color_ansi -{ -namespace detail -{ -inline int colorize_index() -{ - static const int index = std::ios_base::xalloc(); - return index; -} -} // detail - -inline std::ostream& colorize(std::ostream& os) -{ - // by default, it is zero. - os.iword(detail::colorize_index()) = 1; - return os; -} -inline std::ostream& nocolorize(std::ostream& os) -{ - os.iword(detail::colorize_index()) = 0; - return os; -} -inline std::ostream& reset (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;} -inline std::ostream& bold (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;} -inline std::ostream& grey (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;} -inline std::ostream& red (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;} -inline std::ostream& green (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;} -inline std::ostream& yellow (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;} -inline std::ostream& blue (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;} -inline std::ostream& magenta(std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;} -inline std::ostream& cyan (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;} -inline std::ostream& white (std::ostream& os) -{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;} -} // color_ansi - -// ANSI escape sequence is the only and default colorization method currently -namespace color = color_ansi; - -} // toml -#endif// TOML11_COLOR_HPP diff --git a/src/frontend/qt_sdl/toml/toml/combinator.hpp b/src/frontend/qt_sdl/toml/toml/combinator.hpp deleted file mode 100644 index 33ecca1e..00000000 --- a/src/frontend/qt_sdl/toml/toml/combinator.hpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_COMBINATOR_HPP -#define TOML11_COMBINATOR_HPP -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "region.hpp" -#include "result.hpp" -#include "traits.hpp" -#include "utility.hpp" - -// they scans characters and returns region if it matches to the condition. -// when they fail, it does not change the location. -// in lexer.hpp, these are used. - -namespace toml -{ -namespace detail -{ - -// to output character as an error message. -inline std::string show_char(const char c) -{ - // It suppresses an error that occurs only in Debug mode of MSVC++ on Windows. - // I'm not completely sure but they check the value of char to be in the - // range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes - // has negative value (if char has sign). So here it re-interprets c as - // unsigned char through pointer. In general, converting pointer to a - // pointer that has different type cause UB, but `(signed|unsigned)?char` - // are one of the exceptions. Converting pointer only to char and std::byte - // (c++17) are valid. - if(std::isgraph(*reinterpret_cast(std::addressof(c)))) - { - return std::string(1, c); - } - else - { - std::array buf; - buf.fill('\0'); - const auto r = std::snprintf( - buf.data(), buf.size(), "0x%02x", static_cast(c) & 0xFF); - (void) r; // Unused variable warning - assert(r == static_cast(buf.size()) - 1); - return std::string(buf.data()); - } -} - -template -struct character -{ - static constexpr char target = C; - - static result - invoke(location& loc) - { - if(loc.iter() == loc.end()) {return none();} - const auto first = loc.iter(); - - const char c = *(loc.iter()); - if(c != target) - { - return none(); - } - loc.advance(); // update location - - return ok(region(loc, first, loc.iter())); - } -}; -template -constexpr char character::target; - -// closed interval [Low, Up]. both Low and Up are included. -template -struct in_range -{ - // assuming ascii part of UTF-8... - static_assert(Low <= Up, "lower bound should be less than upper bound."); - - static constexpr char upper = Up; - static constexpr char lower = Low; - - static result - invoke(location& loc) - { - if(loc.iter() == loc.end()) {return none();} - const auto first = loc.iter(); - - const char c = *(loc.iter()); - if(c < lower || upper < c) - { - return none(); - } - - loc.advance(); - return ok(region(loc, first, loc.iter())); - } -}; -template constexpr char in_range::upper; -template constexpr char in_range::lower; - -// keep iterator if `Combinator` matches. otherwise, increment `iter` by 1 char. -// for detecting invalid characters, like control sequences in toml string. -template -struct exclude -{ - static result - invoke(location& loc) - { - if(loc.iter() == loc.end()) {return none();} - auto first = loc.iter(); - - auto rslt = Combinator::invoke(loc); - if(rslt.is_ok()) - { - loc.reset(first); - return none(); - } - loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but... - return ok(region(loc, first, loc.iter())); - } -}; - -// increment `iter`, if matches. otherwise, just return empty string. -template -struct maybe -{ - static result - invoke(location& loc) - { - const auto rslt = Combinator::invoke(loc); - if(rslt.is_ok()) - { - return rslt; - } - return ok(region(loc)); - } -}; - -template -struct sequence; - -template -struct sequence -{ - static result - invoke(location& loc) - { - const auto first = loc.iter(); - auto rslt = Head::invoke(loc); - if(rslt.is_err()) - { - loc.reset(first); - return none(); - } - return sequence::invoke(loc, std::move(rslt.unwrap()), first); - } - - // called from the above function only, recursively. - template - static result - invoke(location& loc, region reg, Iterator first) - { - const auto rslt = Head::invoke(loc); - if(rslt.is_err()) - { - loc.reset(first); - return none(); - } - reg += rslt.unwrap(); // concat regions - return sequence::invoke(loc, std::move(reg), first); - } -}; - -template -struct sequence -{ - // would be called from sequence::invoke only. - template - static result - invoke(location& loc, region reg, Iterator first) - { - const auto rslt = Head::invoke(loc); - if(rslt.is_err()) - { - loc.reset(first); - return none(); - } - reg += rslt.unwrap(); // concat regions - return ok(reg); - } -}; - -template -struct either; - -template -struct either -{ - static result - invoke(location& loc) - { - const auto rslt = Head::invoke(loc); - if(rslt.is_ok()) {return rslt;} - return either::invoke(loc); - } -}; -template -struct either -{ - static result - invoke(location& loc) - { - return Head::invoke(loc); - } -}; - -template -struct repeat; - -template struct exactly{}; -template struct at_least{}; -struct unlimited{}; - -template -struct repeat> -{ - static result - invoke(location& loc) - { - region retval(loc); - const auto first = loc.iter(); - for(std::size_t i=0; i -struct repeat> -{ - static result - invoke(location& loc) - { - region retval(loc); - - const auto first = loc.iter(); - for(std::size_t i=0; i -struct repeat -{ - static result - invoke(location& loc) - { - region retval(loc); - while(true) - { - auto rslt = T::invoke(loc); - if(rslt.is_err()) - { - return ok(std::move(retval)); - } - retval += rslt.unwrap(); - } - } -}; - -} // detail -} // toml -#endif// TOML11_COMBINATOR_HPP diff --git a/src/frontend/qt_sdl/toml/toml/datetime.hpp b/src/frontend/qt_sdl/toml/toml/datetime.hpp deleted file mode 100644 index 36db1e10..00000000 --- a/src/frontend/qt_sdl/toml/toml/datetime.hpp +++ /dev/null @@ -1,631 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_DATETIME_HPP -#define TOML11_DATETIME_HPP -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace toml -{ - -// To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is -// provided in the absolutely same purpose, but C++11 is actually not compatible -// with C11. We need to dispatch the function depending on the OS. -namespace detail -{ -// TODO: find more sophisticated way to handle this -#if defined(_MSC_VER) -inline std::tm localtime_s(const std::time_t* src) -{ - std::tm dst; - const auto result = ::localtime_s(&dst, src); - if (result) { throw std::runtime_error("localtime_s failed."); } - return dst; -} -inline std::tm gmtime_s(const std::time_t* src) -{ - std::tm dst; - const auto result = ::gmtime_s(&dst, src); - if (result) { throw std::runtime_error("gmtime_s failed."); } - return dst; -} -#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE) -inline std::tm localtime_s(const std::time_t* src) -{ - std::tm dst; - const auto result = ::localtime_r(src, &dst); - if (!result) { throw std::runtime_error("localtime_r failed."); } - return dst; -} -inline std::tm gmtime_s(const std::time_t* src) -{ - std::tm dst; - const auto result = ::gmtime_r(src, &dst); - if (!result) { throw std::runtime_error("gmtime_r failed."); } - return dst; -} -#else // fallback. not threadsafe -inline std::tm localtime_s(const std::time_t* src) -{ - const auto result = std::localtime(src); - if (!result) { throw std::runtime_error("localtime failed."); } - return *result; -} -inline std::tm gmtime_s(const std::time_t* src) -{ - const auto result = std::gmtime(src); - if (!result) { throw std::runtime_error("gmtime failed."); } - return *result; -} -#endif -} // detail - -enum class month_t : std::uint8_t -{ - Jan = 0, - Feb = 1, - Mar = 2, - Apr = 3, - May = 4, - Jun = 5, - Jul = 6, - Aug = 7, - Sep = 8, - Oct = 9, - Nov = 10, - Dec = 11 -}; - -struct local_date -{ - std::int16_t year; // A.D. (like, 2018) - std::uint8_t month; // [0, 11] - std::uint8_t day; // [1, 31] - - local_date(int y, month_t m, int d) - : year (static_cast(y)), - month(static_cast(m)), - day (static_cast(d)) - {} - - explicit local_date(const std::tm& t) - : year (static_cast(t.tm_year + 1900)), - month(static_cast(t.tm_mon)), - day (static_cast(t.tm_mday)) - {} - - explicit local_date(const std::chrono::system_clock::time_point& tp) - { - const auto t = std::chrono::system_clock::to_time_t(tp); - const auto time = detail::localtime_s(&t); - *this = local_date(time); - } - - explicit local_date(const std::time_t t) - : local_date(std::chrono::system_clock::from_time_t(t)) - {} - - operator std::chrono::system_clock::time_point() const - { - // std::mktime returns date as local time zone. no conversion needed - std::tm t; - t.tm_sec = 0; - t.tm_min = 0; - t.tm_hour = 0; - t.tm_mday = static_cast(this->day); - t.tm_mon = static_cast(this->month); - t.tm_year = static_cast(this->year) - 1900; - t.tm_wday = 0; // the value will be ignored - t.tm_yday = 0; // the value will be ignored - t.tm_isdst = -1; - return std::chrono::system_clock::from_time_t(std::mktime(&t)); - } - - operator std::time_t() const - { - return std::chrono::system_clock::to_time_t( - std::chrono::system_clock::time_point(*this)); - } - - local_date() = default; - ~local_date() = default; - local_date(local_date const&) = default; - local_date(local_date&&) = default; - local_date& operator=(local_date const&) = default; - local_date& operator=(local_date&&) = default; -}; - -inline bool operator==(const local_date& lhs, const local_date& rhs) -{ - return std::make_tuple(lhs.year, lhs.month, lhs.day) == - std::make_tuple(rhs.year, rhs.month, rhs.day); -} -inline bool operator!=(const local_date& lhs, const local_date& rhs) -{ - return !(lhs == rhs); -} -inline bool operator< (const local_date& lhs, const local_date& rhs) -{ - return std::make_tuple(lhs.year, lhs.month, lhs.day) < - std::make_tuple(rhs.year, rhs.month, rhs.day); -} -inline bool operator<=(const local_date& lhs, const local_date& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -inline bool operator> (const local_date& lhs, const local_date& rhs) -{ - return !(lhs <= rhs); -} -inline bool operator>=(const local_date& lhs, const local_date& rhs) -{ - return !(lhs < rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_date& date) -{ - os << std::setfill('0') << std::setw(4) << static_cast(date.year ) << '-'; - os << std::setfill('0') << std::setw(2) << static_cast(date.month) + 1 << '-'; - os << std::setfill('0') << std::setw(2) << static_cast(date.day ) ; - return os; -} - -struct local_time -{ - std::uint8_t hour; // [0, 23] - std::uint8_t minute; // [0, 59] - std::uint8_t second; // [0, 60] - std::uint16_t millisecond; // [0, 999] - std::uint16_t microsecond; // [0, 999] - std::uint16_t nanosecond; // [0, 999] - - local_time(int h, int m, int s, - int ms = 0, int us = 0, int ns = 0) - : hour (static_cast(h)), - minute(static_cast(m)), - second(static_cast(s)), - millisecond(static_cast(ms)), - microsecond(static_cast(us)), - nanosecond (static_cast(ns)) - {} - - explicit local_time(const std::tm& t) - : hour (static_cast(t.tm_hour)), - minute(static_cast(t.tm_min)), - second(static_cast(t.tm_sec)), - millisecond(0), microsecond(0), nanosecond(0) - {} - - template - explicit local_time(const std::chrono::duration& t) - { - const auto h = std::chrono::duration_cast(t); - this->hour = static_cast(h.count()); - const auto t2 = t - h; - const auto m = std::chrono::duration_cast(t2); - this->minute = static_cast(m.count()); - const auto t3 = t2 - m; - const auto s = std::chrono::duration_cast(t3); - this->second = static_cast(s.count()); - const auto t4 = t3 - s; - const auto ms = std::chrono::duration_cast(t4); - this->millisecond = static_cast(ms.count()); - const auto t5 = t4 - ms; - const auto us = std::chrono::duration_cast(t5); - this->microsecond = static_cast(us.count()); - const auto t6 = t5 - us; - const auto ns = std::chrono::duration_cast(t6); - this->nanosecond = static_cast(ns.count()); - } - - operator std::chrono::nanoseconds() const - { - return std::chrono::nanoseconds (this->nanosecond) + - std::chrono::microseconds(this->microsecond) + - std::chrono::milliseconds(this->millisecond) + - std::chrono::seconds(this->second) + - std::chrono::minutes(this->minute) + - std::chrono::hours(this->hour); - } - - local_time() = default; - ~local_time() = default; - local_time(local_time const&) = default; - local_time(local_time&&) = default; - local_time& operator=(local_time const&) = default; - local_time& operator=(local_time&&) = default; -}; - -inline bool operator==(const local_time& lhs, const local_time& rhs) -{ - return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) == - std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond); -} -inline bool operator!=(const local_time& lhs, const local_time& rhs) -{ - return !(lhs == rhs); -} -inline bool operator< (const local_time& lhs, const local_time& rhs) -{ - return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) < - std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond); -} -inline bool operator<=(const local_time& lhs, const local_time& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -inline bool operator> (const local_time& lhs, const local_time& rhs) -{ - return !(lhs <= rhs); -} -inline bool operator>=(const local_time& lhs, const local_time& rhs) -{ - return !(lhs < rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_time& time) -{ - os << std::setfill('0') << std::setw(2) << static_cast(time.hour ) << ':'; - os << std::setfill('0') << std::setw(2) << static_cast(time.minute) << ':'; - os << std::setfill('0') << std::setw(2) << static_cast(time.second); - if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0) - { - os << '.'; - os << std::setfill('0') << std::setw(3) << static_cast(time.millisecond); - if(time.microsecond != 0 || time.nanosecond != 0) - { - os << std::setfill('0') << std::setw(3) << static_cast(time.microsecond); - if(time.nanosecond != 0) - { - os << std::setfill('0') << std::setw(3) << static_cast(time.nanosecond); - } - } - } - return os; -} - -struct time_offset -{ - std::int8_t hour; // [-12, 12] - std::int8_t minute; // [-59, 59] - - time_offset(int h, int m) - : hour (static_cast(h)), - minute(static_cast(m)) - {} - - operator std::chrono::minutes() const - { - return std::chrono::minutes(this->minute) + - std::chrono::hours(this->hour); - } - - time_offset() = default; - ~time_offset() = default; - time_offset(time_offset const&) = default; - time_offset(time_offset&&) = default; - time_offset& operator=(time_offset const&) = default; - time_offset& operator=(time_offset&&) = default; -}; - -inline bool operator==(const time_offset& lhs, const time_offset& rhs) -{ - return std::make_tuple(lhs.hour, lhs.minute) == - std::make_tuple(rhs.hour, rhs.minute); -} -inline bool operator!=(const time_offset& lhs, const time_offset& rhs) -{ - return !(lhs == rhs); -} -inline bool operator< (const time_offset& lhs, const time_offset& rhs) -{ - return std::make_tuple(lhs.hour, lhs.minute) < - std::make_tuple(rhs.hour, rhs.minute); -} -inline bool operator<=(const time_offset& lhs, const time_offset& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -inline bool operator> (const time_offset& lhs, const time_offset& rhs) -{ - return !(lhs <= rhs); -} -inline bool operator>=(const time_offset& lhs, const time_offset& rhs) -{ - return !(lhs < rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const time_offset& offset) -{ - if(offset.hour == 0 && offset.minute == 0) - { - os << 'Z'; - return os; - } - int minute = static_cast(offset.hour) * 60 + offset.minute; - if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';} - os << std::setfill('0') << std::setw(2) << minute / 60 << ':'; - os << std::setfill('0') << std::setw(2) << minute % 60; - return os; -} - -struct local_datetime -{ - local_date date; - local_time time; - - local_datetime(local_date d, local_time t): date(d), time(t) {} - - explicit local_datetime(const std::tm& t): date(t), time(t){} - - explicit local_datetime(const std::chrono::system_clock::time_point& tp) - { - const auto t = std::chrono::system_clock::to_time_t(tp); - std::tm ltime = detail::localtime_s(&t); - - this->date = local_date(ltime); - this->time = local_time(ltime); - - // std::tm lacks subsecond information, so diff between tp and tm - // can be used to get millisecond & microsecond information. - const auto t_diff = tp - - std::chrono::system_clock::from_time_t(std::mktime(<ime)); - this->time.millisecond = static_cast( - std::chrono::duration_cast(t_diff).count()); - this->time.microsecond = static_cast( - std::chrono::duration_cast(t_diff).count()); - this->time.nanosecond = static_cast( - std::chrono::duration_cast(t_diff).count()); - } - - explicit local_datetime(const std::time_t t) - : local_datetime(std::chrono::system_clock::from_time_t(t)) - {} - - operator std::chrono::system_clock::time_point() const - { - using internal_duration = - typename std::chrono::system_clock::time_point::duration; - - // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator - // of local_date and local_time independently, the conversion fails if - // it is the day when DST begins or ends. Since local_date considers the - // time is 00:00 A.M. and local_time does not consider DST because it - // does not have any date information. We need to consider both date and - // time information at the same time to convert it correctly. - - std::tm t; - t.tm_sec = static_cast(this->time.second); - t.tm_min = static_cast(this->time.minute); - t.tm_hour = static_cast(this->time.hour); - t.tm_mday = static_cast(this->date.day); - t.tm_mon = static_cast(this->date.month); - t.tm_year = static_cast(this->date.year) - 1900; - t.tm_wday = 0; // the value will be ignored - t.tm_yday = 0; // the value will be ignored - t.tm_isdst = -1; - - // std::mktime returns date as local time zone. no conversion needed - auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t)); - dt += std::chrono::duration_cast( - std::chrono::milliseconds(this->time.millisecond) + - std::chrono::microseconds(this->time.microsecond) + - std::chrono::nanoseconds (this->time.nanosecond)); - return dt; - } - - operator std::time_t() const - { - return std::chrono::system_clock::to_time_t( - std::chrono::system_clock::time_point(*this)); - } - - local_datetime() = default; - ~local_datetime() = default; - local_datetime(local_datetime const&) = default; - local_datetime(local_datetime&&) = default; - local_datetime& operator=(local_datetime const&) = default; - local_datetime& operator=(local_datetime&&) = default; -}; - -inline bool operator==(const local_datetime& lhs, const local_datetime& rhs) -{ - return std::make_tuple(lhs.date, lhs.time) == - std::make_tuple(rhs.date, rhs.time); -} -inline bool operator!=(const local_datetime& lhs, const local_datetime& rhs) -{ - return !(lhs == rhs); -} -inline bool operator< (const local_datetime& lhs, const local_datetime& rhs) -{ - return std::make_tuple(lhs.date, lhs.time) < - std::make_tuple(rhs.date, rhs.time); -} -inline bool operator<=(const local_datetime& lhs, const local_datetime& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -inline bool operator> (const local_datetime& lhs, const local_datetime& rhs) -{ - return !(lhs <= rhs); -} -inline bool operator>=(const local_datetime& lhs, const local_datetime& rhs) -{ - return !(lhs < rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_datetime& dt) -{ - os << dt.date << 'T' << dt.time; - return os; -} - -struct offset_datetime -{ - local_date date; - local_time time; - time_offset offset; - - offset_datetime(local_date d, local_time t, time_offset o) - : date(d), time(t), offset(o) - {} - offset_datetime(const local_datetime& dt, time_offset o) - : date(dt.date), time(dt.time), offset(o) - {} - explicit offset_datetime(const local_datetime& ld) - : date(ld.date), time(ld.time), offset(get_local_offset(nullptr)) - // use the current local timezone offset - {} - explicit offset_datetime(const std::chrono::system_clock::time_point& tp) - : offset(0, 0) // use gmtime - { - const auto timet = std::chrono::system_clock::to_time_t(tp); - const auto tm = detail::gmtime_s(&timet); - this->date = local_date(tm); - this->time = local_time(tm); - } - explicit offset_datetime(const std::time_t& t) - : offset(0, 0) // use gmtime - { - const auto tm = detail::gmtime_s(&t); - this->date = local_date(tm); - this->time = local_time(tm); - } - explicit offset_datetime(const std::tm& t) - : offset(0, 0) // assume gmtime - { - this->date = local_date(t); - this->time = local_time(t); - } - - operator std::chrono::system_clock::time_point() const - { - // get date-time - using internal_duration = - typename std::chrono::system_clock::time_point::duration; - - // first, convert it to local date-time information in the same way as - // local_datetime does. later we will use time_t to adjust time offset. - std::tm t; - t.tm_sec = static_cast(this->time.second); - t.tm_min = static_cast(this->time.minute); - t.tm_hour = static_cast(this->time.hour); - t.tm_mday = static_cast(this->date.day); - t.tm_mon = static_cast(this->date.month); - t.tm_year = static_cast(this->date.year) - 1900; - t.tm_wday = 0; // the value will be ignored - t.tm_yday = 0; // the value will be ignored - t.tm_isdst = -1; - const std::time_t tp_loc = std::mktime(std::addressof(t)); - - auto tp = std::chrono::system_clock::from_time_t(tp_loc); - tp += std::chrono::duration_cast( - std::chrono::milliseconds(this->time.millisecond) + - std::chrono::microseconds(this->time.microsecond) + - std::chrono::nanoseconds (this->time.nanosecond)); - - // Since mktime uses local time zone, it should be corrected. - // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if - // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need - // to add `+09:00` to `03:00:00Z`. - // Here, it uses the time_t converted from date-time info to handle - // daylight saving time. - const auto ofs = get_local_offset(std::addressof(tp_loc)); - tp += std::chrono::hours (ofs.hour); - tp += std::chrono::minutes(ofs.minute); - - // We got `12:00:00Z` by correcting local timezone applied by mktime. - // Then we will apply the offset. Let's say `12:00:00-08:00` is given. - // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`. - // So we need to subtract the offset. - tp -= std::chrono::minutes(this->offset); - return tp; - } - - operator std::time_t() const - { - return std::chrono::system_clock::to_time_t( - std::chrono::system_clock::time_point(*this)); - } - - offset_datetime() = default; - ~offset_datetime() = default; - offset_datetime(offset_datetime const&) = default; - offset_datetime(offset_datetime&&) = default; - offset_datetime& operator=(offset_datetime const&) = default; - offset_datetime& operator=(offset_datetime&&) = default; - - private: - - static time_offset get_local_offset(const std::time_t* tp) - { - // get local timezone with the same date-time information as mktime - const auto t = detail::localtime_s(tp); - - std::array buf; - const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0 - if(result != 5) - { - throw std::runtime_error("toml::offset_datetime: cannot obtain " - "timezone information of current env"); - } - const int ofs = std::atoi(buf.data()); - const int ofs_h = ofs / 100; - const int ofs_m = ofs - (ofs_h * 100); - return time_offset(ofs_h, ofs_m); - } -}; - -inline bool operator==(const offset_datetime& lhs, const offset_datetime& rhs) -{ - return std::make_tuple(lhs.date, lhs.time, lhs.offset) == - std::make_tuple(rhs.date, rhs.time, rhs.offset); -} -inline bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs) -{ - return !(lhs == rhs); -} -inline bool operator< (const offset_datetime& lhs, const offset_datetime& rhs) -{ - return std::make_tuple(lhs.date, lhs.time, lhs.offset) < - std::make_tuple(rhs.date, rhs.time, rhs.offset); -} -inline bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -inline bool operator> (const offset_datetime& lhs, const offset_datetime& rhs) -{ - return !(lhs <= rhs); -} -inline bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs) -{ - return !(lhs < rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const offset_datetime& dt) -{ - os << dt.date << 'T' << dt.time << dt.offset; - return os; -} - -}//toml -#endif// TOML11_DATETIME diff --git a/src/frontend/qt_sdl/toml/toml/exception.hpp b/src/frontend/qt_sdl/toml/toml/exception.hpp deleted file mode 100644 index c64651d0..00000000 --- a/src/frontend/qt_sdl/toml/toml/exception.hpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_EXCEPTION_HPP -#define TOML11_EXCEPTION_HPP -#include -#include - -#include "source_location.hpp" - -namespace toml -{ - -struct exception : public std::exception -{ - public: - explicit exception(const source_location& loc): loc_(loc) {} - virtual ~exception() noexcept override = default; - virtual const char* what() const noexcept override {return "";} - virtual source_location const& location() const noexcept {return loc_;} - - protected: - source_location loc_; -}; - -struct syntax_error : public toml::exception -{ - public: - explicit syntax_error(const std::string& what_arg, const source_location& loc) - : exception(loc), what_(what_arg) - {} - virtual ~syntax_error() noexcept override = default; - virtual const char* what() const noexcept override {return what_.c_str();} - - protected: - std::string what_; -}; - -struct type_error : public toml::exception -{ - public: - explicit type_error(const std::string& what_arg, const source_location& loc) - : exception(loc), what_(what_arg) - {} - virtual ~type_error() noexcept override = default; - virtual const char* what() const noexcept override {return what_.c_str();} - - protected: - std::string what_; -}; - -struct internal_error : public toml::exception -{ - public: - explicit internal_error(const std::string& what_arg, const source_location& loc) - : exception(loc), what_(what_arg) - {} - virtual ~internal_error() noexcept override = default; - virtual const char* what() const noexcept override {return what_.c_str();} - - protected: - std::string what_; -}; - -} // toml -#endif // TOML_EXCEPTION diff --git a/src/frontend/qt_sdl/toml/toml/get.hpp b/src/frontend/qt_sdl/toml/toml/get.hpp deleted file mode 100644 index 901790b5..00000000 --- a/src/frontend/qt_sdl/toml/toml/get.hpp +++ /dev/null @@ -1,1119 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_GET_HPP -#define TOML11_GET_HPP -#include - -#include "from.hpp" -#include "result.hpp" -#include "value.hpp" - -namespace toml -{ - -// ============================================================================ -// exact toml::* type - -template class M, template class V> -detail::enable_if_t>::value, T> & -get(basic_value& v) -{ - return v.template cast>::value>(); -} - -template class M, template class V> -detail::enable_if_t>::value, T> const& -get(const basic_value& v) -{ - return v.template cast>::value>(); -} - -template class M, template class V> -detail::enable_if_t>::value, T> -get(basic_value&& v) -{ - return T(std::move(v).template cast>::value>()); -} - -// ============================================================================ -// T == toml::value; identity transformation. - -template class M, template class V> -inline detail::enable_if_t>::value, T>& -get(basic_value& v) -{ - return v; -} - -template class M, template class V> -inline detail::enable_if_t>::value, T> const& -get(const basic_value& v) -{ - return v; -} - -template class M, template class V> -inline detail::enable_if_t>::value, T> -get(basic_value&& v) -{ - return basic_value(std::move(v)); -} - -// ============================================================================ -// T == toml::basic_value; basic_value -> basic_value - -template class M, template class V> -inline detail::enable_if_t, - detail::negation>> - >::value, T> -get(const basic_value& v) -{ - return T(v); -} - -// ============================================================================ -// integer convertible from toml::Integer - -template class M, template class V> -inline detail::enable_if_t, // T is integral - detail::negation>, // but not bool - detail::negation< // but not toml::integer - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value& v) -{ - return static_cast(v.as_integer()); -} - -// ============================================================================ -// floating point convertible from toml::Float - -template class M, template class V> -inline detail::enable_if_t, // T is floating_point - detail::negation< // but not toml::floating - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value& v) -{ - return static_cast(v.as_floating()); -} - -// ============================================================================ -// std::string; toml uses its own toml::string, but it should be convertible to -// std::string seamlessly - -template class M, template class V> -inline detail::enable_if_t::value, std::string>& -get(basic_value& v) -{ - return v.as_string().str; -} - -template class M, template class V> -inline detail::enable_if_t::value, std::string> const& -get(const basic_value& v) -{ - return v.as_string().str; -} - -template class M, template class V> -inline detail::enable_if_t::value, std::string> -get(basic_value&& v) -{ - return std::string(std::move(v.as_string().str)); -} - -// ============================================================================ -// std::string_view - -#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0 -template class M, template class V> -inline detail::enable_if_t::value, std::string_view> -get(const basic_value& v) -{ - return std::string_view(v.as_string().str); -} -#endif - -// ============================================================================ -// std::chrono::duration from toml::local_time. - -template class M, template class V> -inline detail::enable_if_t::value, T> -get(const basic_value& v) -{ - return std::chrono::duration_cast( - std::chrono::nanoseconds(v.as_local_time())); -} - -// ============================================================================ -// std::chrono::system_clock::time_point from toml::datetime variants - -template class M, template class V> -inline detail::enable_if_t< - std::is_same::value, T> -get(const basic_value& v) -{ - switch(v.type()) - { - case value_t::local_date: - { - return std::chrono::system_clock::time_point(v.as_local_date()); - } - case value_t::local_datetime: - { - return std::chrono::system_clock::time_point(v.as_local_datetime()); - } - case value_t::offset_datetime: - { - return std::chrono::system_clock::time_point(v.as_offset_datetime()); - } - default: - { - throw type_error(detail::format_underline("toml::value: " - "bad_cast to std::chrono::system_clock::time_point", { - {v.location(), concat_to_string("the actual type is ", v.type())} - }), v.location()); - } - } -} - -// ============================================================================ -// forward declaration to use this recursively. ignore this and go ahead. - -// array-like type with push_back(value) method -template class M, template class V> -detail::enable_if_t, // T is a container - detail::has_push_back_method, // T::push_back(value) works - detail::negation< // but not toml::array - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value&); - -// array-like type without push_back(value) method -template class M, template class V> -detail::enable_if_t, // T is a container - detail::negation>, // w/o push_back(...) - detail::negation>, // T does not have special conversion - detail::negation< // not toml::array - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value&); - -// std::pair -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value&); - -// std::tuple -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value&); - -// map-like classes -template class M, template class V> -detail::enable_if_t, // T is map - detail::negation< // but not toml::table - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value&); - -// T.from_toml(v) -template class M, template class V> -detail::enable_if_t>>, - detail::has_from_toml_method, // but has from_toml(toml::value) - std::is_default_constructible // and default constructible - >::value, T> -get(const basic_value&); - -// toml::from::from_toml(v) -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value&); - -// T(const toml::value&) and T is not toml::basic_value, -// and it does not have `from` nor `from_toml`. -template class M, template class V> -detail::enable_if_t>, - std::is_constructible&>, - detail::negation>, - detail::negation> - >::value, T> -get(const basic_value&); - -// ============================================================================ -// array-like types; most likely STL container, like std::vector, etc. - -template class M, template class V> -detail::enable_if_t, // T is a container - detail::has_push_back_method, // container.push_back(elem) works - detail::negation< // but not toml::array - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value& v) -{ - using value_type = typename T::value_type; - const auto& ary = v.as_array(); - - T container; - try_reserve(container, ary.size()); - - for(const auto& elem : ary) - { - container.push_back(get(elem)); - } - return container; -} - -// ============================================================================ -// std::forward_list does not have push_back, insert, or emplace. -// It has insert_after, emplace_after, push_front. - -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value& v) -{ - using value_type = typename T::value_type; - T container; - for(const auto& elem : v.as_array()) - { - container.push_front(get(elem)); - } - container.reverse(); - return container; -} - -// ============================================================================ -// array-like types, without push_back(). most likely [std|boost]::array. - -template class M, template class V> -detail::enable_if_t, // T is a container - detail::negation>, // w/o push_back - detail::negation>, // T does not have special conversion - detail::negation< // T is not toml::array - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value& v) -{ - using value_type = typename T::value_type; - const auto& ar = v.as_array(); - - T container; - if(ar.size() != container.size()) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "toml::get: specified container size is ", container.size(), - " but there are ", ar.size(), " elements in toml array."), { - {v.location(), "here"} - })); - } - for(std::size_t i=0; i(ar[i]); - } - return container; -} - -// ============================================================================ -// std::pair. - -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value& v) -{ - using first_type = typename T::first_type; - using second_type = typename T::second_type; - - const auto& ar = v.as_array(); - if(ar.size() != 2) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "toml::get: specified std::pair but there are ", ar.size(), - " elements in toml array."), {{v.location(), "here"}})); - } - return std::make_pair(::toml::get(ar.at(0)), - ::toml::get(ar.at(1))); -} - -// ============================================================================ -// std::tuple. - -namespace detail -{ -template -T get_tuple_impl(const Array& a, index_sequence) -{ - return std::make_tuple( - ::toml::get::type>(a.at(I))...); -} -} // detail - -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value& v) -{ - const auto& ar = v.as_array(); - if(ar.size() != std::tuple_size::value) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "toml::get: specified std::tuple with ", - std::tuple_size::value, " elements, but there are ", ar.size(), - " elements in toml array."), {{v.location(), "here"}})); - } - return detail::get_tuple_impl(ar, - detail::make_index_sequence::value>{}); -} - -// ============================================================================ -// map-like types; most likely STL map, like std::map or std::unordered_map. - -template class M, template class V> -detail::enable_if_t, // T is map - detail::negation< // but not toml::array - detail::is_exact_toml_type>> - >::value, T> -get(const basic_value& v) -{ - using key_type = typename T::key_type; - using mapped_type = typename T::mapped_type; - static_assert(std::is_convertible::value, - "toml::get only supports map type of which key_type is " - "convertible from std::string."); - T map; - for(const auto& kv : v.as_table()) - { - map.emplace(key_type(kv.first), get(kv.second)); - } - return map; -} - -// ============================================================================ -// user-defined, but compatible types. - -template class M, template class V> -detail::enable_if_t>>, - detail::has_from_toml_method, // but has from_toml(toml::value) memfn - std::is_default_constructible // and default constructible - >::value, T> -get(const basic_value& v) -{ - T ud; - ud.from_toml(v); - return ud; -} -template class M, template class V> -detail::enable_if_t::value, T> -get(const basic_value& v) -{ - return ::toml::from::from_toml(v); -} - -template class M, template class V> -detail::enable_if_t>, // T is not a toml::value - std::is_constructible&>, // T is constructible from toml::value - detail::negation>, // and T does not have T.from_toml(v); - detail::negation> // and T does not have toml::from{}; - >::value, T> -get(const basic_value& v) -{ - return T(v); -} - -// ============================================================================ -// find - -// ---------------------------------------------------------------------------- -// these overloads do not require to set T. and returns value itself. -template class M, template class V> -basic_value const& find(const basic_value& v, const key& ky) -{ - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return tab.at(ky); -} -template class M, template class V> -basic_value& find(basic_value& v, const key& ky) -{ - auto& tab = v.as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return tab.at(ky); -} -template class M, template class V> -basic_value find(basic_value&& v, const key& ky) -{ - typename basic_value::table_type tab = std::move(v).as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return basic_value(std::move(tab.at(ky))); -} - -// ---------------------------------------------------------------------------- -// find(value, idx) -template class M, template class V> -basic_value const& -find(const basic_value& v, const std::size_t idx) -{ - const auto& ary = v.as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return ary.at(idx); -} -template class M, template class V> -basic_value& find(basic_value& v, const std::size_t idx) -{ - auto& ary = v.as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return ary.at(idx); -} -template class M, template class V> -basic_value find(basic_value&& v, const std::size_t idx) -{ - auto& ary = v.as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return basic_value(std::move(ary.at(idx))); -} - -// ---------------------------------------------------------------------------- -// find(value, key); - -template class M, template class V> -decltype(::toml::get(std::declval const&>())) -find(const basic_value& v, const key& ky) -{ - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return ::toml::get(tab.at(ky)); -} - -template class M, template class V> -decltype(::toml::get(std::declval&>())) -find(basic_value& v, const key& ky) -{ - auto& tab = v.as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return ::toml::get(tab.at(ky)); -} - -template class M, template class V> -decltype(::toml::get(std::declval&&>())) -find(basic_value&& v, const key& ky) -{ - typename basic_value::table_type tab = std::move(v).as_table(); - if(tab.count(ky) == 0) - { - detail::throw_key_not_found_error(v, ky); - } - return ::toml::get(std::move(tab.at(ky))); -} - -// ---------------------------------------------------------------------------- -// find(value, idx) -template class M, template class V> -decltype(::toml::get(std::declval const&>())) -find(const basic_value& v, const std::size_t idx) -{ - const auto& ary = v.as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return ::toml::get(ary.at(idx)); -} -template class M, template class V> -decltype(::toml::get(std::declval&>())) -find(basic_value& v, const std::size_t idx) -{ - auto& ary = v.as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return ::toml::get(ary.at(idx)); -} -template class M, template class V> -decltype(::toml::get(std::declval&&>())) -find(basic_value&& v, const std::size_t idx) -{ - typename basic_value::array_type ary = std::move(v).as_array(); - if(ary.size() <= idx) - { - throw std::out_of_range(detail::format_underline(concat_to_string( - "index ", idx, " is out of range"), {{v.location(), "in this array"}})); - } - return ::toml::get(std::move(ary.at(idx))); -} - -// -------------------------------------------------------------------------- -// toml::find(toml::value, toml::key, Ts&& ... keys) - -namespace detail -{ -// It suppresses warnings by -Wsign-conversion. Let's say we have the following -// code. -// ```cpp -// const auto x = toml::find(data, "array", 0); -// ``` -// Here, the type of literal number `0` is `int`. `int` is a signed integer. -// `toml::find` takes `std::size_t` as an index. So it causes implicit sign -// conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0` -// suppresses the warning, but it makes user code messy. -// To suppress this warning, we need to be aware of type conversion caused -// by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of -// keys can be any combination of {string-like, size_t-like}. Of course we can't -// write down all the combinations. Thus we need to use some function that -// recognize the type of argument and cast it into `std::string` or -// `std::size_t` depending on the context. -// `key_cast` does the job. It has 2 overloads. One is invoked when the -// argument type is an integer and cast the argument into `std::size_t`. The -// other is invoked when the argument type is not an integer, possibly one of -// std::string, const char[N] or const char*, and construct std::string from -// the argument. -// `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to -// `toml::find(v, k)` to suppress -Wsign-conversion. - -template -enable_if_t>, - negation, bool>>>::value, std::size_t> -key_cast(T&& v) noexcept -{ - return std::size_t(v); -} -template -enable_if_t>, - negation, bool>>>>::value, std::string> -key_cast(T&& v) noexcept -{ - return std::string(std::forward(v)); -} -} // detail - -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -const basic_value& -find(const basic_value& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(v, detail::key_cast(k1)), - detail::key_cast(k2), std::forward(keys)...); -} -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -basic_value& -find(basic_value& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(v, detail::key_cast(k1)), - detail::key_cast(k2), std::forward(keys)...); -} -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -basic_value -find(basic_value&& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(std::move(v), std::forward(k1)), - detail::key_cast(k2), std::forward(keys)...); -} - -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -decltype(::toml::get(std::declval&>())) -find(const basic_value& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(v, detail::key_cast(k1)), - detail::key_cast(k2), std::forward(keys)...); -} -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -decltype(::toml::get(std::declval&>())) -find(basic_value& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(v, detail::key_cast(k1)), - detail::key_cast(k2), std::forward(keys)...); -} -template class M, template class V, - typename Key1, typename Key2, typename ... Keys> -decltype(::toml::get(std::declval&&>())) -find(basic_value&& v, Key1&& k1, Key2&& k2, Keys&& ... keys) -{ - return ::toml::find(::toml::find(std::move(v), detail::key_cast(k1)), - detail::key_cast(k2), std::forward(keys)...); -} - -// ============================================================================ -// get_or(value, fallback) - -template class M, template class V> -basic_value const& -get_or(const basic_value& v, const basic_value&) -{ - return v; -} -template class M, template class V> -basic_value& -get_or(basic_value& v, basic_value&) -{ - return v; -} -template class M, template class V> -basic_value -get_or(basic_value&& v, basic_value&&) -{ - return v; -} - -// ---------------------------------------------------------------------------- -// specialization for the exact toml types (return type becomes lvalue ref) - -template class M, template class V> -detail::enable_if_t< - detail::is_exact_toml_type>::value, T> const& -get_or(const basic_value& v, const T& opt) -{ - try - { - return get>(v); - } - catch(...) - { - return opt; - } -} -template class M, template class V> -detail::enable_if_t< - detail::is_exact_toml_type>::value, T>& -get_or(basic_value& v, T& opt) -{ - try - { - return get>(v); - } - catch(...) - { - return opt; - } -} -template class M, template class V> -detail::enable_if_t, - basic_value>::value, detail::remove_cvref_t> -get_or(basic_value&& v, T&& opt) -{ - try - { - return get>(std::move(v)); - } - catch(...) - { - return detail::remove_cvref_t(std::forward(opt)); - } -} - -// ---------------------------------------------------------------------------- -// specialization for std::string (return type becomes lvalue ref) - -template class M, template class V> -detail::enable_if_t, std::string>::value, - std::string> const& -get_or(const basic_value& v, const T& opt) -{ - try - { - return v.as_string().str; - } - catch(...) - { - return opt; - } -} -template class M, template class V> -detail::enable_if_t::value, std::string>& -get_or(basic_value& v, T& opt) -{ - try - { - return v.as_string().str; - } - catch(...) - { - return opt; - } -} -template class M, template class V> -detail::enable_if_t< - std::is_same, std::string>::value, std::string> -get_or(basic_value&& v, T&& opt) -{ - try - { - return std::move(v.as_string().str); - } - catch(...) - { - return std::string(std::forward(opt)); - } -} - -// ---------------------------------------------------------------------------- -// specialization for string literal - -template class M, template class V> -detail::enable_if_t::type>::value, std::string> -get_or(const basic_value& v, T&& opt) -{ - try - { - return std::move(v.as_string().str); - } - catch(...) - { - return std::string(std::forward(opt)); - } -} - -// ---------------------------------------------------------------------------- -// others (require type conversion and return type cannot be lvalue reference) - -template class M, template class V> -detail::enable_if_t, - basic_value>>, - detail::negation>>, - detail::negation::type>> - >::value, detail::remove_cvref_t> -get_or(const basic_value& v, T&& opt) -{ - try - { - return get>(v); - } - catch(...) - { - return detail::remove_cvref_t(std::forward(opt)); - } -} - -// =========================================================================== -// find_or(value, key, fallback) - -template class M, template class V> -basic_value const& -find_or(const basic_value& v, const key& ky, - const basic_value& opt) -{ - if(!v.is_table()) {return opt;} - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return tab.at(ky); -} - -template class M, template class V> -basic_value& -find_or(basic_value& v, const toml::key& ky, basic_value& opt) -{ - if(!v.is_table()) {return opt;} - auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return tab.at(ky); -} - -template class M, template class V> -basic_value -find_or(basic_value&& v, const toml::key& ky, basic_value&& opt) -{ - if(!v.is_table()) {return opt;} - auto tab = std::move(v).as_table(); - if(tab.count(ky) == 0) {return opt;} - return basic_value(std::move(tab.at(ky))); -} - -// --------------------------------------------------------------------------- -// exact types (return type can be a reference) -template class M, template class V> -detail::enable_if_t< - detail::is_exact_toml_type>::value, T> const& -find_or(const basic_value& v, const key& ky, const T& opt) -{ - if(!v.is_table()) {return opt;} - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} - -template class M, template class V> -detail::enable_if_t< - detail::is_exact_toml_type>::value, T>& -find_or(basic_value& v, const toml::key& ky, T& opt) -{ - if(!v.is_table()) {return opt;} - auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} - -template class M, template class V> -detail::enable_if_t< - detail::is_exact_toml_type>::value, - detail::remove_cvref_t> -find_or(basic_value&& v, const toml::key& ky, T&& opt) -{ - if(!v.is_table()) {return std::forward(opt);} - auto tab = std::move(v).as_table(); - if(tab.count(ky) == 0) {return std::forward(opt);} - return get_or(std::move(tab.at(ky)), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// std::string (return type can be a reference) - -template class M, template class V> -detail::enable_if_t::value, std::string> const& -find_or(const basic_value& v, const key& ky, const T& opt) -{ - if(!v.is_table()) {return opt;} - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} -template class M, template class V> -detail::enable_if_t::value, std::string>& -find_or(basic_value& v, const toml::key& ky, T& opt) -{ - if(!v.is_table()) {return opt;} - auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return opt;} - return get_or(tab.at(ky), opt); -} -template class M, template class V> -detail::enable_if_t::value, std::string> -find_or(basic_value&& v, const toml::key& ky, T&& opt) -{ - if(!v.is_table()) {return std::forward(opt);} - auto tab = std::move(v).as_table(); - if(tab.count(ky) == 0) {return std::forward(opt);} - return get_or(std::move(tab.at(ky)), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// string literal (deduced as std::string) -template class M, template class V> -detail::enable_if_t< - detail::is_string_literal::type>::value, - std::string> -find_or(const basic_value& v, const toml::key& ky, T&& opt) -{ - if(!v.is_table()) {return std::string(opt);} - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return std::string(opt);} - return get_or(tab.at(ky), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// others (require type conversion and return type cannot be lvalue reference) -template class M, template class V> -detail::enable_if_t, basic_value>>, - // T is not std::string - detail::negation>>, - // T is not a string literal - detail::negation::type>> - >::value, detail::remove_cvref_t> -find_or(const basic_value& v, const toml::key& ky, T&& opt) -{ - if(!v.is_table()) {return std::forward(opt);} - const auto& tab = v.as_table(); - if(tab.count(ky) == 0) {return std::forward(opt);} - return get_or(tab.at(ky), std::forward(opt)); -} - -// --------------------------------------------------------------------------- -// recursive find-or with type deduction (find_or(value, keys, opt)) - -template 1), std::nullptr_t> = nullptr> - // here we need to add SFINAE in the template parameter to avoid - // infinite recursion in type deduction on gcc -auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys) - -> decltype(find_or(std::forward(v), ky, detail::last_one(std::forward(keys)...))) -{ - if(!v.is_table()) - { - return detail::last_one(std::forward(keys)...); - } - auto&& tab = std::forward(v).as_table(); - if(tab.count(ky) == 0) - { - return detail::last_one(std::forward(keys)...); - } - return find_or(std::forward(tab).at(ky), std::forward(keys)...); -} - -// --------------------------------------------------------------------------- -// recursive find_or with explicit type specialization, find_or(value, keys...) - -template 1), std::nullptr_t> = nullptr> - // here we need to add SFINAE in the template parameter to avoid - // infinite recursion in type deduction on gcc -auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys) - -> decltype(find_or(std::forward(v), ky, detail::last_one(std::forward(keys)...))) -{ - if(!v.is_table()) - { - return detail::last_one(std::forward(keys)...); - } - auto&& tab = std::forward(v).as_table(); - if(tab.count(ky) == 0) - { - return detail::last_one(std::forward(keys)...); - } - return find_or(std::forward(tab).at(ky), std::forward(keys)...); -} - -// ============================================================================ -// expect - -template class M, template class V> -result expect(const basic_value& v) noexcept -{ - try - { - return ok(get(v)); - } - catch(const std::exception& e) - { - return err(e.what()); - } -} -template class M, template class V> -result -expect(const basic_value& v, const toml::key& k) noexcept -{ - try - { - return ok(find(v, k)); - } - catch(const std::exception& e) - { - return err(e.what()); - } -} - -} // toml -#endif// TOML11_GET diff --git a/src/frontend/qt_sdl/toml/toml/lexer.hpp b/src/frontend/qt_sdl/toml/toml/lexer.hpp deleted file mode 100644 index ea5050b8..00000000 --- a/src/frontend/qt_sdl/toml/toml/lexer.hpp +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_LEXER_HPP -#define TOML11_LEXER_HPP -#include -#include -#include -#include - -#include "combinator.hpp" - -namespace toml -{ -namespace detail -{ - -// these scans contents from current location in a container of char -// and extract a region that matches their own pattern. -// to see the implementation of each component, see combinator.hpp. - -using lex_wschar = either, character<'\t'>>; -using lex_ws = repeat>; -using lex_newline = either, - sequence, character<'\n'>>>; -using lex_lower = in_range<'a', 'z'>; -using lex_upper = in_range<'A', 'Z'>; -using lex_alpha = either; -using lex_digit = in_range<'0', '9'>; -using lex_nonzero = in_range<'1', '9'>; -using lex_oct_dig = in_range<'0', '7'>; -using lex_bin_dig = in_range<'0', '1'>; -using lex_hex_dig = either, in_range<'a', 'f'>>; - -using lex_hex_prefix = sequence, character<'x'>>; -using lex_oct_prefix = sequence, character<'o'>>; -using lex_bin_prefix = sequence, character<'b'>>; -using lex_underscore = character<'_'>; -using lex_plus = character<'+'>; -using lex_minus = character<'-'>; -using lex_sign = either; - -// digit | nonzero 1*(digit | _ digit) -using lex_unsigned_dec_int = either>, at_least<1>>>, - lex_digit>; -// (+|-)? unsigned_dec_int -using lex_dec_int = sequence, lex_unsigned_dec_int>; - -// hex_prefix hex_dig *(hex_dig | _ hex_dig) -using lex_hex_int = sequence>, unlimited>>>; -// oct_prefix oct_dig *(oct_dig | _ oct_dig) -using lex_oct_int = sequence>, unlimited>>>; -// bin_prefix bin_dig *(bin_dig | _ bin_dig) -using lex_bin_int = sequence>, unlimited>>>; - -// (dec_int | hex_int | oct_int | bin_int) -using lex_integer = either; - -// =========================================================================== - -using lex_inf = sequence, character<'n'>, character<'f'>>; -using lex_nan = sequence, character<'a'>, character<'n'>>; -using lex_special_float = sequence, either>; - -using lex_zero_prefixable_int = sequence>, unlimited>>; - -using lex_fractional_part = sequence, lex_zero_prefixable_int>; - -using lex_exponent_part = sequence, character<'E'>>, - maybe, lex_zero_prefixable_int>; - -using lex_float = either>>>>; - -// =========================================================================== - -using lex_true = sequence, character<'r'>, - character<'u'>, character<'e'>>; -using lex_false = sequence, character<'a'>, character<'l'>, - character<'s'>, character<'e'>>; -using lex_boolean = either; - -// =========================================================================== - -using lex_date_fullyear = repeat>; -using lex_date_month = repeat>; -using lex_date_mday = repeat>; -using lex_time_delim = either, character<'t'>, character<' '>>; -using lex_time_hour = repeat>; -using lex_time_minute = repeat>; -using lex_time_second = repeat>; -using lex_time_secfrac = sequence, - repeat>>; - -using lex_time_numoffset = sequence, character<'-'>>, - sequence, - lex_time_minute>>; -using lex_time_offset = either, character<'z'>, - lex_time_numoffset>; - -using lex_partial_time = sequence, - lex_time_minute, character<':'>, - lex_time_second, maybe>; -using lex_full_date = sequence, - lex_date_month, character<'-'>, - lex_date_mday>; -using lex_full_time = sequence; - -using lex_offset_date_time = sequence; -using lex_local_date_time = sequence; -using lex_local_date = lex_full_date; -using lex_local_time = lex_partial_time; - -// =========================================================================== - -using lex_quotation_mark = character<'"'>; -using lex_basic_unescaped = exclude, // 0x09 (tab) is allowed - in_range<0x0A, 0x1F>, - character<0x22>, character<0x5C>, - character<0x7F>>>; - -using lex_escape = character<'\\'>; -using lex_escape_unicode_short = sequence, - repeat>>; -using lex_escape_unicode_long = sequence, - repeat>>; -using lex_escape_seq_char = either, character<'\\'>, - character<'b'>, character<'f'>, - character<'n'>, character<'r'>, - character<'t'>, - lex_escape_unicode_short, - lex_escape_unicode_long - >; -using lex_escaped = sequence; -using lex_basic_char = either; -using lex_basic_string = sequence, - lex_quotation_mark>; - -// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings -// are allowed to be used. -// After this, the following strings are *explicitly* allowed. -// - One or two `"`s in a multi-line basic string is allowed wherever it is. -// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter. -// - One or two `"`s can appear just before or after the delimiter. -// ```toml -// str4 = """Here are two quotation marks: "". Simple enough.""" -// str5 = """Here are three quotation marks: ""\".""" -// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" -// str7 = """"This," she said, "is just a pointless statement."""" -// ``` -// In the current implementation (v3.3.0), it is difficult to parse `str7` in -// the above example. It is difficult to recognize `"` at the end of string body -// collectly. It will be misunderstood as a `"""` delimiter and an additional, -// invalid `"`. Like this: -// ```console -// what(): [error] toml::parse_table: invalid line format -// --> hoge.toml -// | -// 13 | str7 = """"This," she said, "is just a pointless statement."""" -// | ^- expected newline, but got '"'. -// ``` -// As a quick workaround for this problem, `lex_ml_basic_string_delim` was -// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`. -// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s. -// In parse_ml_basic_string() function, the trailing `"`s will be attached to -// the string body. -// -using lex_ml_basic_string_delim = repeat>; -using lex_ml_basic_string_open = lex_ml_basic_string_delim; -using lex_ml_basic_string_close = sequence< - repeat>, - maybe, maybe - >; - -using lex_ml_basic_unescaped = exclude, // 0x09 is tab - in_range<0x0A, 0x1F>, - character<0x5C>, // backslash - character<0x7F>, // DEL - lex_ml_basic_string_delim>>; - -using lex_ml_basic_escaped_newline = sequence< - lex_escape, maybe, lex_newline, - repeat, unlimited>>; - -using lex_ml_basic_char = either; -using lex_ml_basic_body = repeat, - unlimited>; -using lex_ml_basic_string = sequence; - -using lex_literal_char = exclude, in_range<0x0A, 0x1F>, - character<0x7F>, character<0x27>>>; -using lex_apostrophe = character<'\''>; -using lex_literal_string = sequence, - lex_apostrophe>; - -// the same reason as above. -using lex_ml_literal_string_delim = repeat>; -using lex_ml_literal_string_open = lex_ml_literal_string_delim; -using lex_ml_literal_string_close = sequence< - repeat>, - maybe, maybe - >; - -using lex_ml_literal_char = exclude, - in_range<0x0A, 0x1F>, - character<0x7F>, - lex_ml_literal_string_delim>>; -using lex_ml_literal_body = repeat, - unlimited>; -using lex_ml_literal_string = sequence; - -using lex_string = either; - -// =========================================================================== -using lex_dot_sep = sequence, character<'.'>, maybe>; - -using lex_unquoted_key = repeat, character<'_'>>, - at_least<1>>; -using lex_quoted_key = either; -using lex_simple_key = either; -using lex_dotted_key = sequence, - at_least<1> - > - >; -using lex_key = either; - -using lex_keyval_sep = sequence, - character<'='>, - maybe>; - -using lex_std_table_open = character<'['>; -using lex_std_table_close = character<']'>; -using lex_std_table = sequence, - lex_key, - maybe, - lex_std_table_close>; - -using lex_array_table_open = sequence; -using lex_array_table_close = sequence; -using lex_array_table = sequence, - lex_key, - maybe, - lex_array_table_close>; - -using lex_utf8_1byte = in_range<0x00, 0x7F>; -using lex_utf8_2byte = sequence< - in_range(0xC2), static_cast(0xDF)>, - in_range(0x80), static_cast(0xBF)> - >; -using lex_utf8_3byte = sequence(0xE0)>, in_range(0xA0), static_cast(0xBF)>>, - sequence(0xE1), static_cast(0xEC)>, in_range(0x80), static_cast(0xBF)>>, - sequence(0xED)>, in_range(0x80), static_cast(0x9F)>>, - sequence(0xEE), static_cast(0xEF)>, in_range(0x80), static_cast(0xBF)>> - >, in_range(0x80), static_cast(0xBF)>>; -using lex_utf8_4byte = sequence(0xF0)>, in_range(0x90), static_cast(0xBF)>>, - sequence(0xF1), static_cast(0xF3)>, in_range(0x80), static_cast(0xBF)>>, - sequence(0xF4)>, in_range(0x80), static_cast(0x8F)>> - >, in_range(0x80), static_cast(0xBF)>, - in_range(0x80), static_cast(0xBF)>>; -using lex_utf8_code = either< - lex_utf8_1byte, - lex_utf8_2byte, - lex_utf8_3byte, - lex_utf8_4byte - >; - -using lex_comment_start_symbol = character<'#'>; -using lex_non_eol_ascii = either, in_range<0x20, 0x7E>>; -using lex_comment = sequence, unlimited>>; - -} // detail -} // toml -#endif // TOML_LEXER_HPP diff --git a/src/frontend/qt_sdl/toml/toml/literal.hpp b/src/frontend/qt_sdl/toml/toml/literal.hpp deleted file mode 100644 index 04fbbc13..00000000 --- a/src/frontend/qt_sdl/toml/toml/literal.hpp +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. -#ifndef TOML11_LITERAL_HPP -#define TOML11_LITERAL_HPP -#include "parser.hpp" - -namespace toml -{ -inline namespace literals -{ -inline namespace toml_literals -{ - -// implementation -inline ::toml::basic_value -literal_internal_impl(::toml::detail::location loc) -{ - using value_type = ::toml::basic_value< - TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>; - // if there are some comments or empty lines, skip them. - using skip_line = ::toml::detail::repeat, - ::toml::detail::maybe<::toml::detail::lex_comment>, - ::toml::detail::lex_newline - >, ::toml::detail::at_least<1>>; - skip_line::invoke(loc); - - // if there are some whitespaces before a value, skip them. - using skip_ws = ::toml::detail::repeat< - ::toml::detail::lex_ws, ::toml::detail::at_least<1>>; - skip_ws::invoke(loc); - - // to distinguish arrays and tables, first check it is a table or not. - // - // "[1,2,3]"_toml; // this is an array - // "[table]"_toml; // a table that has an empty table named "table" inside. - // "[[1,2,3]]"_toml; // this is an array of arrays - // "[[table]]"_toml; // this is a table that has an array of tables inside. - // - // "[[1]]"_toml; // this can be both... (currently it becomes a table) - // "1 = [{}]"_toml; // this is a table that has an array of table named 1. - // "[[1,]]"_toml; // this is an array of arrays. - // "[[1],]"_toml; // this also. - - const auto the_front = loc.iter(); - - const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc); - loc.reset(the_front); - - const bool is_aots_key = ::toml::detail::lex_array_table::invoke(loc); - loc.reset(the_front); - - // If it is neither a table-key or a array-of-table-key, it may be a value. - if(!is_table_key && !is_aots_key) - { - if(auto data = ::toml::detail::parse_value(loc)) - { - return data.unwrap(); - } - } - - // Note that still it can be a table, because the literal might be something - // like the following. - // ```cpp - // R"( // c++11 raw string literals - // key = "value" - // int = 42 - // )"_toml; - // ``` - // It is a valid toml file. - // It should be parsed as if we parse a file with this content. - - if(auto data = ::toml::detail::parse_toml_file(loc)) - { - return data.unwrap(); - } - else // none of them. - { - throw ::toml::syntax_error(data.unwrap_err(), source_location(loc)); - } - -} - -inline ::toml::basic_value -operator"" _toml(const char* str, std::size_t len) -{ - ::toml::detail::location loc( - std::string("TOML literal encoded in a C++ code"), - std::vector(str, str + len)); - // literal length does not include the null character at the end. - return literal_internal_impl(std::move(loc)); -} - -// value of __cplusplus in C++2a/20 mode is not fixed yet along compilers. -// So here we use the feature test macro for `char8_t` itself. -#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L -// value of u8"" literal has been changed from char to char8_t and char8_t is -// NOT compatible to char -inline ::toml::basic_value -operator"" _toml(const char8_t* str, std::size_t len) -{ - ::toml::detail::location loc( - std::string("TOML literal encoded in a C++ code"), - std::vector(reinterpret_cast(str), - reinterpret_cast(str) + len)); - return literal_internal_impl(std::move(loc)); -} -#endif - -} // toml_literals -} // literals -} // toml -#endif//TOML11_LITERAL_HPP diff --git a/src/frontend/qt_sdl/toml/toml/parser.hpp b/src/frontend/qt_sdl/toml/toml/parser.hpp deleted file mode 100644 index bfa5531f..00000000 --- a/src/frontend/qt_sdl/toml/toml/parser.hpp +++ /dev/null @@ -1,2416 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_PARSER_HPP -#define TOML11_PARSER_HPP -#include -#include -#include - -#include "combinator.hpp" -#include "lexer.hpp" -#include "region.hpp" -#include "result.hpp" -#include "types.hpp" -#include "value.hpp" - -#ifndef TOML11_DISABLE_STD_FILESYSTEM -#ifdef __cpp_lib_filesystem -#if __has_include() -#define TOML11_HAS_STD_FILESYSTEM -#include -#endif // has_include() -#endif // __cpp_lib_filesystem -#endif // TOML11_DISABLE_STD_FILESYSTEM - -namespace toml -{ -namespace detail -{ - -inline result, std::string> -parse_boolean(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_boolean::invoke(loc)) - { - const auto reg = token.unwrap(); - if (reg.str() == "true") {return ok(std::make_pair(true, reg));} - else if(reg.str() == "false") {return ok(std::make_pair(false, reg));} - else // internal error. - { - throw internal_error(format_underline( - "toml::parse_boolean: internal error", - {{source_location(reg), "invalid token"}}), - source_location(reg)); - } - } - loc.reset(first); //rollback - return err(format_underline("toml::parse_boolean: ", - {{source_location(loc), "the next token is not a boolean"}})); -} - -inline result, std::string> -parse_binary_integer(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_bin_int::invoke(loc)) - { - auto str = token.unwrap().str(); - assert(str.size() > 2); // minimum -> 0b1 - integer retval(0), base(1); - for(auto i(str.rbegin()), e(str.rend() - 2); i!=e; ++i) - { - if (*i == '1'){retval += base; base *= 2;} - else if(*i == '0'){base *= 2;} - else if(*i == '_'){/* do nothing. */} - else // internal error. - { - throw internal_error(format_underline( - "toml::parse_integer: internal error", - {{source_location(token.unwrap()), "invalid token"}}), - source_location(loc)); - } - } - return ok(std::make_pair(retval, token.unwrap())); - } - loc.reset(first); - return err(format_underline("toml::parse_binary_integer:", - {{source_location(loc), "the next token is not an integer"}})); -} - -inline result, std::string> -parse_octal_integer(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_oct_int::invoke(loc)) - { - auto str = token.unwrap().str(); - str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); - str.erase(str.begin()); str.erase(str.begin()); // remove `0o` prefix - - std::istringstream iss(str); - integer retval(0); - iss >> std::oct >> retval; - return ok(std::make_pair(retval, token.unwrap())); - } - loc.reset(first); - return err(format_underline("toml::parse_octal_integer:", - {{source_location(loc), "the next token is not an integer"}})); -} - -inline result, std::string> -parse_hexadecimal_integer(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_hex_int::invoke(loc)) - { - auto str = token.unwrap().str(); - str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); - str.erase(str.begin()); str.erase(str.begin()); // remove `0x` prefix - - std::istringstream iss(str); - integer retval(0); - iss >> std::hex >> retval; - return ok(std::make_pair(retval, token.unwrap())); - } - loc.reset(first); - return err(format_underline("toml::parse_hexadecimal_integer", - {{source_location(loc), "the next token is not an integer"}})); -} - -inline result, std::string> -parse_integer(location& loc) -{ - const auto first = loc.iter(); - if(first != loc.end() && *first == '0') - { - const auto second = std::next(first); - if(second == loc.end()) // the token is just zero. - { - loc.advance(); - return ok(std::make_pair(0, region(loc, first, second))); - } - - if(*second == 'b') {return parse_binary_integer (loc);} // 0b1100 - if(*second == 'o') {return parse_octal_integer (loc);} // 0o775 - if(*second == 'x') {return parse_hexadecimal_integer(loc);} // 0xC0FFEE - - if(std::isdigit(*second)) - { - return err(format_underline("toml::parse_integer: " - "leading zero in an Integer is not allowed.", - {{source_location(loc), "leading zero"}})); - } - else if(std::isalpha(*second)) - { - return err(format_underline("toml::parse_integer: " - "unknown integer prefix appeared.", - {{source_location(loc), "none of 0x, 0o, 0b"}})); - } - } - - if(const auto token = lex_dec_int::invoke(loc)) - { - auto str = token.unwrap().str(); - str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); - - std::istringstream iss(str); - integer retval(0); - iss >> retval; - return ok(std::make_pair(retval, token.unwrap())); - } - loc.reset(first); - return err(format_underline("toml::parse_integer: ", - {{source_location(loc), "the next token is not an integer"}})); -} - -inline result, std::string> -parse_floating(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_float::invoke(loc)) - { - auto str = token.unwrap().str(); - if(str == "inf" || str == "+inf") - { - if(std::numeric_limits::has_infinity) - { - return ok(std::make_pair( - std::numeric_limits::infinity(), token.unwrap())); - } - else - { - throw std::domain_error("toml::parse_floating: inf value found" - " but the current environment does not support inf. Please" - " make sure that the floating-point implementation conforms" - " IEEE 754/ISO 60559 international standard."); - } - } - else if(str == "-inf") - { - if(std::numeric_limits::has_infinity) - { - return ok(std::make_pair( - -std::numeric_limits::infinity(), token.unwrap())); - } - else - { - throw std::domain_error("toml::parse_floating: inf value found" - " but the current environment does not support inf. Please" - " make sure that the floating-point implementation conforms" - " IEEE 754/ISO 60559 international standard."); - } - } - else if(str == "nan" || str == "+nan") - { - if(std::numeric_limits::has_quiet_NaN) - { - return ok(std::make_pair( - std::numeric_limits::quiet_NaN(), token.unwrap())); - } - else if(std::numeric_limits::has_signaling_NaN) - { - return ok(std::make_pair( - std::numeric_limits::signaling_NaN(), token.unwrap())); - } - else - { - throw std::domain_error("toml::parse_floating: NaN value found" - " but the current environment does not support NaN. Please" - " make sure that the floating-point implementation conforms" - " IEEE 754/ISO 60559 international standard."); - } - } - else if(str == "-nan") - { - if(std::numeric_limits::has_quiet_NaN) - { - return ok(std::make_pair( - -std::numeric_limits::quiet_NaN(), token.unwrap())); - } - else if(std::numeric_limits::has_signaling_NaN) - { - return ok(std::make_pair( - -std::numeric_limits::signaling_NaN(), token.unwrap())); - } - else - { - throw std::domain_error("toml::parse_floating: NaN value found" - " but the current environment does not support NaN. Please" - " make sure that the floating-point implementation conforms" - " IEEE 754/ISO 60559 international standard."); - } - } - str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); - std::istringstream iss(str); - floating v(0.0); - iss >> v; - return ok(std::make_pair(v, token.unwrap())); - } - loc.reset(first); - return err(format_underline("toml::parse_floating: ", - {{source_location(loc), "the next token is not a float"}})); -} - -inline std::string read_utf8_codepoint(const region& reg, const location& loc) -{ - const auto str = reg.str().substr(1); - std::uint_least32_t codepoint; - std::istringstream iss(str); - iss >> std::hex >> codepoint; - - const auto to_char = [](const std::uint_least32_t i) noexcept -> char { - const auto uc = static_cast(i); - return *reinterpret_cast(std::addressof(uc)); - }; - - std::string character; - if(codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII. - { - character += static_cast(codepoint); - } - else if(codepoint < 0x800) //U+0080 ... U+07FF - { - // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 - character += to_char(0xC0| codepoint >> 6); - character += to_char(0x80|(codepoint & 0x3F)); - } - else if(codepoint < 0x10000) // U+0800...U+FFFF - { - if(0xD800 <= codepoint && codepoint <= 0xDFFF) - { - throw syntax_error(format_underline( - "toml::read_utf8_codepoint: codepoints in the range " - "[0xD800, 0xDFFF] are not valid UTF-8.", {{ - source_location(loc), "not a valid UTF-8 codepoint" - }}), source_location(loc)); - } - assert(codepoint < 0xD800 || 0xDFFF < codepoint); - // 1110yyyy 10yxxxxx 10xxxxxx - character += to_char(0xE0| codepoint >> 12); - character += to_char(0x80|(codepoint >> 6 & 0x3F)); - character += to_char(0x80|(codepoint & 0x3F)); - } - else if(codepoint < 0x110000) // U+010000 ... U+10FFFF - { - // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx - character += to_char(0xF0| codepoint >> 18); - character += to_char(0x80|(codepoint >> 12 & 0x3F)); - character += to_char(0x80|(codepoint >> 6 & 0x3F)); - character += to_char(0x80|(codepoint & 0x3F)); - } - else // out of UTF-8 region - { - throw syntax_error(format_underline("toml::read_utf8_codepoint:" - " input codepoint is too large.", - {{source_location(loc), "should be in [0x00..0x10FFFF]"}}), - source_location(loc)); - } - return character; -} - -inline result parse_escape_sequence(location& loc) -{ - const auto first = loc.iter(); - if(first == loc.end() || *first != '\\') - { - return err(format_underline("toml::parse_escape_sequence: ", {{ - source_location(loc), "the next token is not a backslash \"\\\""}})); - } - loc.advance(); - switch(*loc.iter()) - { - case '\\':{loc.advance(); return ok(std::string("\\"));} - case '"' :{loc.advance(); return ok(std::string("\""));} - case 'b' :{loc.advance(); return ok(std::string("\b"));} - case 't' :{loc.advance(); return ok(std::string("\t"));} - case 'n' :{loc.advance(); return ok(std::string("\n"));} - case 'f' :{loc.advance(); return ok(std::string("\f"));} - case 'r' :{loc.advance(); return ok(std::string("\r"));} - case 'u' : - { - if(const auto token = lex_escape_unicode_short::invoke(loc)) - { - return ok(read_utf8_codepoint(token.unwrap(), loc)); - } - else - { - return err(format_underline("parse_escape_sequence: " - "invalid token found in UTF-8 codepoint uXXXX.", - {{source_location(loc), "here"}})); - } - } - case 'U': - { - if(const auto token = lex_escape_unicode_long::invoke(loc)) - { - return ok(read_utf8_codepoint(token.unwrap(), loc)); - } - else - { - return err(format_underline("parse_escape_sequence: " - "invalid token found in UTF-8 codepoint Uxxxxxxxx", - {{source_location(loc), "here"}})); - } - } - } - - const auto msg = format_underline("parse_escape_sequence: " - "unknown escape sequence appeared.", {{source_location(loc), - "escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}}, - /* Hints = */{"if you want to write backslash as just one backslash, " - "use literal string like: regex = '<\\i\\c*\\s*>'"}); - loc.reset(first); - return err(msg); -} - -inline std::ptrdiff_t check_utf8_validity(const std::string& reg) -{ - location loc("tmp", reg); - const auto u8 = repeat::invoke(loc); - if(!u8 || loc.iter() != loc.end()) - { - const auto error_location = std::distance(loc.begin(), loc.iter()); - assert(0 <= error_location); - return error_location; - } - return -1; -} - -inline result, std::string> -parse_ml_basic_string(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_ml_basic_string::invoke(loc)) - { - auto inner_loc = loc; - inner_loc.reset(first); - - std::string retval; - retval.reserve(token.unwrap().size()); - - auto delim = lex_ml_basic_string_open::invoke(inner_loc); - if(!delim) - { - throw internal_error(format_underline( - "parse_ml_basic_string: invalid token", - {{source_location(inner_loc), "should be \"\"\""}}), - source_location(inner_loc)); - } - // immediate newline is ignored (if exists) - /* discard return value */ lex_newline::invoke(inner_loc); - - delim = none(); - while(!delim) - { - using lex_unescaped_seq = repeat< - either, unlimited>; - if(auto unescaped = lex_unescaped_seq::invoke(inner_loc)) - { - retval += unescaped.unwrap().str(); - } - if(auto escaped = parse_escape_sequence(inner_loc)) - { - retval += escaped.unwrap(); - } - if(auto esc_nl = lex_ml_basic_escaped_newline::invoke(inner_loc)) - { - // ignore newline after escape until next non-ws char - } - if(inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "parse_ml_basic_string: unexpected end of region", - {{source_location(inner_loc), "not sufficient token"}}), - source_location(inner_loc)); - } - delim = lex_ml_basic_string_close::invoke(inner_loc); - } - // `lex_ml_basic_string_close` allows 3 to 5 `"`s to allow 1 or 2 `"`s - // at just before the delimiter. Here, we need to attach `"`s at the - // end of the string body, if it exists. - // For detail, see the definition of `lex_ml_basic_string_close`. - assert(std::all_of(delim.unwrap().first(), delim.unwrap().last(), - [](const char c) noexcept {return c == '\"';})); - switch(delim.unwrap().size()) - { - case 3: {break;} - case 4: {retval += "\""; break;} - case 5: {retval += "\"\""; break;} - default: - { - throw internal_error(format_underline( - "parse_ml_basic_string: closing delimiter has invalid length", - {{source_location(inner_loc), "end of this"}}), - source_location(inner_loc)); - } - } - - const auto err_loc = check_utf8_validity(token.unwrap().str()); - if(err_loc == -1) - { - return ok(std::make_pair(toml::string(retval), token.unwrap())); - } - else - { - inner_loc.reset(first); - inner_loc.advance(err_loc); - throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - } - else - { - loc.reset(first); - return err(format_underline("toml::parse_ml_basic_string: " - "the next token is not a valid multiline string", - {{source_location(loc), "here"}})); - } -} - -inline result, std::string> -parse_basic_string(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_basic_string::invoke(loc)) - { - auto inner_loc = loc; - inner_loc.reset(first); - - auto quot = lex_quotation_mark::invoke(inner_loc); - if(!quot) - { - throw internal_error(format_underline("parse_basic_string: " - "invalid token", {{source_location(inner_loc), "should be \""}}), - source_location(inner_loc)); - } - - std::string retval; - retval.reserve(token.unwrap().size()); - - quot = none(); - while(!quot) - { - using lex_unescaped_seq = repeat; - if(auto unescaped = lex_unescaped_seq::invoke(inner_loc)) - { - retval += unescaped.unwrap().str(); - } - if(auto escaped = parse_escape_sequence(inner_loc)) - { - retval += escaped.unwrap(); - } - if(inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "parse_basic_string: unexpected end of region", - {{source_location(inner_loc), "not sufficient token"}}), - source_location(inner_loc)); - } - quot = lex_quotation_mark::invoke(inner_loc); - } - - const auto err_loc = check_utf8_validity(token.unwrap().str()); - if(err_loc == -1) - { - return ok(std::make_pair(toml::string(retval), token.unwrap())); - } - else - { - inner_loc.reset(first); - inner_loc.advance(err_loc); - throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - } - else - { - loc.reset(first); // rollback - return err(format_underline("toml::parse_basic_string: " - "the next token is not a valid string", - {{source_location(loc), "here"}})); - } -} - -inline result, std::string> -parse_ml_literal_string(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_ml_literal_string::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto open = lex_ml_literal_string_open::invoke(inner_loc); - if(!open) - { - throw internal_error(format_underline( - "parse_ml_literal_string: invalid token", - {{source_location(inner_loc), "should be '''"}}), - source_location(inner_loc)); - } - // immediate newline is ignored (if exists) - /* discard return value */ lex_newline::invoke(inner_loc); - - const auto body = lex_ml_literal_body::invoke(inner_loc); - - const auto close = lex_ml_literal_string_close::invoke(inner_loc); - if(!close) - { - throw internal_error(format_underline( - "parse_ml_literal_string: invalid token", - {{source_location(inner_loc), "should be '''"}}), - source_location(inner_loc)); - } - // `lex_ml_literal_string_close` allows 3 to 5 `'`s to allow 1 or 2 `'`s - // at just before the delimiter. Here, we need to attach `'`s at the - // end of the string body, if it exists. - // For detail, see the definition of `lex_ml_basic_string_close`. - - std::string retval = body.unwrap().str(); - assert(std::all_of(close.unwrap().first(), close.unwrap().last(), - [](const char c) noexcept {return c == '\'';})); - switch(close.unwrap().size()) - { - case 3: {break;} - case 4: {retval += "'"; break;} - case 5: {retval += "''"; break;} - default: - { - throw internal_error(format_underline( - "parse_ml_literal_string: closing delimiter has invalid length", - {{source_location(inner_loc), "end of this"}}), - source_location(inner_loc)); - } - } - - const auto err_loc = check_utf8_validity(token.unwrap().str()); - if(err_loc == -1) - { - return ok(std::make_pair(toml::string(retval, toml::string_t::literal), - token.unwrap())); - } - else - { - inner_loc.reset(first); - inner_loc.advance(err_loc); - throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - } - else - { - loc.reset(first); // rollback - return err(format_underline("toml::parse_ml_literal_string: " - "the next token is not a valid multiline literal string", - {{source_location(loc), "here"}})); - } -} - -inline result, std::string> -parse_literal_string(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_literal_string::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto open = lex_apostrophe::invoke(inner_loc); - if(!open) - { - throw internal_error(format_underline( - "parse_literal_string: invalid token", - {{source_location(inner_loc), "should be '"}}), - source_location(inner_loc)); - } - - const auto body = repeat::invoke(inner_loc); - - const auto close = lex_apostrophe::invoke(inner_loc); - if(!close) - { - throw internal_error(format_underline( - "parse_literal_string: invalid token", - {{source_location(inner_loc), "should be '"}}), - source_location(inner_loc)); - } - - const auto err_loc = check_utf8_validity(token.unwrap().str()); - if(err_loc == -1) - { - return ok(std::make_pair( - toml::string(body.unwrap().str(), toml::string_t::literal), - token.unwrap())); - } - else - { - inner_loc.reset(first); - inner_loc.advance(err_loc); - throw syntax_error(format_underline( - "parse_ml_basic_string: invalid utf8 sequence found", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - } - else - { - loc.reset(first); // rollback - return err(format_underline("toml::parse_literal_string: " - "the next token is not a valid literal string", - {{source_location(loc), "here"}})); - } -} - -inline result, std::string> -parse_string(location& loc) -{ - if(loc.iter() != loc.end() && *(loc.iter()) == '"') - { - if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '"' && - loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '"') - { - return parse_ml_basic_string(loc); - } - else - { - return parse_basic_string(loc); - } - } - else if(loc.iter() != loc.end() && *(loc.iter()) == '\'') - { - if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '\'' && - loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '\'') - { - return parse_ml_literal_string(loc); - } - else - { - return parse_literal_string(loc); - } - } - return err(format_underline("toml::parse_string: ", - {{source_location(loc), "the next token is not a string"}})); -} - -inline result, std::string> -parse_local_date(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_local_date::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto y = lex_date_fullyear::invoke(inner_loc); - if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') - { - throw internal_error(format_underline( - "toml::parse_inner_local_date: invalid year format", - {{source_location(inner_loc), "should be `-`"}}), - source_location(inner_loc)); - } - inner_loc.advance(); - const auto m = lex_date_month::invoke(inner_loc); - if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') - { - throw internal_error(format_underline( - "toml::parse_local_date: invalid month format", - {{source_location(inner_loc), "should be `-`"}}), - source_location(inner_loc)); - } - inner_loc.advance(); - const auto d = lex_date_mday::invoke(inner_loc); - if(!d) - { - throw internal_error(format_underline( - "toml::parse_local_date: invalid day format", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - - const auto year = static_cast(from_string(y.unwrap().str(), 0)); - const auto month = static_cast(from_string(m.unwrap().str(), 0)); - const auto day = static_cast(from_string(d.unwrap().str(), 0)); - - // We briefly check whether the input date is valid or not. But here, we - // only check if the RFC3339 compliance. - // Actually there are several special date that does not exist, - // because of historical reasons, such as 1582/10/5-1582/10/14 (only in - // several countries). But here, we do not care about such a complicated - // rule. It makes the code complicated and there is only low probability - // that such a specific date is needed in practice. If someone need to - // validate date accurately, that means that the one need a specialized - // library for their purpose in a different layer. - { - const bool is_leap = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); - const auto max_day = (month == 2) ? (is_leap ? 29 : 28) : - ((month == 4 || month == 6 || month == 9 || month == 11) ? 30 : 31); - - if((month < 1 || 12 < month) || (day < 1 || max_day < day)) - { - throw syntax_error(format_underline("toml::parse_date: " - "invalid date: it does not conform RFC3339.", {{ - source_location(loc), "month should be 01-12, day should be" - " 01-28,29,30,31, depending on month/year." - }}), source_location(inner_loc)); - } - } - return ok(std::make_pair(local_date(year, static_cast(month - 1), day), - token.unwrap())); - } - else - { - loc.reset(first); - return err(format_underline("toml::parse_local_date: ", - {{source_location(loc), "the next token is not a local_date"}})); - } -} - -inline result, std::string> -parse_local_time(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_local_time::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto h = lex_time_hour::invoke(inner_loc); - if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') - { - throw internal_error(format_underline( - "toml::parse_local_time: invalid year format", - {{source_location(inner_loc), "should be `:`"}}), - source_location(inner_loc)); - } - inner_loc.advance(); - const auto m = lex_time_minute::invoke(inner_loc); - if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') - { - throw internal_error(format_underline( - "toml::parse_local_time: invalid month format", - {{source_location(inner_loc), "should be `:`"}}), - source_location(inner_loc)); - } - inner_loc.advance(); - const auto s = lex_time_second::invoke(inner_loc); - if(!s) - { - throw internal_error(format_underline( - "toml::parse_local_time: invalid second format", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - - const int hour = from_string(h.unwrap().str(), 0); - const int minute = from_string(m.unwrap().str(), 0); - const int second = from_string(s.unwrap().str(), 0); - - if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute) || - (second < 0 || 60 < second)) // it may be leap second - { - throw syntax_error(format_underline("toml::parse_time: " - "invalid time: it does not conform RFC3339.", {{ - source_location(loc), "hour should be 00-23, minute should be" - " 00-59, second should be 00-60 (depending on the leap" - " second rules.)"}}), source_location(inner_loc)); - } - - local_time time(hour, minute, second, 0, 0); - - const auto before_secfrac = inner_loc.iter(); - if(const auto secfrac = lex_time_secfrac::invoke(inner_loc)) - { - auto sf = secfrac.unwrap().str(); - sf.erase(sf.begin()); // sf.front() == '.' - switch(sf.size() % 3) - { - case 2: sf += '0'; break; - case 1: sf += "00"; break; - case 0: break; - default: break; - } - if(sf.size() >= 9) - { - time.millisecond = from_string(sf.substr(0, 3), 0u); - time.microsecond = from_string(sf.substr(3, 3), 0u); - time.nanosecond = from_string(sf.substr(6, 3), 0u); - } - else if(sf.size() >= 6) - { - time.millisecond = from_string(sf.substr(0, 3), 0u); - time.microsecond = from_string(sf.substr(3, 3), 0u); - } - else if(sf.size() >= 3) - { - time.millisecond = from_string(sf, 0u); - time.microsecond = 0u; - } - } - else - { - if(before_secfrac != inner_loc.iter()) - { - throw internal_error(format_underline( - "toml::parse_local_time: invalid subsecond format", - {{source_location(inner_loc), "here"}}), - source_location(inner_loc)); - } - } - return ok(std::make_pair(time, token.unwrap())); - } - else - { - loc.reset(first); - return err(format_underline("toml::parse_local_time: ", - {{source_location(loc), "the next token is not a local_time"}})); - } -} - -inline result, std::string> -parse_local_datetime(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_local_date_time::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - const auto date = parse_local_date(inner_loc); - if(!date || inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "toml::parse_local_datetime: invalid datetime format", - {{source_location(inner_loc), "date, not datetime"}}), - source_location(inner_loc)); - } - const char delim = *(inner_loc.iter()); - if(delim != 'T' && delim != 't' && delim != ' ') - { - throw internal_error(format_underline( - "toml::parse_local_datetime: invalid datetime format", - {{source_location(inner_loc), "should be `T` or ` ` (space)"}}), - source_location(inner_loc)); - } - inner_loc.advance(); - const auto time = parse_local_time(inner_loc); - if(!time) - { - throw internal_error(format_underline( - "toml::parse_local_datetime: invalid datetime format", - {{source_location(inner_loc), "invalid time format"}}), - source_location(inner_loc)); - } - return ok(std::make_pair( - local_datetime(date.unwrap().first, time.unwrap().first), - token.unwrap())); - } - else - { - loc.reset(first); - return err(format_underline("toml::parse_local_datetime: ", - {{source_location(loc), "the next token is not a local_datetime"}})); - } -} - -inline result, std::string> -parse_offset_datetime(location& loc) -{ - const auto first = loc.iter(); - if(const auto token = lex_offset_date_time::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - const auto datetime = parse_local_datetime(inner_loc); - if(!datetime || inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "toml::parse_offset_datetime: invalid datetime format", - {{source_location(inner_loc), "date, not datetime"}}), - source_location(inner_loc)); - } - time_offset offset(0, 0); - if(const auto ofs = lex_time_numoffset::invoke(inner_loc)) - { - const auto str = ofs.unwrap().str(); - - const auto hour = from_string(str.substr(1,2), 0); - const auto minute = from_string(str.substr(4,2), 0); - - if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute)) - { - throw syntax_error(format_underline("toml::parse_offset_datetime: " - "invalid offset: it does not conform RFC3339.", {{ - source_location(loc), "month should be 01-12, day should be" - " 01-28,29,30,31, depending on month/year." - }}), source_location(inner_loc)); - } - - if(str.front() == '+') - { - offset = time_offset(hour, minute); - } - else - { - offset = time_offset(-hour, -minute); - } - } - else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z') - { - throw internal_error(format_underline( - "toml::parse_offset_datetime: invalid datetime format", - {{source_location(inner_loc), "should be `Z` or `+HH:MM`"}}), - source_location(inner_loc)); - } - return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset), - token.unwrap())); - } - else - { - loc.reset(first); - return err(format_underline("toml::parse_offset_datetime: ", - {{source_location(loc), "the next token is not a offset_datetime"}})); - } -} - -inline result, std::string> -parse_simple_key(location& loc) -{ - if(const auto bstr = parse_basic_string(loc)) - { - return ok(std::make_pair(bstr.unwrap().first.str, bstr.unwrap().second)); - } - if(const auto lstr = parse_literal_string(loc)) - { - return ok(std::make_pair(lstr.unwrap().first.str, lstr.unwrap().second)); - } - if(const auto bare = lex_unquoted_key::invoke(loc)) - { - const auto reg = bare.unwrap(); - return ok(std::make_pair(reg.str(), reg)); - } - return err(format_underline("toml::parse_simple_key: ", - {{source_location(loc), "the next token is not a simple key"}})); -} - -// dotted key become vector of keys -inline result, region>, std::string> -parse_key(location& loc) -{ - const auto first = loc.iter(); - // dotted key -> `foo.bar.baz` where several single keys are chained by - // dots. Whitespaces between keys and dots are allowed. - if(const auto token = lex_dotted_key::invoke(loc)) - { - const auto reg = token.unwrap(); - location inner_loc(loc.name(), reg.str()); - std::vector keys; - - while(inner_loc.iter() != inner_loc.end()) - { - lex_ws::invoke(inner_loc); - if(const auto k = parse_simple_key(inner_loc)) - { - keys.push_back(k.unwrap().first); - } - else - { - throw internal_error(format_underline( - "toml::detail::parse_key: dotted key contains invalid key", - {{source_location(inner_loc), k.unwrap_err()}}), - source_location(inner_loc)); - } - - lex_ws::invoke(inner_loc); - if(inner_loc.iter() == inner_loc.end()) - { - break; - } - else if(*inner_loc.iter() == '.') - { - inner_loc.advance(); // to skip `.` - } - else - { - throw internal_error(format_underline("toml::parse_key: " - "dotted key contains invalid key ", - {{source_location(inner_loc), "should be `.`"}}), - source_location(inner_loc)); - } - } - return ok(std::make_pair(keys, reg)); - } - loc.reset(first); - - // simple_key: a single (basic_string|literal_string|bare key) - if(const auto smpl = parse_simple_key(loc)) - { - return ok(std::make_pair(std::vector(1, smpl.unwrap().first), - smpl.unwrap().second)); - } - return err(format_underline("toml::parse_key: an invalid key appeared.", - {{source_location(loc), "is not a valid key"}}, { - "bare keys : non-empty strings composed only of [A-Za-z0-9_-].", - "quoted keys: same as \"basic strings\" or 'literal strings'.", - "dotted keys: sequence of bare or quoted keys joined with a dot." - })); -} - -// forward-decl to implement parse_array and parse_table -template -result parse_value(location&); - -template -result, std::string> -parse_array(location& loc) -{ - using value_type = Value; - using array_type = typename value_type::array_type; - - const auto first = loc.iter(); - if(loc.iter() == loc.end()) - { - return err("toml::parse_array: input is empty"); - } - if(*loc.iter() != '[') - { - return err("toml::parse_array: token is not an array"); - } - loc.advance(); - - using lex_ws_comment_newline = repeat< - either, unlimited>; - - array_type retval; - while(loc.iter() != loc.end()) - { - lex_ws_comment_newline::invoke(loc); // skip - - if(loc.iter() != loc.end() && *loc.iter() == ']') - { - loc.advance(); // skip ']' - return ok(std::make_pair(retval, - region(loc, first, loc.iter()))); - } - - if(auto val = parse_value(loc)) - { - // After TOML v1.0.0-rc.1, array becomes to be able to have values - // with different types. So here we will omit this by default. - // - // But some of the test-suite checks if the parser accepts a hetero- - // geneous arrays, so we keep this for a while. -#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS - if(!retval.empty() && retval.front().type() != val.as_ok().type()) - { - auto array_start_loc = loc; - array_start_loc.reset(first); - - throw syntax_error(format_underline("toml::parse_array: " - "type of elements should be the same each other.", { - {source_location(array_start_loc), "array starts here"}, - { - retval.front().location(), - "value has type " + stringize(retval.front().type()) - }, - { - val.unwrap().location(), - "value has different type, " + stringize(val.unwrap().type()) - } - }), source_location(loc)); - } -#endif - retval.push_back(std::move(val.unwrap())); - } - else - { - auto array_start_loc = loc; - array_start_loc.reset(first); - - throw syntax_error(format_underline("toml::parse_array: " - "value having invalid format appeared in an array", { - {source_location(array_start_loc), "array starts here"}, - {source_location(loc), "it is not a valid value."} - }), source_location(loc)); - } - - using lex_array_separator = sequence, character<','>>; - const auto sp = lex_array_separator::invoke(loc); - if(!sp) - { - lex_ws_comment_newline::invoke(loc); - if(loc.iter() != loc.end() && *loc.iter() == ']') - { - loc.advance(); // skip ']' - return ok(std::make_pair(retval, - region(loc, first, loc.iter()))); - } - else - { - auto array_start_loc = loc; - array_start_loc.reset(first); - - throw syntax_error(format_underline("toml::parse_array:" - " missing array separator `,` after a value", { - {source_location(array_start_loc), "array starts here"}, - {source_location(loc), "should be `,`"} - }), source_location(loc)); - } - } - } - loc.reset(first); - throw syntax_error(format_underline("toml::parse_array: " - "array did not closed by `]`", - {{source_location(loc), "should be closed"}}), - source_location(loc)); -} - -template -result, region>, Value>, std::string> -parse_key_value_pair(location& loc) -{ - using value_type = Value; - - const auto first = loc.iter(); - auto key_reg = parse_key(loc); - if(!key_reg) - { - std::string msg = std::move(key_reg.unwrap_err()); - // if the next token is keyvalue-separator, it means that there are no - // key. then we need to show error as "empty key is not allowed". - if(const auto keyval_sep = lex_keyval_sep::invoke(loc)) - { - loc.reset(first); - msg = format_underline("toml::parse_key_value_pair: " - "empty key is not allowed.", - {{source_location(loc), "key expected before '='"}}); - } - return err(std::move(msg)); - } - - const auto kvsp = lex_keyval_sep::invoke(loc); - if(!kvsp) - { - std::string msg; - // if the line contains '=' after the invalid sequence, possibly the - // error is in the key (like, invalid character in bare key). - const auto line_end = std::find(loc.iter(), loc.end(), '\n'); - if(std::find(loc.iter(), line_end, '=') != line_end) - { - msg = format_underline("toml::parse_key_value_pair: " - "invalid format for key", - {{source_location(loc), "invalid character in key"}}, - {"Did you forget '.' to separate dotted-key?", - "Allowed characters for bare key are [0-9a-zA-Z_-]."}); - } - else // if not, the error is lack of key-value separator. - { - msg = format_underline("toml::parse_key_value_pair: " - "missing key-value separator `=`", - {{source_location(loc), "should be `=`"}}); - } - loc.reset(first); - return err(std::move(msg)); - } - - const auto after_kvsp = loc.iter(); // err msg - auto val = parse_value(loc); - if(!val) - { - std::string msg; - loc.reset(after_kvsp); - // check there is something not a comment/whitespace after `=` - if(sequence, maybe, lex_newline>::invoke(loc)) - { - loc.reset(after_kvsp); - msg = format_underline("toml::parse_key_value_pair: " - "missing value after key-value separator '='", - {{source_location(loc), "expected value, but got nothing"}}); - } - else // there is something not a comment/whitespace, so invalid format. - { - msg = std::move(val.unwrap_err()); - } - loc.reset(first); - return err(msg); - } - return ok(std::make_pair(std::move(key_reg.unwrap()), - std::move(val.unwrap()))); -} - -// for error messages. -template -std::string format_dotted_keys(InputIterator first, const InputIterator last) -{ - static_assert(std::is_same::value_type>::value,""); - - std::string retval(*first++); - for(; first != last; ++first) - { - retval += '.'; - retval += *first; - } - return retval; -} - -// forward decl for is_valid_forward_table_definition -result, region>, std::string> -parse_table_key(location& loc); -template -result, std::string> -parse_inline_table(location& loc); - -// The following toml file is allowed. -// ```toml -// [a.b.c] # here, table `a` has element `b`. -// foo = "bar" -// [a] # merge a = {baz = "qux"} to a = {b = {...}} -// baz = "qux" -// ``` -// But the following is not allowed. -// ```toml -// [a] -// b.c.foo = "bar" -// [a] # error! the same table [a] defined! -// baz = "qux" -// ``` -// The following is neither allowed. -// ```toml -// a = { b.c.foo = "bar"} -// [a] # error! the same table [a] defined! -// baz = "qux" -// ``` -// Here, it parses region of `tab->at(k)` as a table key and check the depth -// of the key. If the key region points deeper node, it would be allowed. -// Otherwise, the key points the same node. It would be rejected. -template -bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, - Iterator key_first, Iterator key_curr, Iterator key_last) -{ - // ------------------------------------------------------------------------ - // check type of the value to be inserted/merged - - std::string inserting_reg = ""; - if(const auto ptr = detail::get_region(inserting)) - { - inserting_reg = ptr->str(); - } - location inserting_def("internal", std::move(inserting_reg)); - if(const auto inlinetable = parse_inline_table(inserting_def)) - { - // check if we are overwriting existing table. - // ```toml - // # NG - // a.b = 42 - // a = {d = 3.14} - // ``` - // Inserting an inline table to a existing super-table is not allowed in - // any case. If we found it, we can reject it without further checking. - return false; - } - - // Valid and invalid cases when inserting to the [a.b] table: - // - // ## Invalid - // - // ```toml - // # invalid - // [a] - // b.c.d = "foo" - // [a.b] # a.b is already defined and closed - // d = "bar" - // ``` - // ```toml - // # invalid - // a = {b.c.d = "foo"} - // [a.b] # a is already defined and inline table is closed - // d = "bar" - // ``` - // ```toml - // # invalid - // a.b.c.d = "foo" - // [a.b] # a.b is already defined and dotted-key table is closed - // d = "bar" - // ``` - // - // ## Valid - // - // ```toml - // # OK. a.b is defined, but is *overwritable* - // [a.b.c] - // d = "foo" - // [a.b] - // d = "bar" - // ``` - // ```toml - // # OK. a.b is defined, but is *overwritable* - // [a] - // b.c.d = "foo" - // b.e = "bar" - // ``` - - // ------------------------------------------------------------------------ - // check table defined before - - std::string internal = ""; - if(const auto ptr = detail::get_region(fwd)) - { - internal = ptr->str(); - } - location def("internal", std::move(internal)); - if(const auto tabkeys = parse_table_key(def)) // [table.key] - { - // table keys always contains all the nodes from the root. - const auto& tks = tabkeys.unwrap().first; - if(std::size_t(std::distance(key_first, key_last)) == tks.size() && - std::equal(tks.begin(), tks.end(), key_first)) - { - // the keys are equivalent. it is not allowed. - return false; - } - // the keys are not equivalent. it is allowed. - return true; - } - if(const auto dotkeys = parse_key(def)) // a.b.c = "foo" - { - // consider the following case. - // [a] - // b.c = {d = 42} - // [a.b.c] - // e = 2.71 - // this defines the table [a.b.c] twice. no? - if(const auto reopening_dotkey_by_table = parse_table_key(inserting_def)) - { - // re-opening a dotkey-defined table by a table is invalid. - // only dotkey can append a key-val. Like: - // ```toml - // a.b.c = "foo" - // a.b.d = "bar" # OK. reopen `a.b` by dotkey - // [a.b] - // e = "bar" # Invalid. re-opening `a.b` by [a.b] is not allowed. - // ``` - return false; - } - - // a dotted key starts from the node representing a table in which the - // dotted key belongs to. - const auto& dks = dotkeys.unwrap().first; - if(std::size_t(std::distance(key_curr, key_last)) == dks.size() && - std::equal(dks.begin(), dks.end(), key_curr)) - { - // the keys are equivalent. it is not allowed. - return false; - } - // the keys are not equivalent. it is allowed. - return true; - } - return false; -} - -template -result -insert_nested_key(typename Value::table_type& root, const Value& v, - InputIterator iter, const InputIterator last, - region key_reg, - const bool is_array_of_table = false) -{ - static_assert(std::is_same::value_type>::value,""); - - using value_type = Value; - using table_type = typename value_type::table_type; - using array_type = typename value_type::array_type; - - const auto first = iter; - assert(iter != last); - - table_type* tab = std::addressof(root); - for(; iter != last; ++iter) // search recursively - { - const key& k = *iter; - if(std::next(iter) == last) // k is the last key - { - // XXX if the value is array-of-tables, there can be several - // tables that are in the same array. in that case, we need to - // find the last element and insert it to there. - if(is_array_of_table) - { - if(tab->count(k) == 1) // there is already an array of table - { - if(tab->at(k).is_table()) - { - // show special err msg for conflicting table - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of table (\"", - format_dotted_keys(first, last), - "\") cannot be defined"), { - {tab->at(k).location(), "table already defined"}, - {v.location(), "this conflicts with the previous table"} - }), v.location()); - } - else if(!(tab->at(k).is_array())) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of table (\"", - format_dotted_keys(first, last), "\") collides with" - " existing value"), { - {tab->at(k).location(), - concat_to_string("this ", tab->at(k).type(), - " value already exists")}, - {v.location(), - "while inserting this array-of-tables"} - }), v.location()); - } - // the above if-else-if checks tab->at(k) is an array - auto& a = tab->at(k).as_array(); - // If table element is defined as [[array_of_tables]], it - // cannot be an empty array. If an array of tables is - // defined as `aot = []`, it cannot be appended. - if(a.empty() || !(a.front().is_table())) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of table (\"", - format_dotted_keys(first, last), "\") collides with" - " existing value"), { - {tab->at(k).location(), - concat_to_string("this ", tab->at(k).type(), - " value already exists")}, - {v.location(), - "while inserting this array-of-tables"} - }), v.location()); - } - // avoid conflicting array of table like the following. - // ```toml - // a = [{b = 42}] # define a as an array of *inline* tables - // [[a]] # a is an array of *multi-line* tables - // b = 54 - // ``` - // Here, from the type information, these cannot be detected - // because inline table is also a table. - // But toml v0.5.0 explicitly says it is invalid. The above - // array-of-tables has a static size and appending to the - // array is invalid. - // In this library, multi-line table value has a region - // that points to the key of the table (e.g. [[a]]). By - // comparing the first two letters in key, we can detect - // the array-of-table is inline or multiline. - if(const auto ptr = detail::get_region(a.front())) - { - if(ptr->str().substr(0,2) != "[[") - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of table (\"", - format_dotted_keys(first, last), "\") collides " - "with existing array-of-tables"), { - {tab->at(k).location(), - concat_to_string("this ", tab->at(k).type(), - " value has static size")}, - {v.location(), - "appending it to the statically sized array"} - }), v.location()); - } - } - a.push_back(v); - return ok(true); - } - else // if not, we need to create the array of table - { - // XXX: Consider the following array of tables. - // ```toml - // # This is a comment. - // [[aot]] - // foo = "bar" - // ``` - // Here, the comment is for `aot`. But here, actually two - // values are defined. An array that contains tables, named - // `aot`, and the 0th element of the `aot`, `{foo = "bar"}`. - // Those two are different from each other. But both of them - // points to the same portion of the TOML file, `[[aot]]`, - // so `key_reg.comments()` returns `# This is a comment`. - // If it is assigned as a comment of `aot` defined here, the - // comment will be duplicated. Both the `aot` itself and - // the 0-th element will have the same comment. This causes - // "duplication of the same comments" bug when the data is - // serialized. - // Next, consider the following. - // ```toml - // # comment 1 - // aot = [ - // # comment 2 - // {foo = "bar"}, - // ] - // ``` - // In this case, we can distinguish those two comments. So - // here we need to add "comment 1" to the `aot` and - // "comment 2" to the 0th element of that. - // To distinguish those two, we check the key region. - std::vector comments{/* empty by default */}; - if(key_reg.str().substr(0, 2) != "[[") - { - comments = key_reg.comments(); - } - value_type aot(array_type(1, v), key_reg, std::move(comments)); - tab->insert(std::make_pair(k, aot)); - return ok(true); - } - } // end if(array of table) - - if(tab->count(k) == 1) - { - if(tab->at(k).is_table() && v.is_table()) - { - if(!is_valid_forward_table_definition( - tab->at(k), v, first, iter, last)) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: table (\"", - format_dotted_keys(first, last), - "\") already exists."), { - {tab->at(k).location(), "table already exists here"}, - {v.location(), "table defined twice"} - }), v.location()); - } - // to allow the following toml file. - // [a.b.c] - // d = 42 - // [a] - // e = 2.71 - auto& t = tab->at(k).as_table(); - for(const auto& kv : v.as_table()) - { - if(tab->at(k).contains(kv.first)) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: value (\"", - format_dotted_keys(first, last), - "\") already exists."), { - {t.at(kv.first).location(), "already exists here"}, - {v.location(), "this defined twice"} - }), v.location()); - } - t[kv.first] = kv.second; - } - detail::change_region(tab->at(k), key_reg); - return ok(true); - } - else if(v.is_table() && - tab->at(k).is_array() && - tab->at(k).as_array().size() > 0 && - tab->at(k).as_array().front().is_table()) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: array of tables (\"", - format_dotted_keys(first, last), "\") already exists."), { - {tab->at(k).location(), "array of tables defined here"}, - {v.location(), "table conflicts with the previous array of table"} - }), v.location()); - } - else - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: value (\"", - format_dotted_keys(first, last), "\") already exists."), { - {tab->at(k).location(), "value already exists here"}, - {v.location(), "value defined twice"} - }), v.location()); - } - } - tab->insert(std::make_pair(k, v)); - return ok(true); - } - else // k is not the last one, we should insert recursively - { - // if there is no corresponding value, insert it first. - // related: you don't need to write - // # [x] - // # [x.y] - // to write - // [x.y.z] - if(tab->count(k) == 0) - { - // a table that is defined implicitly doesn't have any comments. - (*tab)[k] = value_type(table_type{}, key_reg, {/*no comment*/}); - } - - // type checking... - if(tab->at(k).is_table()) - { - // According to toml-lang/toml:36d3091b3 "Clarify that inline - // tables are immutable", check if it adds key-value pair to an - // inline table. - if(const auto* ptr = get_region(tab->at(k))) - { - // here, if the value is a (multi-line) table, the region - // should be something like `[table-name]`. - if(ptr->front() == '{') - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: inserting to an inline table (", - format_dotted_keys(first, std::next(iter)), - ") but inline tables are immutable"), { - {tab->at(k).location(), "inline tables are immutable"}, - {v.location(), "inserting this"} - }), v.location()); - } - } - tab = std::addressof((*tab)[k].as_table()); - } - else if(tab->at(k).is_array()) // inserting to array-of-tables? - { - auto& a = (*tab)[k].as_array(); - if(!a.back().is_table()) - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: target (", - format_dotted_keys(first, std::next(iter)), - ") is neither table nor an array of tables"), { - {a.back().location(), concat_to_string( - "actual type is ", a.back().type())}, - {v.location(), "inserting this"} - }), v.location()); - } - tab = std::addressof(a.back().as_table()); - } - else - { - throw syntax_error(format_underline(concat_to_string( - "toml::insert_value: target (", - format_dotted_keys(first, std::next(iter)), - ") is neither table nor an array of tables"), { - {tab->at(k).location(), concat_to_string( - "actual type is ", tab->at(k).type())}, - {v.location(), "inserting this"} - }), v.location()); - } - } - } - return err(std::string("toml::detail::insert_nested_key: never reach here")); -} - -template -result, std::string> -parse_inline_table(location& loc) -{ - using value_type = Value; - using table_type = typename value_type::table_type; - - const auto first = loc.iter(); - table_type retval; - if(!(loc.iter() != loc.end() && *loc.iter() == '{')) - { - return err(format_underline("toml::parse_inline_table: ", - {{source_location(loc), "the next token is not an inline table"}})); - } - loc.advance(); - - // check if the inline table is an empty table = { } - maybe::invoke(loc); - if(loc.iter() != loc.end() && *loc.iter() == '}') - { - loc.advance(); // skip `}` - return ok(std::make_pair(retval, region(loc, first, loc.iter()))); - } - - // it starts from "{". it should be formatted as inline-table - while(loc.iter() != loc.end()) - { - const auto kv_r = parse_key_value_pair(loc); - if(!kv_r) - { - return err(kv_r.unwrap_err()); - } - - const auto& kvpair = kv_r.unwrap(); - const std::vector& keys = kvpair.first.first; - const auto& key_reg = kvpair.first.second; - const value_type& val = kvpair.second; - - const auto inserted = - insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg); - if(!inserted) - { - throw internal_error("toml::parse_inline_table: " - "failed to insert value into table: " + inserted.unwrap_err(), - source_location(loc)); - } - - using lex_table_separator = sequence, character<','>>; - const auto sp = lex_table_separator::invoke(loc); - - if(!sp) - { - maybe::invoke(loc); - - if(loc.iter() == loc.end()) - { - throw syntax_error(format_underline( - "toml::parse_inline_table: missing table separator `}` ", - {{source_location(loc), "should be `}`"}}), - source_location(loc)); - } - else if(*loc.iter() == '}') - { - loc.advance(); // skip `}` - return ok(std::make_pair( - retval, region(loc, first, loc.iter()))); - } - else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n') - { - throw syntax_error(format_underline( - "toml::parse_inline_table: missing curly brace `}`", - {{source_location(loc), "should be `}`"}}), - source_location(loc)); - } - else - { - throw syntax_error(format_underline( - "toml::parse_inline_table: missing table separator `,` ", - {{source_location(loc), "should be `,`"}}), - source_location(loc)); - } - } - else // `,` is found - { - maybe::invoke(loc); - if(loc.iter() != loc.end() && *loc.iter() == '}') - { - throw syntax_error(format_underline( - "toml::parse_inline_table: trailing comma is not allowed in" - " an inline table", - {{source_location(loc), "should be `}`"}}), - source_location(loc)); - } - } - } - loc.reset(first); - throw syntax_error(format_underline("toml::parse_inline_table: " - "inline table did not closed by `}`", - {{source_location(loc), "should be closed"}}), - source_location(loc)); -} - -inline result guess_number_type(const location& l) -{ - // This function tries to find some (common) mistakes by checking characters - // that follows the last character of a value. But it is often difficult - // because some non-newline characters can appear after a value. E.g. - // spaces, tabs, commas (in an array or inline table), closing brackets - // (of an array or inline table), comment-sign (#). Since this function - // does not parse further, those characters are always allowed to be there. - location loc = l; - - if(lex_offset_date_time::invoke(loc)) {return ok(value_t::offset_datetime);} - loc.reset(l.iter()); - - if(lex_local_date_time::invoke(loc)) - { - // bad offset may appear after this. - if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-' - || *loc.iter() == 'Z' || *loc.iter() == 'z')) - { - return err(format_underline("bad offset: should be [+-]HH:MM or Z", - {{source_location(loc), "[+-]HH:MM or Z"}}, - {"pass: +09:00, -05:30", "fail: +9:00, -5:30"})); - } - return ok(value_t::local_datetime); - } - loc.reset(l.iter()); - - if(lex_local_date::invoke(loc)) - { - // bad time may appear after this. - // A space is allowed as a delimiter between local time. But there are - // both cases in which a space becomes valid or invalid. - // - invalid: 2019-06-16 7:00:00 - // - valid : 2019-06-16 07:00:00 - if(loc.iter() != loc.end()) - { - const auto c = *loc.iter(); - if(c == 'T' || c == 't') - { - return err(format_underline("bad time: should be HH:MM:SS.subsec", - {{source_location(loc), "HH:MM:SS.subsec"}}, - {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", - "fail: 1979-05-27T7:32:00, 1979-05-27 17:32"})); - } - if('0' <= c && c <= '9') - { - return err(format_underline("bad time: missing T", - {{source_location(loc), "T or space required here"}}, - {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", - "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); - } - if(c == ' ' && std::next(loc.iter()) != loc.end() && - ('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9')) - { - loc.advance(); - return err(format_underline("bad time: should be HH:MM:SS.subsec", - {{source_location(loc), "HH:MM:SS.subsec"}}, - {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", - "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); - } - } - return ok(value_t::local_date); - } - loc.reset(l.iter()); - - if(lex_local_time::invoke(loc)) {return ok(value_t::local_time);} - loc.reset(l.iter()); - - if(lex_float::invoke(loc)) - { - if(loc.iter() != loc.end() && *loc.iter() == '_') - { - return err(format_underline("bad float: `_` should be surrounded by digits", - {{source_location(loc), "here"}}, - {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", - "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); - } - return ok(value_t::floating); - } - loc.reset(l.iter()); - - if(lex_integer::invoke(loc)) - { - if(loc.iter() != loc.end()) - { - const auto c = *loc.iter(); - if(c == '_') - { - return err(format_underline("bad integer: `_` should be surrounded by digits", - {{source_location(loc), "here"}}, - {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", - "fail: 1__000, 0123"})); - } - if('0' <= c && c <= '9') - { - // leading zero. point '0' - loc.retrace(); - return err(format_underline("bad integer: leading zero", - {{source_location(loc), "here"}}, - {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", - "fail: 1__000, 0123"})); - } - if(c == ':' || c == '-') - { - return err(format_underline("bad datetime: invalid format", - {{source_location(loc), "here"}}, - {"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z", - "fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"})); - } - if(c == '.' || c == 'e' || c == 'E') - { - return err(format_underline("bad float: invalid format", - {{source_location(loc), "here"}}, - {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", - "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); - } - } - return ok(value_t::integer); - } - if(loc.iter() != loc.end() && *loc.iter() == '.') - { - return err(format_underline("bad float: invalid format", - {{source_location(loc), "integer part required before this"}}, - {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", - "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); - } - if(loc.iter() != loc.end() && *loc.iter() == '_') - { - return err(format_underline("bad number: `_` should be surrounded by digits", - {{source_location(loc), "`_` is not surrounded by digits"}}, - {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", - "fail: 1__000, 0123"})); - } - return err(format_underline("bad format: unknown value appeared", - {{source_location(loc), "here"}})); -} - -inline result guess_value_type(const location& loc) -{ - switch(*loc.iter()) - { - case '"' : {return ok(value_t::string); } - case '\'': {return ok(value_t::string); } - case 't' : {return ok(value_t::boolean); } - case 'f' : {return ok(value_t::boolean); } - case '[' : {return ok(value_t::array); } - case '{' : {return ok(value_t::table); } - case 'i' : {return ok(value_t::floating);} // inf. - case 'n' : {return ok(value_t::floating);} // nan. - default : {return guess_number_type(loc);} - } -} - -template -result -parse_value_helper(result, std::string> rslt) -{ - if(rslt.is_ok()) - { - auto comments = rslt.as_ok().second.comments(); - return ok(Value(std::move(rslt.as_ok()), std::move(comments))); - } - else - { - return err(std::move(rslt.as_err())); - } -} - -template -result parse_value(location& loc) -{ - const auto first = loc.iter(); - if(first == loc.end()) - { - return err(format_underline("toml::parse_value: input is empty", - {{source_location(loc), ""}})); - } - - const auto type = guess_value_type(loc); - if(!type) - { - return err(type.unwrap_err()); - } - - switch(type.unwrap()) - { - case value_t::boolean : {return parse_value_helper(parse_boolean(loc) );} - case value_t::integer : {return parse_value_helper(parse_integer(loc) );} - case value_t::floating : {return parse_value_helper(parse_floating(loc) );} - case value_t::string : {return parse_value_helper(parse_string(loc) );} - case value_t::offset_datetime: {return parse_value_helper(parse_offset_datetime(loc) );} - case value_t::local_datetime : {return parse_value_helper(parse_local_datetime(loc) );} - case value_t::local_date : {return parse_value_helper(parse_local_date(loc) );} - case value_t::local_time : {return parse_value_helper(parse_local_time(loc) );} - case value_t::array : {return parse_value_helper(parse_array(loc) );} - case value_t::table : {return parse_value_helper(parse_inline_table(loc));} - default: - { - const auto msg = format_underline("toml::parse_value: " - "unknown token appeared", {{source_location(loc), "unknown"}}); - loc.reset(first); - return err(msg); - } - } -} - -inline result, region>, std::string> -parse_table_key(location& loc) -{ - if(auto token = lex_std_table::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto open = lex_std_table_open::invoke(inner_loc); - if(!open || inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "toml::parse_table_key: no `[`", - {{source_location(inner_loc), "should be `[`"}}), - source_location(inner_loc)); - } - // to skip [ a . b . c ] - // ^----------- this whitespace - lex_ws::invoke(inner_loc); - const auto keys = parse_key(inner_loc); - if(!keys) - { - throw internal_error(format_underline( - "toml::parse_table_key: invalid key", - {{source_location(inner_loc), "not key"}}), - source_location(inner_loc)); - } - // to skip [ a . b . c ] - // ^-- this whitespace - lex_ws::invoke(inner_loc); - const auto close = lex_std_table_close::invoke(inner_loc); - if(!close) - { - throw internal_error(format_underline( - "toml::parse_table_key: no `]`", - {{source_location(inner_loc), "should be `]`"}}), - source_location(inner_loc)); - } - - // after [table.key], newline or EOF(empty table) required. - if(loc.iter() != loc.end()) - { - using lex_newline_after_table_key = - sequence, maybe, lex_newline>; - const auto nl = lex_newline_after_table_key::invoke(loc); - if(!nl) - { - throw syntax_error(format_underline( - "toml::parse_table_key: newline required after [table.key]", - {{source_location(loc), "expected newline"}}), - source_location(loc)); - } - } - return ok(std::make_pair(keys.unwrap().first, token.unwrap())); - } - else - { - return err(format_underline("toml::parse_table_key: " - "not a valid table key", {{source_location(loc), "here"}})); - } -} - -inline result, region>, std::string> -parse_array_table_key(location& loc) -{ - if(auto token = lex_array_table::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - - const auto open = lex_array_table_open::invoke(inner_loc); - if(!open || inner_loc.iter() == inner_loc.end()) - { - throw internal_error(format_underline( - "toml::parse_array_table_key: no `[[`", - {{source_location(inner_loc), "should be `[[`"}}), - source_location(inner_loc)); - } - lex_ws::invoke(inner_loc); - const auto keys = parse_key(inner_loc); - if(!keys) - { - throw internal_error(format_underline( - "toml::parse_array_table_key: invalid key", - {{source_location(inner_loc), "not a key"}}), - source_location(inner_loc)); - } - lex_ws::invoke(inner_loc); - const auto close = lex_array_table_close::invoke(inner_loc); - if(!close) - { - throw internal_error(format_underline( - "toml::parse_table_key: no `]]`", - {{source_location(inner_loc), "should be `]]`"}}), - source_location(inner_loc)); - } - - // after [[table.key]], newline or EOF(empty table) required. - if(loc.iter() != loc.end()) - { - using lex_newline_after_table_key = - sequence, maybe, lex_newline>; - const auto nl = lex_newline_after_table_key::invoke(loc); - if(!nl) - { - throw syntax_error(format_underline("toml::" - "parse_array_table_key: newline required after [[table.key]]", - {{source_location(loc), "expected newline"}}), - source_location(loc)); - } - } - return ok(std::make_pair(keys.unwrap().first, token.unwrap())); - } - else - { - return err(format_underline("toml::parse_array_table_key: " - "not a valid table key", {{source_location(loc), "here"}})); - } -} - -// parse table body (key-value pairs until the iter hits the next [tablekey]) -template -result -parse_ml_table(location& loc) -{ - using value_type = Value; - using table_type = typename value_type::table_type; - - const auto first = loc.iter(); - if(first == loc.end()) - { - return ok(table_type{}); - } - - // XXX at lest one newline is needed. - using skip_line = repeat< - sequence, maybe, lex_newline>, at_least<1>>; - skip_line::invoke(loc); - lex_ws::invoke(loc); - - table_type tab; - while(loc.iter() != loc.end()) - { - lex_ws::invoke(loc); - const auto before = loc.iter(); - if(const auto tmp = parse_array_table_key(loc)) // next table found - { - loc.reset(before); - return ok(tab); - } - if(const auto tmp = parse_table_key(loc)) // next table found - { - loc.reset(before); - return ok(tab); - } - - if(const auto kv = parse_key_value_pair(loc)) - { - const auto& kvpair = kv.unwrap(); - const std::vector& keys = kvpair.first.first; - const auto& key_reg = kvpair.first.second; - const value_type& val = kvpair.second; - const auto inserted = - insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg); - if(!inserted) - { - return err(inserted.unwrap_err()); - } - } - else - { - return err(kv.unwrap_err()); - } - - // comment lines are skipped by the above function call. - // However, since the `skip_line` requires at least 1 newline, it fails - // if the file ends with ws and/or comment without newline. - // `skip_line` matches `ws? + comment? + newline`, not `ws` or `comment` - // itself. To skip the last ws and/or comment, call lexers. - // It does not matter if these fails, so the return value is discarded. - lex_ws::invoke(loc); - lex_comment::invoke(loc); - - // skip_line is (whitespace? comment? newline)_{1,}. multiple empty lines - // and comments after the last key-value pairs are allowed. - const auto newline = skip_line::invoke(loc); - if(!newline && loc.iter() != loc.end()) - { - const auto before2 = loc.iter(); - lex_ws::invoke(loc); // skip whitespace - const auto msg = format_underline("toml::parse_table: " - "invalid line format", {{source_location(loc), concat_to_string( - "expected newline, but got '", show_char(*loc.iter()), "'.")}}); - loc.reset(before2); - return err(msg); - } - - // the skip_lines only matches with lines that includes newline. - // to skip the last line that includes comment and/or whitespace - // but no newline, call them one more time. - lex_ws::invoke(loc); - lex_comment::invoke(loc); - } - return ok(tab); -} - -template -result parse_toml_file(location& loc) -{ - using value_type = Value; - using table_type = typename value_type::table_type; - - const auto first = loc.iter(); - if(first == loc.end()) - { - // For empty files, return an empty table with an empty region (zero-length). - // Without the region, error messages would miss the filename. - return ok(value_type(table_type{}, region(loc, first, first), {})); - } - - // put the first line as a region of a file - // Here first != loc.end(), so taking std::next is okay - const region file(loc, first, std::next(loc.iter())); - - // The first successive comments that are separated from the first value - // by an empty line are for a file itself. - // ```toml - // # this is a comment for a file. - // - // key = "the first value" - // ``` - // ```toml - // # this is a comment for "the first value". - // key = "the first value" - // ``` - std::vector comments; - using lex_first_comments = sequence< - repeat, lex_comment, lex_newline>, at_least<1>>, - sequence, lex_newline> - >; - if(const auto token = lex_first_comments::invoke(loc)) - { - location inner_loc(loc.name(), token.unwrap().str()); - while(inner_loc.iter() != inner_loc.end()) - { - maybe::invoke(inner_loc); // remove ws if exists - if(lex_newline::invoke(inner_loc)) - { - assert(inner_loc.iter() == inner_loc.end()); - break; // empty line found. - } - auto com = lex_comment::invoke(inner_loc).unwrap().str(); - com.erase(com.begin()); // remove # sign - comments.push_back(std::move(com)); - lex_newline::invoke(inner_loc); - } - } - - table_type data; - // root object is also a table, but without [tablename] - if(const auto tab = parse_ml_table(loc)) - { - data = std::move(tab.unwrap()); - } - else // failed (empty table is regarded as success in parse_ml_table) - { - return err(tab.unwrap_err()); - } - while(loc.iter() != loc.end()) - { - // here, the region of [table] is regarded as the table-key because - // the table body is normally too big and it is not so informative - // if the first key-value pair of the table is shown in the error - // message. - if(const auto tabkey = parse_array_table_key(loc)) - { - const auto tab = parse_ml_table(loc); - if(!tab){return err(tab.unwrap_err());} - - const auto& tk = tabkey.unwrap(); - const auto& keys = tk.first; - const auto& reg = tk.second; - - const auto inserted = insert_nested_key(data, - value_type(tab.unwrap(), reg, reg.comments()), - keys.begin(), keys.end(), reg, - /*is_array_of_table=*/ true); - if(!inserted) {return err(inserted.unwrap_err());} - - continue; - } - if(const auto tabkey = parse_table_key(loc)) - { - const auto tab = parse_ml_table(loc); - if(!tab){return err(tab.unwrap_err());} - - const auto& tk = tabkey.unwrap(); - const auto& keys = tk.first; - const auto& reg = tk.second; - - const auto inserted = insert_nested_key(data, - value_type(tab.unwrap(), reg, reg.comments()), - keys.begin(), keys.end(), reg); - if(!inserted) {return err(inserted.unwrap_err());} - - continue; - } - return err(format_underline("toml::parse_toml_file: " - "unknown line appeared", {{source_location(loc), "unknown format"}})); - } - - return ok(Value(std::move(data), file, comments)); -} - -} // detail - -template class Table = std::unordered_map, - template class Array = std::vector> -basic_value -parse(std::istream& is, const std::string& fname = "unknown file") -{ - using value_type = basic_value; - - const auto beg = is.tellg(); - is.seekg(0, std::ios::end); - const auto end = is.tellg(); - const auto fsize = end - beg; - is.seekg(beg); - - // read whole file as a sequence of char - assert(fsize >= 0); - std::vector letters(static_cast(fsize)); - is.read(letters.data(), fsize); - - // append LF. - // Although TOML does not require LF at the EOF, to make parsing logic - // simpler, we "normalize" the content by adding LF if it does not exist. - // It also checks if the last char is CR, to avoid changing the meaning. - // This is not the *best* way to deal with the last character, but is a - // simple and quick fix. - if(!letters.empty() && letters.back() != '\n' && letters.back() != '\r') - { - letters.push_back('\n'); - } - - detail::location loc(std::move(fname), std::move(letters)); - - // skip BOM if exists. - // XXX component of BOM (like 0xEF) exceeds the representable range of - // signed char, so on some (actually, most) of the environment, these cannot - // be compared to char. However, since we are always out of luck, we need to - // check our chars are equivalent to BOM. To do this, first we need to - // convert char to unsigned char to guarantee the comparability. - if(loc.source()->size() >= 3) - { - std::array BOM; - std::memcpy(BOM.data(), loc.source()->data(), 3); - if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF) - { - loc.advance(3); // BOM found. skip. - } - } - - const auto data = detail::parse_toml_file(loc); - if(!data) - { - throw syntax_error(data.unwrap_err(), source_location(loc)); - } - return data.unwrap(); -} - -template class Table = std::unordered_map, - template class Array = std::vector> -basic_value parse(const std::string& fname) -{ - std::ifstream ifs(fname.c_str(), std::ios_base::binary); - if(!ifs.good()) - { - throw std::runtime_error("toml::parse: file open error -> " + fname); - } - return parse(ifs, fname); -} - -#ifdef TOML11_HAS_STD_FILESYSTEM -// This function just forwards `parse("filename.toml")` to std::string version -// to avoid the ambiguity in overload resolution. -// -// Both std::string and std::filesystem::path are convertible from const char*. -// Without this, both parse(std::string) and parse(std::filesystem::path) -// matches to parse("filename.toml"). This breaks the existing code. -// -// This function exactly matches to the invocation with c-string. -// So this function is preferred than others and the ambiguity disappears. -template class Table = std::unordered_map, - template class Array = std::vector> -basic_value parse(const char* fname) -{ - return parse(std::string(fname)); -} - -template class Table = std::unordered_map, - template class Array = std::vector> -basic_value parse(const std::filesystem::path& fpath) -{ - std::ifstream ifs(fpath, std::ios_base::binary); - if(!ifs.good()) - { - throw std::runtime_error("toml::parse: file open error -> " + - fpath.string()); - } - return parse(ifs, fpath.string()); -} -#endif // TOML11_HAS_STD_FILESYSTEM - -} // toml -#endif// TOML11_PARSER_HPP diff --git a/src/frontend/qt_sdl/toml/toml/region.hpp b/src/frontend/qt_sdl/toml/toml/region.hpp deleted file mode 100644 index 2e01e51d..00000000 --- a/src/frontend/qt_sdl/toml/toml/region.hpp +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_REGION_HPP -#define TOML11_REGION_HPP -#include -#include -#include -#include -#include -#include -#include -#include "color.hpp" - -namespace toml -{ -namespace detail -{ - -// helper function to avoid std::string(0, 'c') or std::string(iter, iter) -template -std::string make_string(Iterator first, Iterator last) -{ - if(first == last) {return "";} - return std::string(first, last); -} -inline std::string make_string(std::size_t len, char c) -{ - if(len == 0) {return "";} - return std::string(len, c); -} - -// region_base is a base class of location and region that are defined below. -// it will be used to generate better error messages. -struct region_base -{ - region_base() = default; - virtual ~region_base() = default; - region_base(const region_base&) = default; - region_base(region_base&& ) = default; - region_base& operator=(const region_base&) = default; - region_base& operator=(region_base&& ) = default; - - virtual bool is_ok() const noexcept {return false;} - virtual char front() const noexcept {return '\0';} - - virtual std::string str() const {return std::string("unknown region");} - virtual std::string name() const {return std::string("unknown file");} - virtual std::string line() const {return std::string("unknown line");} - virtual std::string line_num() const {return std::string("?");} - - // length of the region - virtual std::size_t size() const noexcept {return 0;} - // number of characters in the line before the region - virtual std::size_t before() const noexcept {return 0;} - // number of characters in the line after the region - virtual std::size_t after() const noexcept {return 0;} - - virtual std::vector comments() const {return {};} - // ```toml - // # comment_before - // key = "value" # comment_inline - // ``` -}; - -// location represents a position in a container, which contains a file content. -// it can be considered as a region that contains only one character. -// -// it contains pointer to the file content and iterator that points the current -// location. -struct location final : public region_base -{ - using const_iterator = typename std::vector::const_iterator; - using difference_type = typename const_iterator::difference_type; - using source_ptr = std::shared_ptr>; - - location(std::string source_name, std::vector cont) - : source_(std::make_shared>(std::move(cont))), - line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin()) - {} - location(std::string source_name, const std::string& cont) - : source_(std::make_shared>(cont.begin(), cont.end())), - line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin()) - {} - - location(const location&) = default; - location(location&&) = default; - location& operator=(const location&) = default; - location& operator=(location&&) = default; - ~location() = default; - - bool is_ok() const noexcept override {return static_cast(source_);} - char front() const noexcept override {return *iter_;} - - // this const prohibits codes like `++(loc.iter())`. - const const_iterator iter() const noexcept {return iter_;} - - const_iterator begin() const noexcept {return source_->cbegin();} - const_iterator end() const noexcept {return source_->cend();} - - // XXX `location::line_num()` used to be implemented using `std::count` to - // count a number of '\n'. But with a long toml file (typically, 10k lines), - // it becomes intolerably slow because each time it generates error messages, - // it counts '\n' from thousands of characters. To workaround it, I decided - // to introduce `location::line_number_` member variable and synchronize it - // to the location changes the point to look. So an overload of `iter()` - // which returns mutable reference is removed and `advance()`, `retrace()` - // and `reset()` is added. - void advance(difference_type n = 1) noexcept - { - this->line_number_ += static_cast( - std::count(this->iter_, std::next(this->iter_, n), '\n')); - this->iter_ += n; - return; - } - void retrace(difference_type n = 1) noexcept - { - this->line_number_ -= static_cast( - std::count(std::prev(this->iter_, n), this->iter_, '\n')); - this->iter_ -= n; - return; - } - void reset(const_iterator rollback) noexcept - { - // since c++11, std::distance works in both ways for random-access - // iterators and returns a negative value if `first > last`. - if(0 <= std::distance(rollback, this->iter_)) // rollback < iter - { - this->line_number_ -= static_cast( - std::count(rollback, this->iter_, '\n')); - } - else // iter < rollback [[unlikely]] - { - this->line_number_ += static_cast( - std::count(this->iter_, rollback, '\n')); - } - this->iter_ = rollback; - return; - } - - std::string str() const override {return make_string(1, *this->iter());} - std::string name() const override {return source_name_;} - - std::string line_num() const override - { - return std::to_string(this->line_number_); - } - - std::string line() const override - { - return make_string(this->line_begin(), this->line_end()); - } - - const_iterator line_begin() const noexcept - { - using reverse_iterator = std::reverse_iterator; - return std::find(reverse_iterator(this->iter()), - reverse_iterator(this->begin()), '\n').base(); - } - const_iterator line_end() const noexcept - { - return std::find(this->iter(), this->end(), '\n'); - } - - // location is always points a character. so the size is 1. - std::size_t size() const noexcept override - { - return 1u; - } - std::size_t before() const noexcept override - { - const auto sz = std::distance(this->line_begin(), this->iter()); - assert(sz >= 0); - return static_cast(sz); - } - std::size_t after() const noexcept override - { - const auto sz = std::distance(this->iter(), this->line_end()); - assert(sz >= 0); - return static_cast(sz); - } - - source_ptr const& source() const& noexcept {return source_;} - source_ptr&& source() && noexcept {return std::move(source_);} - - private: - - source_ptr source_; - std::size_t line_number_; - std::string source_name_; - const_iterator iter_; -}; - -// region represents a range in a container, which contains a file content. -// -// it contains pointer to the file content and iterator that points the first -// and last location. -struct region final : public region_base -{ - using const_iterator = typename std::vector::const_iterator; - using source_ptr = std::shared_ptr>; - - // delete default constructor. source_ never be null. - region() = delete; - - explicit region(const location& loc) - : source_(loc.source()), source_name_(loc.name()), - first_(loc.iter()), last_(loc.iter()) - {} - explicit region(location&& loc) - : source_(loc.source()), source_name_(loc.name()), - first_(loc.iter()), last_(loc.iter()) - {} - - region(const location& loc, const_iterator f, const_iterator l) - : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l) - {} - region(location&& loc, const_iterator f, const_iterator l) - : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l) - {} - - region(const region&) = default; - region(region&&) = default; - region& operator=(const region&) = default; - region& operator=(region&&) = default; - ~region() = default; - - region& operator+=(const region& other) - { - // different regions cannot be concatenated - assert(this->begin() == other.begin() && this->end() == other.end() && - this->last_ == other.first_); - - this->last_ = other.last_; - return *this; - } - - bool is_ok() const noexcept override {return static_cast(source_);} - char front() const noexcept override {return *first_;} - - std::string str() const override {return make_string(first_, last_);} - std::string line() const override - { - if(this->contain_newline()) - { - return make_string(this->line_begin(), - std::find(this->line_begin(), this->last(), '\n')); - } - return make_string(this->line_begin(), this->line_end()); - } - std::string line_num() const override - { - return std::to_string(1 + std::count(this->begin(), this->first(), '\n')); - } - - std::size_t size() const noexcept override - { - const auto sz = std::distance(first_, last_); - assert(sz >= 0); - return static_cast(sz); - } - std::size_t before() const noexcept override - { - const auto sz = std::distance(this->line_begin(), this->first()); - assert(sz >= 0); - return static_cast(sz); - } - std::size_t after() const noexcept override - { - const auto sz = std::distance(this->last(), this->line_end()); - assert(sz >= 0); - return static_cast(sz); - } - - bool contain_newline() const noexcept - { - return std::find(this->first(), this->last(), '\n') != this->last(); - } - - const_iterator line_begin() const noexcept - { - using reverse_iterator = std::reverse_iterator; - return std::find(reverse_iterator(this->first()), - reverse_iterator(this->begin()), '\n').base(); - } - const_iterator line_end() const noexcept - { - return std::find(this->last(), this->end(), '\n'); - } - - const_iterator begin() const noexcept {return source_->cbegin();} - const_iterator end() const noexcept {return source_->cend();} - const_iterator first() const noexcept {return first_;} - const_iterator last() const noexcept {return last_;} - - source_ptr const& source() const& noexcept {return source_;} - source_ptr&& source() && noexcept {return std::move(source_);} - - std::string name() const override {return source_name_;} - - std::vector comments() const override - { - // assuming the current region (`*this`) points a value. - // ```toml - // a = "value" - // ^^^^^^^- this region - // ``` - using rev_iter = std::reverse_iterator; - - std::vector com{}; - { - // find comments just before the current region. - // ```toml - // # this should be collected. - // # this also. - // a = value # not this. - // ``` - - // # this is a comment for `a`, not array elements. - // a = [1, 2, 3, 4, 5] - if(this->first() == std::find_if(this->line_begin(), this->first(), - [](const char c) noexcept -> bool {return c == '[' || c == '{';})) - { - auto iter = this->line_begin(); // points the first character - while(iter != this->begin()) - { - iter = std::prev(iter); - - // range [line_start, iter) represents the previous line - const auto line_start = std::find( - rev_iter(iter), rev_iter(this->begin()), '\n').base(); - const auto comment_found = std::find(line_start, iter, '#'); - if(comment_found == iter) - { - break; // comment not found. - } - - // exclude the following case. - // > a = "foo" # comment // <-- this is not a comment for b but a. - // > b = "current value" - if(std::all_of(line_start, comment_found, - [](const char c) noexcept -> bool { - return c == ' ' || c == '\t'; - })) - { - // unwrap the first '#' by std::next. - auto s = make_string(std::next(comment_found), iter); - if(!s.empty() && s.back() == '\r') {s.pop_back();} - com.push_back(std::move(s)); - } - else - { - break; - } - iter = line_start; - } - } - } - - if(com.size() > 1) - { - std::reverse(com.begin(), com.end()); - } - - { - // find comments just after the current region. - // ```toml - // # not this. - // a = value # this one. - // a = [ # not this (technically difficult) - // - // ] # and this. - // ``` - // The reason why it's difficult is that it requires parsing in the - // following case. - // ```toml - // a = [ 10 # this comment is for `10`. not for `a` but `a[0]`. - // # ... - // ] # this is apparently a comment for a. - // - // b = [ - // 3.14 ] # there is no way to add a comment to `3.14` currently. - // - // c = [ - // 3.14 # do this if you need a comment here. - // ] - // ``` - const auto comment_found = - std::find(this->last(), this->line_end(), '#'); - if(comment_found != this->line_end()) // '#' found - { - // table = {key = "value"} # what is this for? - // the above comment is not for "value", but {key="value"}. - if(comment_found == std::find_if(this->last(), comment_found, - [](const char c) noexcept -> bool { - return !(c == ' ' || c == '\t' || c == ','); - })) - { - // unwrap the first '#' by std::next. - auto s = make_string(std::next(comment_found), this->line_end()); - if(!s.empty() && s.back() == '\r') {s.pop_back();} - com.push_back(std::move(s)); - } - } - } - return com; - } - - private: - - source_ptr source_; - std::string source_name_; - const_iterator first_, last_; -}; - -} // detail -} // toml -#endif// TOML11_REGION_H diff --git a/src/frontend/qt_sdl/toml/toml/result.hpp b/src/frontend/qt_sdl/toml/toml/result.hpp deleted file mode 100644 index 77cd46c6..00000000 --- a/src/frontend/qt_sdl/toml/toml/result.hpp +++ /dev/null @@ -1,717 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_RESULT_HPP -#define TOML11_RESULT_HPP -#include "traits.hpp" -#include -#include -#include -#include -#include -#include -#include - -namespace toml -{ - -template -struct success -{ - using value_type = T; - value_type value; - - explicit success(const value_type& v) - noexcept(std::is_nothrow_copy_constructible::value) - : value(v) - {} - explicit success(value_type&& v) - noexcept(std::is_nothrow_move_constructible::value) - : value(std::move(v)) - {} - - template - explicit success(U&& v): value(std::forward(v)) {} - - template - explicit success(const success& v): value(v.value) {} - template - explicit success(success&& v): value(std::move(v.value)) {} - - ~success() = default; - success(const success&) = default; - success(success&&) = default; - success& operator=(const success&) = default; - success& operator=(success&&) = default; -}; - -template -struct failure -{ - using value_type = T; - value_type value; - - explicit failure(const value_type& v) - noexcept(std::is_nothrow_copy_constructible::value) - : value(v) - {} - explicit failure(value_type&& v) - noexcept(std::is_nothrow_move_constructible::value) - : value(std::move(v)) - {} - - template - explicit failure(U&& v): value(std::forward(v)) {} - - template - explicit failure(const failure& v): value(v.value) {} - template - explicit failure(failure&& v): value(std::move(v.value)) {} - - ~failure() = default; - failure(const failure&) = default; - failure(failure&&) = default; - failure& operator=(const failure&) = default; - failure& operator=(failure&&) = default; -}; - -template -success::type>::type> -ok(T&& v) -{ - return success< - typename std::remove_cv::type>::type - >(std::forward(v)); -} -template -failure::type>::type> -err(T&& v) -{ - return failure< - typename std::remove_cv::type>::type - >(std::forward(v)); -} - -inline success ok(const char* literal) -{ - return success(std::string(literal)); -} -inline failure err(const char* literal) -{ - return failure(std::string(literal)); -} - - -template -struct result -{ - using value_type = T; - using error_type = E; - using success_type = success; - using failure_type = failure; - - result(const success_type& s): is_ok_(true) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(s); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - result(const failure_type& f): is_ok_(false) - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(f); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - result(success_type&& s): is_ok_(true) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s)); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - result(failure_type&& f): is_ok_(false) - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f)); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - - template - result(const success& s): is_ok_(true) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(s.value); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - template - result(const failure& f): is_ok_(false) - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - template - result(success&& s): is_ok_(true) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value)); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - template - result(failure&& f): is_ok_(false) - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value)); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - - result& operator=(const success_type& s) - { - this->cleanup(); - this->is_ok_ = true; - auto tmp = ::new(std::addressof(this->succ)) success_type(s); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - return *this; - } - result& operator=(const failure_type& f) - { - this->cleanup(); - this->is_ok_ = false; - auto tmp = ::new(std::addressof(this->fail)) failure_type(f); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - return *this; - } - result& operator=(success_type&& s) - { - this->cleanup(); - this->is_ok_ = true; - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s)); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - return *this; - } - result& operator=(failure_type&& f) - { - this->cleanup(); - this->is_ok_ = false; - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f)); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - return *this; - } - - template - result& operator=(const success& s) - { - this->cleanup(); - this->is_ok_ = true; - auto tmp = ::new(std::addressof(this->succ)) success_type(s.value); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - return *this; - } - template - result& operator=(const failure& f) - { - this->cleanup(); - this->is_ok_ = false; - auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - return *this; - } - template - result& operator=(success&& s) - { - this->cleanup(); - this->is_ok_ = true; - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value)); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - return *this; - } - template - result& operator=(failure&& f) - { - this->cleanup(); - this->is_ok_ = false; - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value)); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - return *this; - } - - ~result() noexcept {this->cleanup();} - - result(const result& other): is_ok_(other.is_ok()) - { - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok()); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err()); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - } - result(result&& other): is_ok_(other.is_ok()) - { - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok())); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err())); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - } - - template - result(const result& other): is_ok_(other.is_ok()) - { - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok()); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err()); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - } - template - result(result&& other): is_ok_(other.is_ok()) - { - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok())); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err())); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - } - - result& operator=(const result& other) - { - this->cleanup(); - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok()); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err()); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - is_ok_ = other.is_ok(); - return *this; - } - result& operator=(result&& other) - { - this->cleanup(); - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok())); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err())); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - is_ok_ = other.is_ok(); - return *this; - } - - template - result& operator=(const result& other) - { - this->cleanup(); - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok()); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err()); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - is_ok_ = other.is_ok(); - return *this; - } - template - result& operator=(result&& other) - { - this->cleanup(); - if(other.is_ok()) - { - auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok())); - assert(tmp == std::addressof(this->succ)); - (void)tmp; - } - else - { - auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err())); - assert(tmp == std::addressof(this->fail)); - (void)tmp; - } - is_ok_ = other.is_ok(); - return *this; - } - - bool is_ok() const noexcept {return is_ok_;} - bool is_err() const noexcept {return !is_ok_;} - - operator bool() const noexcept {return is_ok_;} - - value_type& unwrap() & - { - if(is_err()) - { - throw std::runtime_error("toml::result: bad unwrap: " + - format_error(this->as_err())); - } - return this->succ.value; - } - value_type const& unwrap() const& - { - if(is_err()) - { - throw std::runtime_error("toml::result: bad unwrap: " + - format_error(this->as_err())); - } - return this->succ.value; - } - value_type&& unwrap() && - { - if(is_err()) - { - throw std::runtime_error("toml::result: bad unwrap: " + - format_error(this->as_err())); - } - return std::move(this->succ.value); - } - - value_type& unwrap_or(value_type& opt) & - { - if(is_err()) {return opt;} - return this->succ.value; - } - value_type const& unwrap_or(value_type const& opt) const& - { - if(is_err()) {return opt;} - return this->succ.value; - } - value_type unwrap_or(value_type opt) && - { - if(is_err()) {return opt;} - return this->succ.value; - } - - error_type& unwrap_err() & - { - if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");} - return this->fail.value; - } - error_type const& unwrap_err() const& - { - if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");} - return this->fail.value; - } - error_type&& unwrap_err() && - { - if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");} - return std::move(this->fail.value); - } - - value_type& as_ok() & noexcept {return this->succ.value;} - value_type const& as_ok() const& noexcept {return this->succ.value;} - value_type&& as_ok() && noexcept {return std::move(this->succ.value);} - - error_type& as_err() & noexcept {return this->fail.value;} - error_type const& as_err() const& noexcept {return this->fail.value;} - error_type&& as_err() && noexcept {return std::move(this->fail.value);} - - - // prerequisities - // F: T -> U - // retval: result - template - result, error_type> - map(F&& f) & - { - if(this->is_ok()){return ok(f(this->as_ok()));} - return err(this->as_err()); - } - template - result, error_type> - map(F&& f) const& - { - if(this->is_ok()){return ok(f(this->as_ok()));} - return err(this->as_err()); - } - template - result, error_type> - map(F&& f) && - { - if(this->is_ok()){return ok(f(std::move(this->as_ok())));} - return err(std::move(this->as_err())); - } - - // prerequisities - // F: E -> F - // retval: result - template - result> - map_err(F&& f) & - { - if(this->is_err()){return err(f(this->as_err()));} - return ok(this->as_ok()); - } - template - result> - map_err(F&& f) const& - { - if(this->is_err()){return err(f(this->as_err()));} - return ok(this->as_ok()); - } - template - result> - map_err(F&& f) && - { - if(this->is_err()){return err(f(std::move(this->as_err())));} - return ok(std::move(this->as_ok())); - } - - // prerequisities - // F: T -> U - // retval: U - template - detail::return_type_of_t - map_or_else(F&& f, U&& opt) & - { - if(this->is_err()){return std::forward(opt);} - return f(this->as_ok()); - } - template - detail::return_type_of_t - map_or_else(F&& f, U&& opt) const& - { - if(this->is_err()){return std::forward(opt);} - return f(this->as_ok()); - } - template - detail::return_type_of_t - map_or_else(F&& f, U&& opt) && - { - if(this->is_err()){return std::forward(opt);} - return f(std::move(this->as_ok())); - } - - // prerequisities - // F: E -> U - // retval: U - template - detail::return_type_of_t - map_err_or_else(F&& f, U&& opt) & - { - if(this->is_ok()){return std::forward(opt);} - return f(this->as_err()); - } - template - detail::return_type_of_t - map_err_or_else(F&& f, U&& opt) const& - { - if(this->is_ok()){return std::forward(opt);} - return f(this->as_err()); - } - template - detail::return_type_of_t - map_err_or_else(F&& f, U&& opt) && - { - if(this->is_ok()){return std::forward(opt);} - return f(std::move(this->as_err())); - } - - // prerequisities: - // F: func T -> U - // toml::err(error_type) should be convertible to U. - // normally, type U is another result and E is convertible to F - template - detail::return_type_of_t - and_then(F&& f) & - { - if(this->is_ok()){return f(this->as_ok());} - return err(this->as_err()); - } - template - detail::return_type_of_t - and_then(F&& f) const& - { - if(this->is_ok()){return f(this->as_ok());} - return err(this->as_err()); - } - template - detail::return_type_of_t - and_then(F&& f) && - { - if(this->is_ok()){return f(std::move(this->as_ok()));} - return err(std::move(this->as_err())); - } - - // prerequisities: - // F: func E -> U - // toml::ok(value_type) should be convertible to U. - // normally, type U is another result and T is convertible to S - template - detail::return_type_of_t - or_else(F&& f) & - { - if(this->is_err()){return f(this->as_err());} - return ok(this->as_ok()); - } - template - detail::return_type_of_t - or_else(F&& f) const& - { - if(this->is_err()){return f(this->as_err());} - return ok(this->as_ok()); - } - template - detail::return_type_of_t - or_else(F&& f) && - { - if(this->is_err()){return f(std::move(this->as_err()));} - return ok(std::move(this->as_ok())); - } - - // if *this is error, returns *this. otherwise, returns other. - result and_other(const result& other) const& - { - return this->is_err() ? *this : other; - } - result and_other(result&& other) && - { - return this->is_err() ? std::move(*this) : std::move(other); - } - - // if *this is okay, returns *this. otherwise, returns other. - result or_other(const result& other) const& - { - return this->is_ok() ? *this : other; - } - result or_other(result&& other) && - { - return this->is_ok() ? std::move(*this) : std::move(other); - } - - void swap(result& other) - { - result tmp(std::move(*this)); - *this = std::move(other); - other = std::move(tmp); - return ; - } - - private: - - static std::string format_error(std::exception const& excpt) - { - return std::string(excpt.what()); - } - template::value, std::nullptr_t>::type = nullptr> - static std::string format_error(U const& others) - { - std::ostringstream oss; oss << others; - return oss.str(); - } - - void cleanup() noexcept - { - if(this->is_ok_) {this->succ.~success_type();} - else {this->fail.~failure_type();} - return; - } - - private: - - bool is_ok_; - union - { - success_type succ; - failure_type fail; - }; -}; - -template -void swap(result& lhs, result& rhs) -{ - lhs.swap(rhs); - return; -} - -// this might be confusing because it eagerly evaluated, while in the other -// cases operator && and || are short-circuited. -// -// template -// inline result -// operator&&(const result& lhs, const result& rhs) noexcept -// { -// return lhs.is_ok() ? rhs : lhs; -// } -// -// template -// inline result -// operator||(const result& lhs, const result& rhs) noexcept -// { -// return lhs.is_ok() ? lhs : rhs; -// } - -// ---------------------------------------------------------------------------- -// re-use result as a optional with none_t - -namespace detail -{ -struct none_t {}; -inline bool operator==(const none_t&, const none_t&) noexcept {return true;} -inline bool operator!=(const none_t&, const none_t&) noexcept {return false;} -inline bool operator< (const none_t&, const none_t&) noexcept {return false;} -inline bool operator<=(const none_t&, const none_t&) noexcept {return true;} -inline bool operator> (const none_t&, const none_t&) noexcept {return false;} -inline bool operator>=(const none_t&, const none_t&) noexcept {return true;} -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const none_t&) -{ - os << "none"; - return os; -} -inline failure none() noexcept {return failure{none_t{}};} -} // detail -} // toml11 -#endif// TOML11_RESULT_H diff --git a/src/frontend/qt_sdl/toml/toml/serializer.hpp b/src/frontend/qt_sdl/toml/toml/serializer.hpp deleted file mode 100644 index 88ae775a..00000000 --- a/src/frontend/qt_sdl/toml/toml/serializer.hpp +++ /dev/null @@ -1,922 +0,0 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. -#ifndef TOML11_SERIALIZER_HPP -#define TOML11_SERIALIZER_HPP -#include -#include - -#include - -#include "lexer.hpp" -#include "value.hpp" - -namespace toml -{ - -// This function serialize a key. It checks a string is a bare key and -// escapes special characters if the string is not compatible to a bare key. -// ```cpp -// std::string k("non.bare.key"); // the key itself includes `.`s. -// std::string formatted = toml::format_key(k); -// assert(formatted == "\"non.bare.key\""); -// ``` -// -// This function is exposed to make it easy to write a user-defined serializer. -// Since toml restricts characters available in a bare key, generally a string -// should be escaped. But checking whether a string needs to be surrounded by -// a `"` and escaping some special character is boring. -template -std::basic_string -format_key(const std::basic_string& k) -{ - if(k.empty()) - { - return std::string("\"\""); - } - - // check the key can be a bare (unquoted) key - detail::location loc(k, std::vector(k.begin(), k.end())); - detail::lex_unquoted_key::invoke(loc); - if(loc.iter() == loc.end()) - { - return k; // all the tokens are consumed. the key is unquoted-key. - } - - //if it includes special characters, then format it in a "quoted" key. - std::basic_string serialized("\""); - for(const char c : k) - { - switch(c) - { - case '\\': {serialized += "\\\\"; break;} - case '\"': {serialized += "\\\""; break;} - case '\b': {serialized += "\\b"; break;} - case '\t': {serialized += "\\t"; break;} - case '\f': {serialized += "\\f"; break;} - case '\n': {serialized += "\\n"; break;} - case '\r': {serialized += "\\r"; break;} - default : {serialized += c; break;} - } - } - serialized += "\""; - return serialized; -} - -template -std::basic_string -format_keys(const std::vector>& keys) -{ - if(keys.empty()) - { - return std::string("\"\""); - } - - std::basic_string serialized; - for(const auto& ky : keys) - { - serialized += format_key(ky); - serialized += charT('.'); - } - serialized.pop_back(); // remove the last dot '.' - return serialized; -} - -template -struct serializer -{ - static_assert(detail::is_basic_value::value, - "toml::serializer is for toml::value and its variants, " - "toml::basic_value<...>."); - - using value_type = Value; - using key_type = typename value_type::key_type ; - using comment_type = typename value_type::comment_type ; - using boolean_type = typename value_type::boolean_type ; - using integer_type = typename value_type::integer_type ; - using floating_type = typename value_type::floating_type ; - using string_type = typename value_type::string_type ; - using local_time_type = typename value_type::local_time_type ; - using local_date_type = typename value_type::local_date_type ; - using local_datetime_type = typename value_type::local_datetime_type ; - using offset_datetime_type = typename value_type::offset_datetime_type; - using array_type = typename value_type::array_type ; - using table_type = typename value_type::table_type ; - - serializer(const std::size_t w = 80u, - const int float_prec = std::numeric_limits::max_digits10, - const bool can_be_inlined = false, - const bool no_comment = false, - std::vector ks = {}, - const bool value_has_comment = false) - : can_be_inlined_(can_be_inlined), no_comment_(no_comment), - value_has_comment_(value_has_comment && !no_comment), - float_prec_(float_prec), width_(w), keys_(std::move(ks)) - {} - ~serializer() = default; - - std::string operator()(const boolean_type& b) const - { - return b ? "true" : "false"; - } - std::string operator()(const integer_type i) const - { - return std::to_string(i); - } - std::string operator()(const floating_type f) const - { - if(std::isnan(f)) - { - if(std::signbit(f)) - { - return std::string("-nan"); - } - else - { - return std::string("nan"); - } - } - else if(!std::isfinite(f)) - { - if(std::signbit(f)) - { - return std::string("-inf"); - } - else - { - return std::string("inf"); - } - } - - const auto fmt = "%.*g"; - const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f); - // +1 for null character(\0) - std::vector buf(static_cast(bsz + 1), '\0'); - std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f); - - std::string token(buf.begin(), std::prev(buf.end())); - if(!token.empty() && token.back() == '.') // 1. => 1.0 - { - token += '0'; - } - - const auto e = std::find_if( - token.cbegin(), token.cend(), [](const char c) noexcept -> bool { - return c == 'e' || c == 'E'; - }); - const auto has_exponent = (token.cend() != e); - const auto has_fraction = (token.cend() != std::find( - token.cbegin(), token.cend(), '.')); - - if(!has_exponent && !has_fraction) - { - // the resulting value does not have any float specific part! - token += ".0"; - } - return token; - } - std::string operator()(const string_type& s) const - { - if(s.kind == string_t::basic) - { - if((std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() || - std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend()) && - this->width_ != (std::numeric_limits::max)()) - { - // if linefeed or double-quote is contained, - // make it multiline basic string. - const auto escaped = this->escape_ml_basic_string(s.str); - std::string open("\"\"\""); - std::string close("\"\"\""); - if(escaped.find('\n') != std::string::npos || - this->width_ < escaped.size() + 6) - { - // if the string body contains newline or is enough long, - // add newlines after and before delimiters. - open += "\n"; - close = std::string("\\\n") + close; - } - return open + escaped + close; - } - - // no linefeed. try to make it oneline-string. - std::string oneline = this->escape_basic_string(s.str); - if(oneline.size() + 2 < width_ || width_ < 2) - { - const std::string quote("\""); - return quote + oneline + quote; - } - - // the line is too long compared to the specified width. - // split it into multiple lines. - std::string token("\"\"\"\n"); - while(!oneline.empty()) - { - if(oneline.size() < width_) - { - token += oneline; - oneline.clear(); - } - else if(oneline.at(width_-2) == '\\') - { - token += oneline.substr(0, width_-2); - token += "\\\n"; - oneline.erase(0, width_-2); - } - else - { - token += oneline.substr(0, width_-1); - token += "\\\n"; - oneline.erase(0, width_-1); - } - } - return token + std::string("\\\n\"\"\""); - } - else // the string `s` is literal-string. - { - if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() || - std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() ) - { - std::string open("'''"); - if(this->width_ + 6 < s.str.size()) - { - open += '\n'; // the first newline is ignored by TOML spec - } - const std::string close("'''"); - return open + s.str + close; - } - else - { - const std::string quote("'"); - return quote + s.str + quote; - } - } - } - - std::string operator()(const local_date_type& d) const - { - std::ostringstream oss; - oss << d; - return oss.str(); - } - std::string operator()(const local_time_type& t) const - { - std::ostringstream oss; - oss << t; - return oss.str(); - } - std::string operator()(const local_datetime_type& dt) const - { - std::ostringstream oss; - oss << dt; - return oss.str(); - } - std::string operator()(const offset_datetime_type& odt) const - { - std::ostringstream oss; - oss << odt; - return oss.str(); - } - - std::string operator()(const array_type& v) const - { - if(v.empty()) - { - return std::string("[]"); - } - if(this->is_array_of_tables(v)) - { - return make_array_of_tables(v); - } - - // not an array of tables. normal array. - // first, try to make it inline if none of the elements have a comment. - if( ! this->has_comment_inside(v)) - { - const auto inl = this->make_inline_array(v); - if(inl.size() < this->width_ && - std::find(inl.cbegin(), inl.cend(), '\n') == inl.cend()) - { - return inl; - } - } - - // if the length exceeds this->width_, print multiline array. - // key = [ - // # ... - // 42, - // ... - // ] - std::string token; - std::string current_line; - token += "[\n"; - for(const auto& item : v) - { - if( ! item.comments().empty() && !no_comment_) - { - // if comment exists, the element must be the only element in the line. - // e.g. the following is not allowed. - // ```toml - // array = [ - // # comment for what? - // 1, 2, 3, 4, 5 - // ] - // ``` - if(!current_line.empty()) - { - if(current_line.back() != '\n') - { - current_line += '\n'; - } - token += current_line; - current_line.clear(); - } - for(const auto& c : item.comments()) - { - token += '#'; - token += c; - token += '\n'; - } - token += toml::visit(*this, item); - if(!token.empty() && token.back() == '\n') {token.pop_back();} - token += ",\n"; - continue; - } - std::string next_elem; - if(item.is_table()) - { - serializer ser(*this); - ser.can_be_inlined_ = true; - ser.width_ = (std::numeric_limits::max)(); - next_elem += toml::visit(ser, item); - } - else - { - next_elem += toml::visit(*this, item); - } - - // comma before newline. - if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();} - - // if current line does not exceeds the width limit, continue. - if(current_line.size() + next_elem.size() + 1 < this->width_) - { - current_line += next_elem; - current_line += ','; - } - else if(current_line.empty()) - { - // if current line was empty, force put the next_elem because - // next_elem is not splittable - token += next_elem; - token += ",\n"; - // current_line is kept empty - } - else // reset current_line - { - assert(current_line.back() == ','); - token += current_line; - token += '\n'; - current_line = next_elem; - current_line += ','; - } - } - if(!current_line.empty()) - { - if(!current_line.empty() && current_line.back() != '\n') - { - current_line += '\n'; - } - token += current_line; - } - token += "]\n"; - return token; - } - - // templatize for any table-like container - std::string operator()(const table_type& v) const - { - // if an element has a comment, then it can't be inlined. - // table = {# how can we write a comment for this? key = "value"} - if(this->can_be_inlined_ && !(this->has_comment_inside(v))) - { - std::string token; - if(!this->keys_.empty()) - { - token += format_key(this->keys_.back()); - token += " = "; - } - token += this->make_inline_table(v); - if(token.size() < this->width_ && - token.end() == std::find(token.begin(), token.end(), '\n')) - { - return token; - } - } - - std::string token; - if(!keys_.empty()) - { - token += '['; - token += format_keys(keys_); - token += "]\n"; - } - token += this->make_multiline_table(v); - return token; - } - - private: - - std::string escape_basic_string(const std::string& s) const - { - //XXX assuming `s` is a valid utf-8 sequence. - std::string retval; - for(const char c : s) - { - switch(c) - { - case '\\': {retval += "\\\\"; break;} - case '\"': {retval += "\\\""; break;} - case '\b': {retval += "\\b"; break;} - case '\t': {retval += "\\t"; break;} - case '\f': {retval += "\\f"; break;} - case '\n': {retval += "\\n"; break;} - case '\r': {retval += "\\r"; break;} - default : - { - if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F) - { - retval += "\\u00"; - retval += char(48 + (c / 16)); - retval += char((c % 16 < 10 ? 48 : 55) + (c % 16)); - } - else - { - retval += c; - } - } - } - } - return retval; - } - - std::string escape_ml_basic_string(const std::string& s) const - { - std::string retval; - for(auto i=s.cbegin(), e=s.cend(); i!=e; ++i) - { - switch(*i) - { - case '\\': {retval += "\\\\"; break;} - // One or two consecutive "s are allowed. - // Later we will check there are no three consecutive "s. - // case '\"': {retval += "\\\""; break;} - case '\b': {retval += "\\b"; break;} - case '\t': {retval += "\\t"; break;} - case '\f': {retval += "\\f"; break;} - case '\n': {retval += "\n"; break;} - case '\r': - { - if(std::next(i) != e && *std::next(i) == '\n') - { - retval += "\r\n"; - ++i; - } - else - { - retval += "\\r"; - } - break; - } - default : - { - const auto c = *i; - if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F) - { - retval += "\\u00"; - retval += char(48 + (c / 16)); - retval += char((c % 16 < 10 ? 48 : 55) + (c % 16)); - } - else - { - retval += c; - } - } - - } - } - // Only 1 or 2 consecutive `"`s are allowed in multiline basic string. - // 3 consecutive `"`s are considered as a closing delimiter. - // We need to check if there are 3 or more consecutive `"`s and insert - // backslash to break them down into several short `"`s like the `str6` - // in the following example. - // ```toml - // str4 = """Here are two quotation marks: "". Simple enough.""" - // # str5 = """Here are three quotation marks: """.""" # INVALID - // str5 = """Here are three quotation marks: ""\".""" - // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" - // ``` - auto found_3_quotes = retval.find("\"\"\""); - while(found_3_quotes != std::string::npos) - { - retval.replace(found_3_quotes, 3, "\"\"\\\""); - found_3_quotes = retval.find("\"\"\""); - } - return retval; - } - - // if an element of a table or an array has a comment, it cannot be inlined. - bool has_comment_inside(const array_type& a) const noexcept - { - // if no_comment is set, comments would not be written. - if(this->no_comment_) {return false;} - - for(const auto& v : a) - { - if(!v.comments().empty()) {return true;} - } - return false; - } - bool has_comment_inside(const table_type& t) const noexcept - { - // if no_comment is set, comments would not be written. - if(this->no_comment_) {return false;} - - for(const auto& kv : t) - { - if(!kv.second.comments().empty()) {return true;} - } - return false; - } - - std::string make_inline_array(const array_type& v) const - { - assert(!has_comment_inside(v)); - std::string token; - token += '['; - bool is_first = true; - for(const auto& item : v) - { - if(is_first) {is_first = false;} else {token += ',';} - token += visit(serializer( - (std::numeric_limits::max)(), this->float_prec_, - /* inlined */ true, /*no comment*/ false, /*keys*/ {}, - /*has_comment*/ !item.comments().empty()), item); - } - token += ']'; - return token; - } - - std::string make_inline_table(const table_type& v) const - { - assert(!has_comment_inside(v)); - assert(this->can_be_inlined_); - std::string token; - token += '{'; - bool is_first = true; - for(const auto& kv : v) - { - // in inline tables, trailing comma is not allowed (toml-lang #569). - if(is_first) {is_first = false;} else {token += ',';} - token += format_key(kv.first); - token += '='; - token += visit(serializer( - (std::numeric_limits::max)(), this->float_prec_, - /* inlined */ true, /*no comment*/ false, /*keys*/ {}, - /*has_comment*/ !kv.second.comments().empty()), kv.second); - } - token += '}'; - return token; - } - - std::string make_multiline_table(const table_type& v) const - { - std::string token; - - // print non-table elements first. - // ```toml - // [foo] # a table we're writing now here - // key = "value" # <- non-table element, "key" - // # ... - // [foo.bar] # <- table element, "bar" - // ``` - // because after printing [foo.bar], the remaining non-table values will - // be assigned into [foo.bar], not [foo]. Those values should be printed - // earlier. - for(const auto& kv : v) - { - if(kv.second.is_table() || is_array_of_tables(kv.second)) - { - continue; - } - - token += write_comments(kv.second); - - const auto key_and_sep = format_key(kv.first) + " = "; - const auto residual_width = (this->width_ > key_and_sep.size()) ? - this->width_ - key_and_sep.size() : 0; - token += key_and_sep; - token += visit(serializer(residual_width, this->float_prec_, - /*can be inlined*/ true, /*no comment*/ false, /*keys*/ {}, - /*has_comment*/ !kv.second.comments().empty()), kv.second); - - if(token.back() != '\n') - { - token += '\n'; - } - } - - // normal tables / array of tables - - // after multiline table appeared, the other tables cannot be inline - // because the table would be assigned into the table. - // [foo] - // ... - // bar = {...} # <- bar will be a member of [foo]. - bool multiline_table_printed = false; - for(const auto& kv : v) - { - if(!kv.second.is_table() && !is_array_of_tables(kv.second)) - { - continue; // other stuff are already serialized. skip them. - } - - std::vector ks(this->keys_); - ks.push_back(kv.first); - - auto tmp = visit(serializer(this->width_, this->float_prec_, - !multiline_table_printed, this->no_comment_, ks, - /*has_comment*/ !kv.second.comments().empty()), kv.second); - - // If it is the first time to print a multi-line table, it would be - // helpful to separate normal key-value pair and subtables by a - // newline. - // (this checks if the current key-value pair contains newlines. - // but it is not perfect because multi-line string can also contain - // a newline. in such a case, an empty line will be written) TODO - if((!multiline_table_printed) && - std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend()) - { - multiline_table_printed = true; - token += '\n'; // separate key-value pairs and subtables - - token += write_comments(kv.second); - token += tmp; - - // care about recursive tables (all tables in each level prints - // newline and there will be a full of newlines) - if(tmp.substr(tmp.size() - 2, 2) != "\n\n" && - tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" ) - { - token += '\n'; - } - } - else - { - token += write_comments(kv.second); - token += tmp; - token += '\n'; - } - } - return token; - } - - std::string make_array_of_tables(const array_type& v) const - { - // if it's not inlined, we need to add `[[table.key]]`. - // but if it can be inlined, we can format it as the following. - // ``` - // table.key = [ - // {...}, - // # comment - // {...}, - // ] - // ``` - // This function checks if inlinization is possible or not, and then - // format the array-of-tables in a proper way. - // - // Note about comments: - // - // If the array itself has a comment (value_has_comment_ == true), we - // should try to make it inline. - // ```toml - // # comment about array - // array = [ - // # comment about table element - // {of = "table"} - // ] - // ``` - // If it is formatted as a multiline table, the two comments becomes - // indistinguishable. - // ```toml - // # comment about array - // # comment about table element - // [[array]] - // of = "table" - // ``` - // So we need to try to make it inline, and it force-inlines regardless - // of the line width limit. - // It may fail if the element of a table has comment. In that case, - // the array-of-tables will be formatted as a multiline table. - if(this->can_be_inlined_ || this->value_has_comment_) - { - std::string token; - if(!keys_.empty()) - { - token += format_key(keys_.back()); - token += " = "; - } - - bool failed = false; - token += "[\n"; - for(const auto& item : v) - { - // if an element of the table has a comment, the table - // cannot be inlined. - if(this->has_comment_inside(item.as_table())) - { - failed = true; - break; - } - // write comments for the table itself - token += write_comments(item); - - const auto t = this->make_inline_table(item.as_table()); - - if(t.size() + 1 > width_ || // +1 for the last comma {...}, - std::find(t.cbegin(), t.cend(), '\n') != t.cend()) - { - // if the value itself has a comment, ignore the line width limit - if( ! this->value_has_comment_) - { - failed = true; - break; - } - } - token += t; - token += ",\n"; - } - - if( ! failed) - { - token += "]\n"; - return token; - } - // if failed, serialize them as [[array.of.tables]]. - } - - std::string token; - for(const auto& item : v) - { - token += write_comments(item); - token += "[["; - token += format_keys(keys_); - token += "]]\n"; - token += this->make_multiline_table(item.as_table()); - } - return token; - } - - std::string write_comments(const value_type& v) const - { - std::string retval; - if(this->no_comment_) {return retval;} - - for(const auto& c : v.comments()) - { - retval += '#'; - retval += c; - retval += '\n'; - } - return retval; - } - - bool is_array_of_tables(const value_type& v) const - { - if(!v.is_array() || v.as_array().empty()) {return false;} - return is_array_of_tables(v.as_array()); - } - bool is_array_of_tables(const array_type& v) const - { - // Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to - // check all the element in an array to check if the array is an array - // of tables. - return std::all_of(v.begin(), v.end(), [](const value_type& elem) { - return elem.is_table(); - }); - } - - private: - - bool can_be_inlined_; - bool no_comment_; - bool value_has_comment_; - int float_prec_; - std::size_t width_; - std::vector keys_; -}; - -template class M, template class V> -std::string -format(const basic_value& v, std::size_t w = 80u, - int fprec = std::numeric_limits::max_digits10, - bool no_comment = false, bool force_inline = false) -{ - using value_type = basic_value; - // if value is a table, it is considered to be a root object. - // the root object can't be an inline table. - if(v.is_table()) - { - std::ostringstream oss; - if(!v.comments().empty()) - { - oss << v.comments(); - oss << '\n'; // to split the file comment from the first element - } - const auto serialized = visit(serializer(w, fprec, false, no_comment), v); - oss << serialized; - return oss.str(); - } - return visit(serializer(w, fprec, force_inline), v); -} - -namespace detail -{ -template -int comment_index(std::basic_ostream&) -{ - static const int index = std::ios_base::xalloc(); - return index; -} -} // detail - -template -std::basic_ostream& -nocomment(std::basic_ostream& os) -{ - // by default, it is zero. and by default, it shows comments. - os.iword(detail::comment_index(os)) = 1; - return os; -} - -template -std::basic_ostream& -showcomment(std::basic_ostream& os) -{ - // by default, it is zero. and by default, it shows comments. - os.iword(detail::comment_index(os)) = 0; - return os; -} - -template class M, template class V> -std::basic_ostream& -operator<<(std::basic_ostream& os, const basic_value& v) -{ - using value_type = basic_value; - - // get status of std::setw(). - const auto w = static_cast(os.width()); - const int fprec = static_cast(os.precision()); - os.width(0); - - // by default, iword is initialized by 0. And by default, toml11 outputs - // comments. So `0` means showcomment. 1 means nocommnet. - const bool no_comment = (1 == os.iword(detail::comment_index(os))); - - if(!no_comment && v.is_table() && !v.comments().empty()) - { - os << v.comments(); - os << '\n'; // to split the file comment from the first element - } - // the root object can't be an inline table. so pass `false`. - const auto serialized = visit(serializer(w, fprec, no_comment, false), v); - os << serialized; - - // if v is a non-table value, and has only one comment, then - // put a comment just after a value. in the following way. - // - // ```toml - // key = "value" # comment. - // ``` - // - // Since the top-level toml object is a table, one who want to put a - // non-table toml value must use this in a following way. - // - // ```cpp - // toml::value v; - // std::cout << "user-defined-key = " << v << std::endl; - // ``` - // - // In this case, it is impossible to put comments before key-value pair. - // The only way to preserve comments is to put all of them after a value. - if(!no_comment && !v.is_table() && !v.comments().empty()) - { - os << " #"; - for(const auto& c : v.comments()) {os << c;} - } - return os; -} - -} // toml -#endif// TOML11_SERIALIZER_HPP diff --git a/src/frontend/qt_sdl/toml/toml/source_location.hpp b/src/frontend/qt_sdl/toml/toml/source_location.hpp deleted file mode 100644 index fa175b5b..00000000 --- a/src/frontend/qt_sdl/toml/toml/source_location.hpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. -#ifndef TOML11_SOURCE_LOCATION_HPP -#define TOML11_SOURCE_LOCATION_HPP -#include -#include - -#include "region.hpp" - -namespace toml -{ - -// A struct to contain location in a toml file. -// The interface imitates std::experimental::source_location, -// but not completely the same. -// -// It would be constructed by toml::value. It can be used to generate -// user-defined error messages. -// -// - std::uint_least32_t line() const noexcept -// - returns the line number where the region is on. -// - std::uint_least32_t column() const noexcept -// - returns the column number where the region starts. -// - std::uint_least32_t region() const noexcept -// - returns the size of the region. -// -// +-- line() +-- region of interest (region() == 9) -// v .---+---. -// 12 | value = "foo bar" -// ^ -// +-- column() -// -// - std::string const& file_name() const noexcept; -// - name of the file. -// - std::string const& line_str() const noexcept; -// - the whole line that contains the region of interest. -// -struct source_location -{ - public: - - source_location() - : line_num_(1), column_num_(1), region_size_(1), - file_name_("unknown file"), line_str_("") - {} - - explicit source_location(const detail::region_base* reg) - : line_num_(1), column_num_(1), region_size_(1), - file_name_("unknown file"), line_str_("") - { - if(reg) - { - if(reg->line_num() != detail::region_base().line_num()) - { - line_num_ = static_cast( - std::stoul(reg->line_num())); - } - column_num_ = static_cast(reg->before() + 1); - region_size_ = static_cast(reg->size()); - file_name_ = reg->name(); - line_str_ = reg->line(); - } - } - - explicit source_location(const detail::region& reg) - : line_num_(static_cast(std::stoul(reg.line_num()))), - column_num_(static_cast(reg.before() + 1)), - region_size_(static_cast(reg.size())), - file_name_(reg.name()), - line_str_ (reg.line()) - {} - explicit source_location(const detail::location& loc) - : line_num_(static_cast(std::stoul(loc.line_num()))), - column_num_(static_cast(loc.before() + 1)), - region_size_(static_cast(loc.size())), - file_name_(loc.name()), - line_str_ (loc.line()) - {} - - ~source_location() = default; - source_location(source_location const&) = default; - source_location(source_location &&) = default; - source_location& operator=(source_location const&) = default; - source_location& operator=(source_location &&) = default; - - std::uint_least32_t line() const noexcept {return line_num_;} - std::uint_least32_t column() const noexcept {return column_num_;} - std::uint_least32_t region() const noexcept {return region_size_;} - - std::string const& file_name() const noexcept {return file_name_;} - std::string const& line_str() const noexcept {return line_str_;} - - private: - - std::uint_least32_t line_num_; - std::uint_least32_t column_num_; - std::uint_least32_t region_size_; - std::string file_name_; - std::string line_str_; -}; - -namespace detail -{ - -// internal error message generation. -inline std::string format_underline(const std::string& message, - const std::vector>& loc_com, - const std::vector& helps = {}, - const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) -{ - std::size_t line_num_width = 0; - for(const auto& lc : loc_com) - { - std::uint_least32_t line = lc.first.line(); - std::size_t digit = 0; - while(line != 0) - { - line /= 10; - digit += 1; - } - line_num_width = (std::max)(line_num_width, digit); - } - // 1 is the minimum width - line_num_width = std::max(line_num_width, 1); - - std::ostringstream retval; - - if(colorize) - { - retval << color::colorize; // turn on ANSI color - } - - // XXX - // Here, before `colorize` support, it does not output `[error]` prefix - // automatically. So some user may output it manually and this change may - // duplicate the prefix. To avoid it, check the first 7 characters and - // if it is "[error]", it removes that part from the message shown. - if(message.size() > 7 && message.substr(0, 7) == "[error]") - { - retval << color::bold << color::red << "[error]" << color::reset - << color::bold << message.substr(7) << color::reset << '\n'; - } - else - { - retval << color::bold << color::red << "[error] " << color::reset - << color::bold << message << color::reset << '\n'; - } - - const auto format_one_location = [line_num_width] - (std::ostringstream& oss, - const source_location& loc, const std::string& comment) -> void - { - oss << ' ' << color::bold << color::blue - << std::setw(static_cast(line_num_width)) - << std::right << loc.line() << " | " << color::reset - << loc.line_str() << '\n'; - - oss << make_string(line_num_width + 1, ' ') - << color::bold << color::blue << " | " << color::reset - << make_string(loc.column()-1 /*1-origin*/, ' '); - - if(loc.region() == 1) - { - // invalid - // ^------ - oss << color::bold << color::red << "^---" << color::reset; - } - else - { - // invalid - // ~~~~~~~ - const auto underline_len = (std::min)( - static_cast(loc.region()), loc.line_str().size()); - oss << color::bold << color::red - << make_string(underline_len, '~') << color::reset; - } - oss << ' '; - oss << comment; - return; - }; - - assert(!loc_com.empty()); - - // --> example.toml - // | - retval << color::bold << color::blue << " --> " << color::reset - << loc_com.front().first.file_name() << '\n'; - retval << make_string(line_num_width + 1, ' ') - << color::bold << color::blue << " |\n" << color::reset; - // 1 | key value - // | ^--- missing = - format_one_location(retval, loc_com.front().first, loc_com.front().second); - - // process the rest of the locations - for(std::size_t i=1; i filename.toml" again - { - retval << color::bold << color::blue << " --> " << color::reset - << curr.first.file_name() << '\n'; - retval << make_string(line_num_width + 1, ' ') - << color::bold << color::blue << " |\n" << color::reset; - } - - format_one_location(retval, curr.first, curr.second); - } - - if(!helps.empty()) - { - retval << '\n'; - retval << make_string(line_num_width + 1, ' '); - retval << color::bold << color::blue << " |" << color::reset; - for(const auto& help : helps) - { - retval << color::bold << "\nHint: " << color::reset; - retval << help; - } - } - return retval.str(); -} - -} // detail -} // toml -#endif// TOML11_SOURCE_LOCATION_HPP diff --git a/src/frontend/qt_sdl/toml/toml/storage.hpp b/src/frontend/qt_sdl/toml/toml/storage.hpp deleted file mode 100644 index 202f9035..00000000 --- a/src/frontend/qt_sdl/toml/toml/storage.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_STORAGE_HPP -#define TOML11_STORAGE_HPP -#include "utility.hpp" - -namespace toml -{ -namespace detail -{ - -// this contains pointer and deep-copy the content if copied. -// to avoid recursive pointer. -template -struct storage -{ - using value_type = T; - - explicit storage(value_type const& v): ptr(toml::make_unique(v)) {} - explicit storage(value_type&& v): ptr(toml::make_unique(std::move(v))) {} - ~storage() = default; - storage(const storage& rhs): ptr(toml::make_unique(*rhs.ptr)) {} - storage& operator=(const storage& rhs) - { - this->ptr = toml::make_unique(*rhs.ptr); - return *this; - } - storage(storage&&) = default; - storage& operator=(storage&&) = default; - - bool is_ok() const noexcept {return static_cast(ptr);} - - value_type& value() & noexcept {return *ptr;} - value_type const& value() const& noexcept {return *ptr;} - value_type&& value() && noexcept {return std::move(*ptr);} - - private: - std::unique_ptr ptr; -}; - -} // detail -} // toml -#endif// TOML11_STORAGE_HPP diff --git a/src/frontend/qt_sdl/toml/toml/string.hpp b/src/frontend/qt_sdl/toml/toml/string.hpp deleted file mode 100644 index def3e57c..00000000 --- a/src/frontend/qt_sdl/toml/toml/string.hpp +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_STRING_HPP -#define TOML11_STRING_HPP - -#include "version.hpp" - -#include - -#include -#include - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L -#if __has_include() -#define TOML11_USING_STRING_VIEW 1 -#include -#endif -#endif - -namespace toml -{ - -enum class string_t : std::uint8_t -{ - basic = 0, - literal = 1, -}; - -struct string -{ - string() = default; - ~string() = default; - string(const string& s) = default; - string(string&& s) = default; - string& operator=(const string& s) = default; - string& operator=(string&& s) = default; - - string(const std::string& s): kind(string_t::basic), str(s){} - string(const std::string& s, string_t k): kind(k), str(s){} - string(const char* s): kind(string_t::basic), str(s){} - string(const char* s, string_t k): kind(k), str(s){} - - string(std::string&& s): kind(string_t::basic), str(std::move(s)){} - string(std::string&& s, string_t k): kind(k), str(std::move(s)){} - - string& operator=(const std::string& s) - {kind = string_t::basic; str = s; return *this;} - string& operator=(std::string&& s) - {kind = string_t::basic; str = std::move(s); return *this;} - - operator std::string& () & noexcept {return str;} - operator std::string const& () const& noexcept {return str;} - operator std::string&& () && noexcept {return std::move(str);} - - string& operator+=(const char* rhs) {str += rhs; return *this;} - string& operator+=(const char rhs) {str += rhs; return *this;} - string& operator+=(const std::string& rhs) {str += rhs; return *this;} - string& operator+=(const string& rhs) {str += rhs.str; return *this;} - -#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0 - explicit string(std::string_view s): kind(string_t::basic), str(s){} - string(std::string_view s, string_t k): kind(k), str(s){} - - string& operator=(std::string_view s) - {kind = string_t::basic; str = s; return *this;} - - explicit operator std::string_view() const noexcept - {return std::string_view(str);} - - string& operator+=(const std::string_view& rhs) {str += rhs; return *this;} -#endif - - string_t kind; - std::string str; -}; - -inline bool operator==(const string& lhs, const string& rhs) -{ - return lhs.kind == rhs.kind && lhs.str == rhs.str; -} -inline bool operator!=(const string& lhs, const string& rhs) -{ - return !(lhs == rhs); -} -inline bool operator<(const string& lhs, const string& rhs) -{ - return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind); -} -inline bool operator>(const string& lhs, const string& rhs) -{ - return rhs < lhs; -} -inline bool operator<=(const string& lhs, const string& rhs) -{ - return !(rhs < lhs); -} -inline bool operator>=(const string& lhs, const string& rhs) -{ - return !(lhs < rhs); -} - -inline bool -operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;} -inline bool -operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;} -inline bool -operator< (const string& lhs, const std::string& rhs) {return lhs.str < rhs;} -inline bool -operator> (const string& lhs, const std::string& rhs) {return lhs.str > rhs;} -inline bool -operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;} -inline bool -operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;} - -inline bool -operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;} -inline bool -operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;} -inline bool -operator< (const std::string& lhs, const string& rhs) {return lhs < rhs.str;} -inline bool -operator> (const std::string& lhs, const string& rhs) {return lhs > rhs.str;} -inline bool -operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;} -inline bool -operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;} - -inline bool -operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);} -inline bool -operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);} -inline bool -operator< (const string& lhs, const char* rhs) {return lhs.str < std::string(rhs);} -inline bool -operator> (const string& lhs, const char* rhs) {return lhs.str > std::string(rhs);} -inline bool -operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);} -inline bool -operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);} - -inline bool -operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;} -inline bool -operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;} -inline bool -operator< (const char* lhs, const string& rhs) {return std::string(lhs) < rhs.str;} -inline bool -operator> (const char* lhs, const string& rhs) {return std::string(lhs) > rhs.str;} -inline bool -operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;} -inline bool -operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const string& s) -{ - if(s.kind == string_t::basic) - { - if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend()) - { - // it contains newline. make it multiline string. - os << "\"\"\"\n"; - for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i) - { - switch(*i) - { - case '\\': {os << "\\\\"; break;} - case '\"': {os << "\\\""; break;} - case '\b': {os << "\\b"; break;} - case '\t': {os << "\\t"; break;} - case '\f': {os << "\\f"; break;} - case '\n': {os << '\n'; break;} - case '\r': - { - // since it is a multiline string, - // CRLF is not needed to be escaped. - if(std::next(i) != e && *std::next(i) == '\n') - { - os << "\r\n"; - ++i; - } - else - { - os << "\\r"; - } - break; - } - default: {os << *i; break;} - } - } - os << "\\\n\"\"\""; - return os; - } - // no newline. make it inline. - os << "\""; - for(const auto c : s.str) - { - switch(c) - { - case '\\': {os << "\\\\"; break;} - case '\"': {os << "\\\""; break;} - case '\b': {os << "\\b"; break;} - case '\t': {os << "\\t"; break;} - case '\f': {os << "\\f"; break;} - case '\n': {os << "\\n"; break;} - case '\r': {os << "\\r"; break;} - default : {os << c; break;} - } - } - os << "\""; - return os; - } - // the string `s` is literal-string. - if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() || - std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() ) - { - // contains newline or single quote. make it multiline. - os << "'''\n" << s.str << "'''"; - return os; - } - // normal literal string - os << '\'' << s.str << '\''; - return os; -} - -} // toml -#endif// TOML11_STRING_H diff --git a/src/frontend/qt_sdl/toml/toml/traits.hpp b/src/frontend/qt_sdl/toml/toml/traits.hpp deleted file mode 100644 index 255d9e88..00000000 --- a/src/frontend/qt_sdl/toml/toml/traits.hpp +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_TRAITS_HPP -#define TOML11_TRAITS_HPP - -#include "from.hpp" -#include "into.hpp" -#include "version.hpp" - -#include -#include -#include -#include -#include -#include - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L -#if __has_include() -#include -#endif // has_include() -#endif // cplusplus >= C++17 - -namespace toml -{ -template class T, template class A> -class basic_value; - -namespace detail -{ -// --------------------------------------------------------------------------- -// check whether type T is a kind of container/map class - -struct has_iterator_impl -{ - template static std::true_type check(typename T::iterator*); - template static std::false_type check(...); -}; -struct has_value_type_impl -{ - template static std::true_type check(typename T::value_type*); - template static std::false_type check(...); -}; -struct has_key_type_impl -{ - template static std::true_type check(typename T::key_type*); - template static std::false_type check(...); -}; -struct has_mapped_type_impl -{ - template static std::true_type check(typename T::mapped_type*); - template static std::false_type check(...); -}; -struct has_reserve_method_impl -{ - template static std::false_type check(...); - template static std::true_type check( - decltype(std::declval().reserve(std::declval()))*); -}; -struct has_push_back_method_impl -{ - template static std::false_type check(...); - template static std::true_type check( - decltype(std::declval().push_back(std::declval()))*); -}; -struct is_comparable_impl -{ - template static std::false_type check(...); - template static std::true_type check( - decltype(std::declval() < std::declval())*); -}; - -struct has_from_toml_method_impl -{ - template class Tb, template class A> - static std::true_type check( - decltype(std::declval().from_toml( - std::declval<::toml::basic_value>()))*); - - template class Tb, template class A> - static std::false_type check(...); -}; -struct has_into_toml_method_impl -{ - template - static std::true_type check(decltype(std::declval().into_toml())*); - template - static std::false_type check(...); -}; - -struct has_specialized_from_impl -{ - template - static std::false_type check(...); - template)> - static std::true_type check(::toml::from*); -}; -struct has_specialized_into_impl -{ - template - static std::false_type check(...); - template)> - static std::true_type check(::toml::from*); -}; - - -/// Intel C++ compiler can not use decltype in parent class declaration, here -/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076 -#ifdef __INTEL_COMPILER -#define decltype(...) std::enable_if::type -#endif - -template -struct has_iterator : decltype(has_iterator_impl::check(nullptr)){}; -template -struct has_value_type : decltype(has_value_type_impl::check(nullptr)){}; -template -struct has_key_type : decltype(has_key_type_impl::check(nullptr)){}; -template -struct has_mapped_type : decltype(has_mapped_type_impl::check(nullptr)){}; -template -struct has_reserve_method : decltype(has_reserve_method_impl::check(nullptr)){}; -template -struct has_push_back_method : decltype(has_push_back_method_impl::check(nullptr)){}; -template -struct is_comparable : decltype(is_comparable_impl::check(nullptr)){}; - -template class Tb, template class A> -struct has_from_toml_method -: decltype(has_from_toml_method_impl::check(nullptr)){}; - -template -struct has_into_toml_method -: decltype(has_into_toml_method_impl::check(nullptr)){}; - -template -struct has_specialized_from : decltype(has_specialized_from_impl::check(nullptr)){}; -template -struct has_specialized_into : decltype(has_specialized_into_impl::check(nullptr)){}; - -#ifdef __INTEL_COMPILER -#undef decltype -#endif - -// --------------------------------------------------------------------------- -// C++17 and/or/not - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L - -using std::conjunction; -using std::disjunction; -using std::negation; - -#else - -template struct conjunction : std::true_type{}; -template struct conjunction : T{}; -template -struct conjunction : - std::conditional(T::value), conjunction, T>::type -{}; - -template struct disjunction : std::false_type{}; -template struct disjunction : T {}; -template -struct disjunction : - std::conditional(T::value), T, disjunction>::type -{}; - -template -struct negation : std::integral_constant(T::value)>{}; - -#endif - -// --------------------------------------------------------------------------- -// type checkers - -template struct is_std_pair : std::false_type{}; -template -struct is_std_pair> : std::true_type{}; - -template struct is_std_tuple : std::false_type{}; -template -struct is_std_tuple> : std::true_type{}; - -template struct is_std_forward_list : std::false_type{}; -template -struct is_std_forward_list> : std::true_type{}; - -template struct is_chrono_duration: std::false_type{}; -template -struct is_chrono_duration>: std::true_type{}; - -template -struct is_map : conjunction< // map satisfies all the following conditions - has_iterator, // has T::iterator - has_value_type, // has T::value_type - has_key_type, // has T::key_type - has_mapped_type // has T::mapped_type - >{}; -template struct is_map : is_map{}; -template struct is_map : is_map{}; -template struct is_map : is_map{}; -template struct is_map : is_map{}; - -template -struct is_container : conjunction< - negation>, // not a map - negation>, // not a std::string -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L -#if __has_include() - negation>, // not a std::string_view -#endif // has_include() -#endif - has_iterator, // has T::iterator - has_value_type // has T::value_type - >{}; -template struct is_container : is_container{}; -template struct is_container : is_container{}; -template struct is_container : is_container{}; -template struct is_container : is_container{}; - -template -struct is_basic_value: std::false_type{}; -template struct is_basic_value : is_basic_value{}; -template struct is_basic_value : is_basic_value{}; -template struct is_basic_value : is_basic_value{}; -template struct is_basic_value : is_basic_value{}; -template class M, template class V> -struct is_basic_value<::toml::basic_value>: std::true_type{}; - -// --------------------------------------------------------------------------- -// C++14 index_sequence - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L - -using std::index_sequence; -using std::make_index_sequence; - -#else - -template struct index_sequence{}; - -template struct push_back_index_sequence{}; -template -struct push_back_index_sequence, N> -{ - typedef index_sequence type; -}; - -template -struct index_sequence_maker -{ - typedef typename push_back_index_sequence< - typename index_sequence_maker::type, N>::type type; -}; -template<> -struct index_sequence_maker<0> -{ - typedef index_sequence<0> type; -}; -template -using make_index_sequence = typename index_sequence_maker::type; - -#endif // cplusplus >= 2014 - -// --------------------------------------------------------------------------- -// C++14 enable_if_t - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L - -using std::enable_if_t; - -#else - -template -using enable_if_t = typename std::enable_if::type; - -#endif // cplusplus >= 2014 - -// --------------------------------------------------------------------------- -// return_type_of_t - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703 - -template -using return_type_of_t = std::invoke_result_t; - -#else -// result_of is deprecated after C++17 -template -using return_type_of_t = typename std::result_of::type; - -#endif - -// --------------------------------------------------------------------------- -// is_string_literal -// -// to use this, pass `typename remove_reference::type` to T. - -template -struct is_string_literal: -disjunction< - std::is_same, - conjunction< - std::is_array, - std::is_same::type> - > - >{}; - -// --------------------------------------------------------------------------- -// C++20 remove_cvref_t - -template -struct remove_cvref -{ - using type = typename std::remove_cv< - typename std::remove_reference::type>::type; -}; - -template -using remove_cvref_t = typename remove_cvref::type; - -}// detail -}//toml -#endif // TOML_TRAITS diff --git a/src/frontend/qt_sdl/toml/toml/types.hpp b/src/frontend/qt_sdl/toml/toml/types.hpp deleted file mode 100644 index 1e420e7f..00000000 --- a/src/frontend/qt_sdl/toml/toml/types.hpp +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_TYPES_HPP -#define TOML11_TYPES_HPP -#include -#include - -#include "comments.hpp" -#include "datetime.hpp" -#include "string.hpp" -#include "traits.hpp" - -namespace toml -{ - -template class Table, // map-like class - template class Array> // vector-like class -class basic_value; - -using character = char; -using key = std::string; - -#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wshadow" -#endif - -using boolean = bool; -using integer = std::int64_t; -using floating = double; // "float" is a keyword, cannot use it here. -// the following stuffs are structs defined here, so aliases are not needed. -// - string -// - offset_datetime -// - offset_datetime -// - local_datetime -// - local_date -// - local_time - -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - -// default toml::value and default array/table. these are defined after defining -// basic_value itself. -// using value = basic_value; -// using array = typename value::array_type; -// using table = typename value::table_type; - -// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in -// GCC -Wshadow=global. -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# if 7 <= __GNUC__ -# pragma GCC diagnostic ignored "-Wshadow=global" -# else // gcc-6 or older -# pragma GCC diagnostic ignored "-Wshadow" -# endif -#endif -enum class value_t : std::uint8_t -{ - empty = 0, - boolean = 1, - integer = 2, - floating = 3, - string = 4, - offset_datetime = 5, - local_datetime = 6, - local_date = 7, - local_time = 8, - array = 9, - table = 10, -}; -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - -template -inline std::basic_ostream& -operator<<(std::basic_ostream& os, value_t t) -{ - switch(t) - { - case value_t::boolean : os << "boolean"; return os; - case value_t::integer : os << "integer"; return os; - case value_t::floating : os << "floating"; return os; - case value_t::string : os << "string"; return os; - case value_t::offset_datetime : os << "offset_datetime"; return os; - case value_t::local_datetime : os << "local_datetime"; return os; - case value_t::local_date : os << "local_date"; return os; - case value_t::local_time : os << "local_time"; return os; - case value_t::array : os << "array"; return os; - case value_t::table : os << "table"; return os; - case value_t::empty : os << "empty"; return os; - default : os << "unknown"; return os; - } -} - -template, - typename alloc = std::allocator> -inline std::basic_string stringize(value_t t) -{ - std::basic_ostringstream oss; - oss << t; - return oss.str(); -} - -namespace detail -{ - -// helper to define a type that represents a value_t value. -template -using value_t_constant = std::integral_constant; - -// meta-function that convertes from value_t to the exact toml type that corresponds to. -// It takes toml::basic_value type because array and table types depend on it. -template struct enum_to_type {using type = void ;}; -template struct enum_to_type{using type = void ;}; -template struct enum_to_type{using type = boolean ;}; -template struct enum_to_type{using type = integer ;}; -template struct enum_to_type{using type = floating ;}; -template struct enum_to_type{using type = string ;}; -template struct enum_to_type{using type = offset_datetime ;}; -template struct enum_to_type{using type = local_datetime ;}; -template struct enum_to_type{using type = local_date ;}; -template struct enum_to_type{using type = local_time ;}; -template struct enum_to_type{using type = typename Value::array_type;}; -template struct enum_to_type{using type = typename Value::table_type;}; - -// meta-function that converts from an exact toml type to the enum that corresponds to. -template -struct type_to_enum : std::conditional< - std::is_same::value, // if T == array_type, - value_t_constant, // then value_t::array - typename std::conditional< // else... - std::is_same::value, // if T == table_type - value_t_constant, // then value_t::table - value_t_constant // else value_t::empty - >::type - >::type {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; -template struct type_to_enum: value_t_constant {}; - -// meta-function that checks the type T is the same as one of the toml::* types. -template -struct is_exact_toml_type : disjunction< - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same, - std::is_same - >{}; -template struct is_exact_toml_type : is_exact_toml_type{}; -template struct is_exact_toml_type : is_exact_toml_type{}; -template struct is_exact_toml_type : is_exact_toml_type{}; -template struct is_exact_toml_type: is_exact_toml_type{}; - -} // detail -} // toml - -#endif// TOML11_TYPES_H diff --git a/src/frontend/qt_sdl/toml/toml/utility.hpp b/src/frontend/qt_sdl/toml/toml/utility.hpp deleted file mode 100644 index 53a18b94..00000000 --- a/src/frontend/qt_sdl/toml/toml/utility.hpp +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_UTILITY_HPP -#define TOML11_UTILITY_HPP -#include -#include -#include - -#include "traits.hpp" -#include "version.hpp" - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L -# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]] -#elif defined(__GNUC__) -# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg))) -#elif defined(_MSC_VER) -# define TOML11_MARK_AS_DEPRECATED(msg) __declspec(deprecated(msg)) -#else -# define TOML11_MARK_AS_DEPRECATED -#endif - -namespace toml -{ - -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L - -using std::make_unique; - -#else - -template -inline std::unique_ptr make_unique(Ts&& ... args) -{ - return std::unique_ptr(new T(std::forward(args)...)); -} - -#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014 - -namespace detail -{ -template -void try_reserve_impl(Container& container, std::size_t N, std::true_type) -{ - container.reserve(N); - return; -} -template -void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept -{ - return; -} -} // detail - -template -void try_reserve(Container& container, std::size_t N) -{ - if(N <= container.size()) {return;} - detail::try_reserve_impl(container, N, detail::has_reserve_method{}); - return; -} - -namespace detail -{ -inline std::string concat_to_string_impl(std::ostringstream& oss) -{ - return oss.str(); -} -template -std::string concat_to_string_impl(std::ostringstream& oss, T&& head, Ts&& ... tail) -{ - oss << std::forward(head); - return concat_to_string_impl(oss, std::forward(tail) ... ); -} -} // detail - -template -std::string concat_to_string(Ts&& ... args) -{ - std::ostringstream oss; - oss << std::boolalpha << std::fixed; - return detail::concat_to_string_impl(oss, std::forward(args) ...); -} - -template -T from_string(const std::string& str, T opt) -{ - T v(opt); - std::istringstream iss(str); - iss >> v; - return v; -} - -namespace detail -{ -#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L -template -decltype(auto) last_one(T&& tail) noexcept -{ - return std::forward(tail); -} - -template -decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept -{ - return last_one(std::forward(tail)...); -} -#else // C++11 -// The following code -// ```cpp -// 1 | template -// 2 | auto last_one(T&& /*head*/, Ts&& ... tail) -// 3 | -> decltype(last_one(std::forward(tail)...)) -// 4 | { -// 5 | return last_one(std::forward(tail)...); -// 6 | } -// ``` -// does not work because the function `last_one(...)` is not yet defined at -// line #3, so `decltype()` cannot deduce the type returned from `last_one`. -// So we need to determine return type in a different way, like a meta func. - -template -struct last_one_in_pack -{ - using type = typename last_one_in_pack::type; -}; -template -struct last_one_in_pack -{ - using type = T; -}; -template -using last_one_in_pack_t = typename last_one_in_pack::type; - -template -T&& last_one(T&& tail) noexcept -{ - return std::forward(tail); -} -template -enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t> -last_one(T&& /*head*/, Ts&& ... tail) -{ - return last_one(std::forward(tail)...); -} - -#endif -} // detail - -}// toml -#endif // TOML11_UTILITY diff --git a/src/frontend/qt_sdl/toml/toml/value.hpp b/src/frontend/qt_sdl/toml/toml/value.hpp deleted file mode 100644 index 1b43db8d..00000000 --- a/src/frontend/qt_sdl/toml/toml/value.hpp +++ /dev/null @@ -1,2035 +0,0 @@ -// Copyright Toru Niina 2017. -// Distributed under the MIT License. -#ifndef TOML11_VALUE_HPP -#define TOML11_VALUE_HPP -#include - -#include "comments.hpp" -#include "exception.hpp" -#include "into.hpp" -#include "region.hpp" -#include "source_location.hpp" -#include "storage.hpp" -#include "traits.hpp" -#include "types.hpp" -#include "utility.hpp" - -namespace toml -{ - -namespace detail -{ - -// to show error messages. not recommended for users. -template -inline region_base const* get_region(const Value& v) -{ - return v.region_info_.get(); -} - -template -void change_region(Value& v, region reg) -{ - v.region_info_ = std::make_shared(std::move(reg)); - return; -} - -template -[[noreturn]] inline void -throw_bad_cast(const std::string& funcname, value_t actual, const Value& v) -{ - throw type_error(detail::format_underline( - concat_to_string(funcname, "bad_cast to ", Expected), { - {v.location(), concat_to_string("the actual type is ", actual)} - }), v.location()); -} - -// Throw `out_of_range` from `toml::value::at()` and `toml::find()` -// after generating an error message. -// -// The implementation is a bit complicated and there are many edge-cases. -// If you are not interested in the error message generation, just skip this. -template -[[noreturn]] void -throw_key_not_found_error(const Value& v, const key& ky) -{ - // The top-level table has its region at the first character of the file. - // That means that, in the case when a key is not found in the top-level - // table, the error message points to the first character. If the file has - // its first table at the first line, the error message would be like this. - // ```console - // [error] key "a" not found - // --> example.toml - // | - // 1 | [table] - // | ^------ in this table - // ``` - // It actually points to the top-level table at the first character, - // not `[table]`. But it is too confusing. To avoid the confusion, the error - // message should explicitly say "key not found in the top-level table", - // or "the parsed file is empty" if there is no content at all (0 bytes in file). - const auto loc = v.location(); - if(loc.line() == 1 && loc.region() == 0) - { - // First line with a zero-length region means "empty file". - // The region will be generated at `parse_toml_file` function - // if the file contains no bytes. - throw std::out_of_range(format_underline(concat_to_string( - "key \"", ky, "\" not found in the top-level table"), { - {loc, "the parsed file is empty"} - })); - } - else if(loc.line() == 1 && loc.region() == 1) - { - // Here it assumes that top-level table starts at the first character. - // The region corresponds to the top-level table will be generated at - // `parse_toml_file` function. - // It also assumes that the top-level table size is just one and - // the line number is `1`. It is always satisfied. And those conditions - // are satisfied only if the table is the top-level table. - // - // 1. one-character dot-key at the first line - // ```toml - // a.b = "c" - // ``` - // toml11 counts whole key as the table key. Here, `a.b` is the region - // of the table "a". It could be counter intuitive, but it works. - // The size of the region is 3, not 1. The above example is the shortest - // dot-key example. The size cannot be 1. - // - // 2. one-character inline-table at the first line - // ```toml - // a = {b = "c"} - // ``` - // toml11 considers the inline table body as the table region. Here, - // `{b = "c"}` is the region of the table "a". The size of the region - // is 9, not 1. The shotest inline table still has two characters, `{` - // and `}`. The size cannot be 1. - // - // 3. one-character table declaration at the first line - // ```toml - // [a] - // ``` - // toml11 considers the whole table key as the table region. Here, - // `[a]` is the table region. The size is 3, not 1. - // - throw std::out_of_range(format_underline(concat_to_string( - "key \"", ky, "\" not found in the top-level table"), { - {loc, "the top-level table starts here"} - })); - } - else - { - // normal table. - throw std::out_of_range(format_underline(concat_to_string( - "key \"", ky, "\" not found"), { {loc, "in this table"} })); - } -} - -// switch by `value_t` at the compile time. -template -struct switch_cast {}; -#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \ - template<> \ - struct switch_cast \ - { \ - template \ - static typename Value::TYPE##_type& invoke(Value& v) \ - { \ - return v.as_##TYPE(); \ - } \ - template \ - static typename Value::TYPE##_type const& invoke(const Value& v) \ - { \ - return v.as_##TYPE(); \ - } \ - template \ - static typename Value::TYPE##_type&& invoke(Value&& v) \ - { \ - return std::move(v).as_##TYPE(); \ - } \ - }; \ - /**/ -TOML11_GENERATE_SWITCH_CASTER(boolean) -TOML11_GENERATE_SWITCH_CASTER(integer) -TOML11_GENERATE_SWITCH_CASTER(floating) -TOML11_GENERATE_SWITCH_CASTER(string) -TOML11_GENERATE_SWITCH_CASTER(offset_datetime) -TOML11_GENERATE_SWITCH_CASTER(local_datetime) -TOML11_GENERATE_SWITCH_CASTER(local_date) -TOML11_GENERATE_SWITCH_CASTER(local_time) -TOML11_GENERATE_SWITCH_CASTER(array) -TOML11_GENERATE_SWITCH_CASTER(table) - -#undef TOML11_GENERATE_SWITCH_CASTER - -}// detail - -template class Table = std::unordered_map, - template class Array = std::vector> -class basic_value -{ - template - static void assigner(T& dst, U&& v) - { - const auto tmp = ::new(std::addressof(dst)) T(std::forward(v)); - assert(tmp == std::addressof(dst)); - (void)tmp; - } - - using region_base = detail::region_base; - - template class T, - template class A> - friend class basic_value; - - public: - - using comment_type = Comment; - using key_type = ::toml::key; - using value_type = basic_value; - using boolean_type = ::toml::boolean; - using integer_type = ::toml::integer; - using floating_type = ::toml::floating; - using string_type = ::toml::string; - using local_time_type = ::toml::local_time; - using local_date_type = ::toml::local_date; - using local_datetime_type = ::toml::local_datetime; - using offset_datetime_type = ::toml::offset_datetime; - using array_type = Array; - using table_type = Table; - - public: - - basic_value() noexcept - : type_(value_t::empty), - region_info_(std::make_shared(region_base{})) - {} - ~basic_value() noexcept {this->cleanup();} - - basic_value(const basic_value& v) - : type_(v.type()), region_info_(v.region_info_), comments_(v.comments_) - { - switch(v.type()) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : assigner(array_ , v.array_ ); break; - case value_t::table : assigner(table_ , v.table_ ); break; - default: break; - } - } - basic_value(basic_value&& v) - : type_(v.type()), region_info_(std::move(v.region_info_)), - comments_(std::move(v.comments_)) - { - switch(this->type_) // here this->type_ is already initialized - { - case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; - case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; - case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; - case value_t::string : assigner(string_ , std::move(v.string_ )); break; - case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; - case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; - case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; - case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; - case value_t::array : assigner(array_ , std::move(v.array_ )); break; - case value_t::table : assigner(table_ , std::move(v.table_ )); break; - default: break; - } - } - basic_value& operator=(const basic_value& v) - { - this->cleanup(); - this->region_info_ = v.region_info_; - this->comments_ = v.comments_; - this->type_ = v.type(); - switch(this->type_) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : assigner(array_ , v.array_ ); break; - case value_t::table : assigner(table_ , v.table_ ); break; - default: break; - } - return *this; - } - basic_value& operator=(basic_value&& v) - { - this->cleanup(); - this->region_info_ = std::move(v.region_info_); - this->comments_ = std::move(v.comments_); - this->type_ = v.type(); - switch(this->type_) - { - case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; - case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; - case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; - case value_t::string : assigner(string_ , std::move(v.string_ )); break; - case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; - case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; - case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; - case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; - case value_t::array : assigner(array_ , std::move(v.array_ )); break; - case value_t::table : assigner(table_ , std::move(v.table_ )); break; - default: break; - } - return *this; - } - - // overwrite comments ---------------------------------------------------- - - basic_value(const basic_value& v, std::vector com) - : type_(v.type()), region_info_(v.region_info_), - comments_(std::move(com)) - { - switch(v.type()) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : assigner(array_ , v.array_ ); break; - case value_t::table : assigner(table_ , v.table_ ); break; - default: break; - } - } - - basic_value(basic_value&& v, std::vector com) - : type_(v.type()), region_info_(std::move(v.region_info_)), - comments_(std::move(com)) - { - switch(this->type_) // here this->type_ is already initialized - { - case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; - case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; - case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; - case value_t::string : assigner(string_ , std::move(v.string_ )); break; - case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; - case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; - case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; - case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; - case value_t::array : assigner(array_ , std::move(v.array_ )); break; - case value_t::table : assigner(table_ , std::move(v.table_ )); break; - default: break; - } - } - - // ----------------------------------------------------------------------- - // conversion between different basic_values. - template class T, - template class A> - basic_value(const basic_value& v) - : type_(v.type()), region_info_(v.region_info_), comments_(v.comments()) - { - switch(v.type()) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : - { - array_type tmp(v.as_array(std::nothrow).begin(), - v.as_array(std::nothrow).end()); - assigner(array_, std::move(tmp)); - break; - } - case value_t::table : - { - table_type tmp(v.as_table(std::nothrow).begin(), - v.as_table(std::nothrow).end()); - assigner(table_, std::move(tmp)); - break; - } - default: break; - } - } - template class T, - template class A> - basic_value(const basic_value& v, std::vector com) - : type_(v.type()), region_info_(v.region_info_), - comments_(std::move(com)) - { - switch(v.type()) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : - { - array_type tmp(v.as_array(std::nothrow).begin(), - v.as_array(std::nothrow).end()); - assigner(array_, std::move(tmp)); - break; - } - case value_t::table : - { - table_type tmp(v.as_table(std::nothrow).begin(), - v.as_table(std::nothrow).end()); - assigner(table_, std::move(tmp)); - break; - } - default: break; - } - } - template class T, - template class A> - basic_value& operator=(const basic_value& v) - { - this->region_info_ = v.region_info_; - this->comments_ = comment_type(v.comments()); - this->type_ = v.type(); - switch(v.type()) - { - case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; - case value_t::integer : assigner(integer_ , v.integer_ ); break; - case value_t::floating : assigner(floating_ , v.floating_ ); break; - case value_t::string : assigner(string_ , v.string_ ); break; - case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; - case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; - case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; - case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; - case value_t::array : - { - array_type tmp(v.as_array(std::nothrow).begin(), - v.as_array(std::nothrow).end()); - assigner(array_, std::move(tmp)); - break; - } - case value_t::table : - { - table_type tmp(v.as_table(std::nothrow).begin(), - v.as_table(std::nothrow).end()); - assigner(table_, std::move(tmp)); - break; - } - default: break; - } - return *this; - } - - // boolean ============================================================== - - basic_value(boolean b) - : type_(value_t::boolean), - region_info_(std::make_shared(region_base{})) - { - assigner(this->boolean_, b); - } - basic_value& operator=(boolean b) - { - this->cleanup(); - this->type_ = value_t::boolean; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->boolean_, b); - return *this; - } - basic_value(boolean b, std::vector com) - : type_(value_t::boolean), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->boolean_, b); - } - - // integer ============================================================== - - template, detail::negation>>::value, - std::nullptr_t>::type = nullptr> - basic_value(T i) - : type_(value_t::integer), - region_info_(std::make_shared(region_base{})) - { - assigner(this->integer_, static_cast(i)); - } - - template, detail::negation>>::value, - std::nullptr_t>::type = nullptr> - basic_value& operator=(T i) - { - this->cleanup(); - this->type_ = value_t::integer; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->integer_, static_cast(i)); - return *this; - } - - template, detail::negation>>::value, - std::nullptr_t>::type = nullptr> - basic_value(T i, std::vector com) - : type_(value_t::integer), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->integer_, static_cast(i)); - } - - // floating ============================================================= - - template::value, std::nullptr_t>::type = nullptr> - basic_value(T f) - : type_(value_t::floating), - region_info_(std::make_shared(region_base{})) - { - assigner(this->floating_, static_cast(f)); - } - - - template::value, std::nullptr_t>::type = nullptr> - basic_value& operator=(T f) - { - this->cleanup(); - this->type_ = value_t::floating; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->floating_, static_cast(f)); - return *this; - } - - template::value, std::nullptr_t>::type = nullptr> - basic_value(T f, std::vector com) - : type_(value_t::floating), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->floating_, f); - } - - // string =============================================================== - - basic_value(toml::string s) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, std::move(s)); - } - basic_value& operator=(toml::string s) - { - this->cleanup(); - this->type_ = value_t::string ; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->string_, s); - return *this; - } - basic_value(toml::string s, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, std::move(s)); - } - - basic_value(std::string s) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(std::move(s))); - } - basic_value& operator=(std::string s) - { - this->cleanup(); - this->type_ = value_t::string ; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->string_, toml::string(std::move(s))); - return *this; - } - basic_value(std::string s, string_t kind) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(std::move(s), kind)); - } - basic_value(std::string s, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(std::move(s))); - } - basic_value(std::string s, string_t kind, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(std::move(s), kind)); - } - - basic_value(const char* s) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(std::string(s))); - } - basic_value& operator=(const char* s) - { - this->cleanup(); - this->type_ = value_t::string ; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->string_, toml::string(std::string(s))); - return *this; - } - basic_value(const char* s, string_t kind) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(std::string(s), kind)); - } - basic_value(const char* s, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(std::string(s))); - } - basic_value(const char* s, string_t kind, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(std::string(s), kind)); - } - -#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0 - basic_value(std::string_view s) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(s)); - } - basic_value& operator=(std::string_view s) - { - this->cleanup(); - this->type_ = value_t::string ; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->string_, toml::string(s)); - return *this; - } - basic_value(std::string_view s, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(s)); - } - basic_value(std::string_view s, string_t kind) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})) - { - assigner(this->string_, toml::string(s, kind)); - } - basic_value(std::string_view s, string_t kind, std::vector com) - : type_(value_t::string), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->string_, toml::string(s, kind)); - } -#endif - - // local date =========================================================== - - basic_value(const local_date& ld) - : type_(value_t::local_date), - region_info_(std::make_shared(region_base{})) - { - assigner(this->local_date_, ld); - } - basic_value& operator=(const local_date& ld) - { - this->cleanup(); - this->type_ = value_t::local_date; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->local_date_, ld); - return *this; - } - basic_value(const local_date& ld, std::vector com) - : type_(value_t::local_date), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->local_date_, ld); - } - - // local time =========================================================== - - basic_value(const local_time& lt) - : type_(value_t::local_time), - region_info_(std::make_shared(region_base{})) - { - assigner(this->local_time_, lt); - } - basic_value(const local_time& lt, std::vector com) - : type_(value_t::local_time), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->local_time_, lt); - } - basic_value& operator=(const local_time& lt) - { - this->cleanup(); - this->type_ = value_t::local_time; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->local_time_, lt); - return *this; - } - - template - basic_value(const std::chrono::duration& dur) - : type_(value_t::local_time), - region_info_(std::make_shared(region_base{})) - { - assigner(this->local_time_, local_time(dur)); - } - template - basic_value(const std::chrono::duration& dur, - std::vector com) - : type_(value_t::local_time), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->local_time_, local_time(dur)); - } - template - basic_value& operator=(const std::chrono::duration& dur) - { - this->cleanup(); - this->type_ = value_t::local_time; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->local_time_, local_time(dur)); - return *this; - } - - // local datetime ======================================================= - - basic_value(const local_datetime& ldt) - : type_(value_t::local_datetime), - region_info_(std::make_shared(region_base{})) - { - assigner(this->local_datetime_, ldt); - } - basic_value(const local_datetime& ldt, std::vector com) - : type_(value_t::local_datetime), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->local_datetime_, ldt); - } - basic_value& operator=(const local_datetime& ldt) - { - this->cleanup(); - this->type_ = value_t::local_datetime; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->local_datetime_, ldt); - return *this; - } - - // offset datetime ====================================================== - - basic_value(const offset_datetime& odt) - : type_(value_t::offset_datetime), - region_info_(std::make_shared(region_base{})) - { - assigner(this->offset_datetime_, odt); - } - basic_value(const offset_datetime& odt, std::vector com) - : type_(value_t::offset_datetime), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->offset_datetime_, odt); - } - basic_value& operator=(const offset_datetime& odt) - { - this->cleanup(); - this->type_ = value_t::offset_datetime; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->offset_datetime_, odt); - return *this; - } - basic_value(const std::chrono::system_clock::time_point& tp) - : type_(value_t::offset_datetime), - region_info_(std::make_shared(region_base{})) - { - assigner(this->offset_datetime_, offset_datetime(tp)); - } - basic_value(const std::chrono::system_clock::time_point& tp, - std::vector com) - : type_(value_t::offset_datetime), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->offset_datetime_, offset_datetime(tp)); - } - basic_value& operator=(const std::chrono::system_clock::time_point& tp) - { - this->cleanup(); - this->type_ = value_t::offset_datetime; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->offset_datetime_, offset_datetime(tp)); - return *this; - } - - // array ================================================================ - - basic_value(const array_type& ary) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})) - { - assigner(this->array_, ary); - } - basic_value(const array_type& ary, std::vector com) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->array_, ary); - } - basic_value& operator=(const array_type& ary) - { - this->cleanup(); - this->type_ = value_t::array ; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->array_, ary); - return *this; - } - - // array (initializer_list) ---------------------------------------------- - - template::value, - std::nullptr_t>::type = nullptr> - basic_value(std::initializer_list list) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})) - { - array_type ary(list.begin(), list.end()); - assigner(this->array_, std::move(ary)); - } - template::value, - std::nullptr_t>::type = nullptr> - basic_value(std::initializer_list list, std::vector com) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - array_type ary(list.begin(), list.end()); - assigner(this->array_, std::move(ary)); - } - template::value, - std::nullptr_t>::type = nullptr> - basic_value& operator=(std::initializer_list list) - { - this->cleanup(); - this->type_ = value_t::array; - this->region_info_ = std::make_shared(region_base{}); - - array_type ary(list.begin(), list.end()); - assigner(this->array_, std::move(ary)); - return *this; - } - - // array (STL Containers) ------------------------------------------------ - - template>, - detail::is_container - >::value, std::nullptr_t>::type = nullptr> - basic_value(const T& list) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})) - { - static_assert(std::is_convertible::value, - "elements of a container should be convertible to toml::value"); - - array_type ary(list.size()); - std::copy(list.begin(), list.end(), ary.begin()); - assigner(this->array_, std::move(ary)); - } - template>, - detail::is_container - >::value, std::nullptr_t>::type = nullptr> - basic_value(const T& list, std::vector com) - : type_(value_t::array), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - static_assert(std::is_convertible::value, - "elements of a container should be convertible to toml::value"); - - array_type ary(list.size()); - std::copy(list.begin(), list.end(), ary.begin()); - assigner(this->array_, std::move(ary)); - } - template>, - detail::is_container - >::value, std::nullptr_t>::type = nullptr> - basic_value& operator=(const T& list) - { - static_assert(std::is_convertible::value, - "elements of a container should be convertible to toml::value"); - - this->cleanup(); - this->type_ = value_t::array; - this->region_info_ = std::make_shared(region_base{}); - - array_type ary(list.size()); - std::copy(list.begin(), list.end(), ary.begin()); - assigner(this->array_, std::move(ary)); - return *this; - } - - // table ================================================================ - - basic_value(const table_type& tab) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})) - { - assigner(this->table_, tab); - } - basic_value(const table_type& tab, std::vector com) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - assigner(this->table_, tab); - } - basic_value& operator=(const table_type& tab) - { - this->cleanup(); - this->type_ = value_t::table; - this->region_info_ = std::make_shared(region_base{}); - assigner(this->table_, tab); - return *this; - } - - // initializer-list ------------------------------------------------------ - - basic_value(std::initializer_list> list) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})) - { - table_type tab; - for(const auto& elem : list) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - } - - basic_value(std::initializer_list> list, - std::vector com) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - table_type tab; - for(const auto& elem : list) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - } - basic_value& operator=(std::initializer_list> list) - { - this->cleanup(); - this->type_ = value_t::table; - this->region_info_ = std::make_shared(region_base{}); - - table_type tab; - for(const auto& elem : list) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - return *this; - } - - // other table-like ----------------------------------------------------- - - template>, - detail::is_map - >::value, std::nullptr_t>::type = nullptr> - basic_value(const Map& mp) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})) - { - table_type tab; - for(const auto& elem : mp) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - } - template>, - detail::is_map - >::value, std::nullptr_t>::type = nullptr> - basic_value(const Map& mp, std::vector com) - : type_(value_t::table), - region_info_(std::make_shared(region_base{})), - comments_(std::move(com)) - { - table_type tab; - for(const auto& elem : mp) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - } - template>, - detail::is_map - >::value, std::nullptr_t>::type = nullptr> - basic_value& operator=(const Map& mp) - { - this->cleanup(); - this->type_ = value_t::table; - this->region_info_ = std::make_shared(region_base{}); - - table_type tab; - for(const auto& elem : mp) {tab[elem.first] = elem.second;} - assigner(this->table_, std::move(tab)); - return *this; - } - - // user-defined ========================================================= - - // convert using into_toml() method ------------------------------------- - - template::value, std::nullptr_t>::type = nullptr> - basic_value(const T& ud): basic_value(ud.into_toml()) {} - - template::value, std::nullptr_t>::type = nullptr> - basic_value(const T& ud, std::vector com) - : basic_value(ud.into_toml(), std::move(com)) - {} - template::value, std::nullptr_t>::type = nullptr> - basic_value& operator=(const T& ud) - { - *this = ud.into_toml(); - return *this; - } - - // convert using into struct ----------------------------------------- - - template)> - basic_value(const T& ud): basic_value(::toml::into::into_toml(ud)) {} - template)> - basic_value(const T& ud, std::vector com) - : basic_value(::toml::into::into_toml(ud), std::move(com)) - {} - template)> - basic_value& operator=(const T& ud) - { - *this = ::toml::into::into_toml(ud); - return *this; - } - - // for internal use ------------------------------------------------------ - // - // Those constructors take detail::region that contains parse result. - - basic_value(boolean b, detail::region reg, std::vector cm) - : type_(value_t::boolean), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->boolean_, b); - } - template, detail::negation> - >::value, std::nullptr_t>::type = nullptr> - basic_value(T i, detail::region reg, std::vector cm) - : type_(value_t::integer), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->integer_, static_cast(i)); - } - template::value, std::nullptr_t>::type = nullptr> - basic_value(T f, detail::region reg, std::vector cm) - : type_(value_t::floating), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->floating_, static_cast(f)); - } - basic_value(toml::string s, detail::region reg, - std::vector cm) - : type_(value_t::string), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->string_, std::move(s)); - } - basic_value(const local_date& ld, detail::region reg, - std::vector cm) - : type_(value_t::local_date), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->local_date_, ld); - } - basic_value(const local_time& lt, detail::region reg, - std::vector cm) - : type_(value_t::local_time), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->local_time_, lt); - } - basic_value(const local_datetime& ldt, detail::region reg, - std::vector cm) - : type_(value_t::local_datetime), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->local_datetime_, ldt); - } - basic_value(const offset_datetime& odt, detail::region reg, - std::vector cm) - : type_(value_t::offset_datetime), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->offset_datetime_, odt); - } - basic_value(const array_type& ary, detail::region reg, - std::vector cm) - : type_(value_t::array), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->array_, ary); - } - basic_value(const table_type& tab, detail::region reg, - std::vector cm) - : type_(value_t::table), - region_info_(std::make_shared(std::move(reg))), - comments_(std::move(cm)) - { - assigner(this->table_, tab); - } - - template::value, - std::nullptr_t>::type = nullptr> - basic_value(std::pair parse_result, std::vector com) - : basic_value(std::move(parse_result.first), - std::move(parse_result.second), - std::move(com)) - {} - - // type checking and casting ============================================ - - template::value, - std::nullptr_t>::type = nullptr> - bool is() const noexcept - { - return detail::type_to_enum::value == this->type_; - } - bool is(value_t t) const noexcept {return t == this->type_;} - - bool is_uninitialized() const noexcept {return this->is(value_t::empty );} - bool is_boolean() const noexcept {return this->is(value_t::boolean );} - bool is_integer() const noexcept {return this->is(value_t::integer );} - bool is_floating() const noexcept {return this->is(value_t::floating );} - bool is_string() const noexcept {return this->is(value_t::string );} - bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);} - bool is_local_datetime() const noexcept {return this->is(value_t::local_datetime );} - bool is_local_date() const noexcept {return this->is(value_t::local_date );} - bool is_local_time() const noexcept {return this->is(value_t::local_time );} - bool is_array() const noexcept {return this->is(value_t::array );} - bool is_table() const noexcept {return this->is(value_t::table );} - - value_t type() const noexcept {return type_;} - - template - typename detail::enum_to_type::type& cast() & - { - if(this->type_ != T) - { - detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); - } - return detail::switch_cast::invoke(*this); - } - template - typename detail::enum_to_type::type const& cast() const& - { - if(this->type_ != T) - { - detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); - } - return detail::switch_cast::invoke(*this); - } - template - typename detail::enum_to_type::type&& cast() && - { - if(this->type_ != T) - { - detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); - } - return detail::switch_cast::invoke(std::move(*this)); - } - - // ------------------------------------------------------------------------ - // nothrow version - - boolean const& as_boolean (const std::nothrow_t&) const& noexcept {return this->boolean_;} - integer const& as_integer (const std::nothrow_t&) const& noexcept {return this->integer_;} - floating const& as_floating (const std::nothrow_t&) const& noexcept {return this->floating_;} - string const& as_string (const std::nothrow_t&) const& noexcept {return this->string_;} - offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;} - local_datetime const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;} - local_date const& as_local_date (const std::nothrow_t&) const& noexcept {return this->local_date_;} - local_time const& as_local_time (const std::nothrow_t&) const& noexcept {return this->local_time_;} - array_type const& as_array (const std::nothrow_t&) const& noexcept {return this->array_.value();} - table_type const& as_table (const std::nothrow_t&) const& noexcept {return this->table_.value();} - - boolean & as_boolean (const std::nothrow_t&) & noexcept {return this->boolean_;} - integer & as_integer (const std::nothrow_t&) & noexcept {return this->integer_;} - floating & as_floating (const std::nothrow_t&) & noexcept {return this->floating_;} - string & as_string (const std::nothrow_t&) & noexcept {return this->string_;} - offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;} - local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;} - local_date & as_local_date (const std::nothrow_t&) & noexcept {return this->local_date_;} - local_time & as_local_time (const std::nothrow_t&) & noexcept {return this->local_time_;} - array_type & as_array (const std::nothrow_t&) & noexcept {return this->array_.value();} - table_type & as_table (const std::nothrow_t&) & noexcept {return this->table_.value();} - - boolean && as_boolean (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);} - integer && as_integer (const std::nothrow_t&) && noexcept {return std::move(this->integer_);} - floating && as_floating (const std::nothrow_t&) && noexcept {return std::move(this->floating_);} - string && as_string (const std::nothrow_t&) && noexcept {return std::move(this->string_);} - offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);} - local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);} - local_date && as_local_date (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);} - local_time && as_local_time (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);} - array_type && as_array (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());} - table_type && as_table (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());} - - // ======================================================================== - // throw version - // ------------------------------------------------------------------------ - // const reference {{{ - - boolean const& as_boolean() const& - { - if(this->type_ != value_t::boolean) - { - detail::throw_bad_cast( - "toml::value::as_boolean(): ", this->type_, *this); - } - return this->boolean_; - } - integer const& as_integer() const& - { - if(this->type_ != value_t::integer) - { - detail::throw_bad_cast( - "toml::value::as_integer(): ", this->type_, *this); - } - return this->integer_; - } - floating const& as_floating() const& - { - if(this->type_ != value_t::floating) - { - detail::throw_bad_cast( - "toml::value::as_floating(): ", this->type_, *this); - } - return this->floating_; - } - string const& as_string() const& - { - if(this->type_ != value_t::string) - { - detail::throw_bad_cast( - "toml::value::as_string(): ", this->type_, *this); - } - return this->string_; - } - offset_datetime const& as_offset_datetime() const& - { - if(this->type_ != value_t::offset_datetime) - { - detail::throw_bad_cast( - "toml::value::as_offset_datetime(): ", this->type_, *this); - } - return this->offset_datetime_; - } - local_datetime const& as_local_datetime() const& - { - if(this->type_ != value_t::local_datetime) - { - detail::throw_bad_cast( - "toml::value::as_local_datetime(): ", this->type_, *this); - } - return this->local_datetime_; - } - local_date const& as_local_date() const& - { - if(this->type_ != value_t::local_date) - { - detail::throw_bad_cast( - "toml::value::as_local_date(): ", this->type_, *this); - } - return this->local_date_; - } - local_time const& as_local_time() const& - { - if(this->type_ != value_t::local_time) - { - detail::throw_bad_cast( - "toml::value::as_local_time(): ", this->type_, *this); - } - return this->local_time_; - } - array_type const& as_array() const& - { - if(this->type_ != value_t::array) - { - detail::throw_bad_cast( - "toml::value::as_array(): ", this->type_, *this); - } - return this->array_.value(); - } - table_type const& as_table() const& - { - if(this->type_ != value_t::table) - { - detail::throw_bad_cast( - "toml::value::as_table(): ", this->type_, *this); - } - return this->table_.value(); - } - // }}} - // ------------------------------------------------------------------------ - // nonconst reference {{{ - - boolean & as_boolean() & - { - if(this->type_ != value_t::boolean) - { - detail::throw_bad_cast( - "toml::value::as_boolean(): ", this->type_, *this); - } - return this->boolean_; - } - integer & as_integer() & - { - if(this->type_ != value_t::integer) - { - detail::throw_bad_cast( - "toml::value::as_integer(): ", this->type_, *this); - } - return this->integer_; - } - floating & as_floating() & - { - if(this->type_ != value_t::floating) - { - detail::throw_bad_cast( - "toml::value::as_floating(): ", this->type_, *this); - } - return this->floating_; - } - string & as_string() & - { - if(this->type_ != value_t::string) - { - detail::throw_bad_cast( - "toml::value::as_string(): ", this->type_, *this); - } - return this->string_; - } - offset_datetime & as_offset_datetime() & - { - if(this->type_ != value_t::offset_datetime) - { - detail::throw_bad_cast( - "toml::value::as_offset_datetime(): ", this->type_, *this); - } - return this->offset_datetime_; - } - local_datetime & as_local_datetime() & - { - if(this->type_ != value_t::local_datetime) - { - detail::throw_bad_cast( - "toml::value::as_local_datetime(): ", this->type_, *this); - } - return this->local_datetime_; - } - local_date & as_local_date() & - { - if(this->type_ != value_t::local_date) - { - detail::throw_bad_cast( - "toml::value::as_local_date(): ", this->type_, *this); - } - return this->local_date_; - } - local_time & as_local_time() & - { - if(this->type_ != value_t::local_time) - { - detail::throw_bad_cast( - "toml::value::as_local_time(): ", this->type_, *this); - } - return this->local_time_; - } - array_type & as_array() & - { - if(this->type_ != value_t::array) - { - detail::throw_bad_cast( - "toml::value::as_array(): ", this->type_, *this); - } - return this->array_.value(); - } - table_type & as_table() & - { - if(this->type_ != value_t::table) - { - detail::throw_bad_cast( - "toml::value::as_table(): ", this->type_, *this); - } - return this->table_.value(); - } - - // }}} - // ------------------------------------------------------------------------ - // rvalue reference {{{ - - boolean && as_boolean() && - { - if(this->type_ != value_t::boolean) - { - detail::throw_bad_cast( - "toml::value::as_boolean(): ", this->type_, *this); - } - return std::move(this->boolean_); - } - integer && as_integer() && - { - if(this->type_ != value_t::integer) - { - detail::throw_bad_cast( - "toml::value::as_integer(): ", this->type_, *this); - } - return std::move(this->integer_); - } - floating && as_floating() && - { - if(this->type_ != value_t::floating) - { - detail::throw_bad_cast( - "toml::value::as_floating(): ", this->type_, *this); - } - return std::move(this->floating_); - } - string && as_string() && - { - if(this->type_ != value_t::string) - { - detail::throw_bad_cast( - "toml::value::as_string(): ", this->type_, *this); - } - return std::move(this->string_); - } - offset_datetime && as_offset_datetime() && - { - if(this->type_ != value_t::offset_datetime) - { - detail::throw_bad_cast( - "toml::value::as_offset_datetime(): ", this->type_, *this); - } - return std::move(this->offset_datetime_); - } - local_datetime && as_local_datetime() && - { - if(this->type_ != value_t::local_datetime) - { - detail::throw_bad_cast( - "toml::value::as_local_datetime(): ", this->type_, *this); - } - return std::move(this->local_datetime_); - } - local_date && as_local_date() && - { - if(this->type_ != value_t::local_date) - { - detail::throw_bad_cast( - "toml::value::as_local_date(): ", this->type_, *this); - } - return std::move(this->local_date_); - } - local_time && as_local_time() && - { - if(this->type_ != value_t::local_time) - { - detail::throw_bad_cast( - "toml::value::as_local_time(): ", this->type_, *this); - } - return std::move(this->local_time_); - } - array_type && as_array() && - { - if(this->type_ != value_t::array) - { - detail::throw_bad_cast( - "toml::value::as_array(): ", this->type_, *this); - } - return std::move(this->array_.value()); - } - table_type && as_table() && - { - if(this->type_ != value_t::table) - { - detail::throw_bad_cast( - "toml::value::as_table(): ", this->type_, *this); - } - return std::move(this->table_.value()); - } - // }}} - - // accessors ============================================================= - // - // may throw type_error or out_of_range - // - value_type& at(const key& k) - { - if(!this->is_table()) - { - detail::throw_bad_cast( - "toml::value::at(key): ", this->type_, *this); - } - if(this->as_table(std::nothrow).count(k) == 0) - { - detail::throw_key_not_found_error(*this, k); - } - return this->as_table(std::nothrow).at(k); - } - value_type const& at(const key& k) const - { - if(!this->is_table()) - { - detail::throw_bad_cast( - "toml::value::at(key): ", this->type_, *this); - } - if(this->as_table(std::nothrow).count(k) == 0) - { - detail::throw_key_not_found_error(*this, k); - } - return this->as_table(std::nothrow).at(k); - } - value_type& operator[](const key& k) - { - if(this->is_uninitialized()) - { - *this = table_type{}; - } - else if(!this->is_table()) // initialized, but not a table - { - detail::throw_bad_cast( - "toml::value::operator[](key): ", this->type_, *this); - } - return this->as_table(std::nothrow)[k]; - } - - value_type& at(const std::size_t idx) - { - if(!this->is_array()) - { - detail::throw_bad_cast( - "toml::value::at(idx): ", this->type_, *this); - } - if(this->as_array(std::nothrow).size() <= idx) - { - throw std::out_of_range(detail::format_underline( - "toml::value::at(idx): no element corresponding to the index", { - {this->location(), concat_to_string("the length is ", - this->as_array(std::nothrow).size(), - ", and the specified index is ", idx)} - })); - } - return this->as_array().at(idx); - } - value_type const& at(const std::size_t idx) const - { - if(!this->is_array()) - { - detail::throw_bad_cast( - "toml::value::at(idx): ", this->type_, *this); - } - if(this->as_array(std::nothrow).size() <= idx) - { - throw std::out_of_range(detail::format_underline( - "toml::value::at(idx): no element corresponding to the index", { - {this->location(), concat_to_string("the length is ", - this->as_array(std::nothrow).size(), - ", and the specified index is ", idx)} - })); - } - return this->as_array(std::nothrow).at(idx); - } - - value_type& operator[](const std::size_t idx) noexcept - { - // no check... - return this->as_array(std::nothrow)[idx]; - } - value_type const& operator[](const std::size_t idx) const noexcept - { - // no check... - return this->as_array(std::nothrow)[idx]; - } - - void push_back(const value_type& x) - { - if(!this->is_array()) - { - detail::throw_bad_cast( - "toml::value::push_back(value): ", this->type_, *this); - } - this->as_array(std::nothrow).push_back(x); - return; - } - void push_back(value_type&& x) - { - if(!this->is_array()) - { - detail::throw_bad_cast( - "toml::value::push_back(value): ", this->type_, *this); - } - this->as_array(std::nothrow).push_back(std::move(x)); - return; - } - - template - value_type& emplace_back(Ts&& ... args) - { - if(!this->is_array()) - { - detail::throw_bad_cast( - "toml::value::emplace_back(...): ", this->type_, *this); - } - this->as_array(std::nothrow).emplace_back(std::forward(args) ...); - return this->as_array(std::nothrow).back(); - } - - std::size_t size() const - { - switch(this->type_) - { - case value_t::array: - { - return this->as_array(std::nothrow).size(); - } - case value_t::table: - { - return this->as_table(std::nothrow).size(); - } - case value_t::string: - { - return this->as_string(std::nothrow).str.size(); - } - default: - { - throw type_error(detail::format_underline( - "toml::value::size(): bad_cast to container types", { - {this->location(), - concat_to_string("the actual type is ", this->type_)} - }), this->location()); - } - } - } - - std::size_t count(const key_type& k) const - { - if(!this->is_table()) - { - detail::throw_bad_cast( - "toml::value::count(key): ", this->type_, *this); - } - return this->as_table(std::nothrow).count(k); - } - - bool contains(const key_type& k) const - { - if(!this->is_table()) - { - detail::throw_bad_cast( - "toml::value::contains(key): ", this->type_, *this); - } - return (this->as_table(std::nothrow).count(k) != 0); - } - - source_location location() const - { - return source_location(this->region_info_.get()); - } - - comment_type const& comments() const noexcept {return this->comments_;} - comment_type& comments() noexcept {return this->comments_;} - - private: - - void cleanup() noexcept - { - switch(this->type_) - { - case value_t::string : {string_.~string(); return;} - case value_t::array : {array_.~array_storage(); return;} - case value_t::table : {table_.~table_storage(); return;} - default : return; - } - } - - // for error messages - template - friend region_base const* detail::get_region(const Value& v); - - template - friend void detail::change_region(Value& v, detail::region reg); - - private: - - using array_storage = detail::storage; - using table_storage = detail::storage; - - value_t type_; - union - { - boolean boolean_; - integer integer_; - floating floating_; - string string_; - offset_datetime offset_datetime_; - local_datetime local_datetime_; - local_date local_date_; - local_time local_time_; - array_storage array_; - table_storage table_; - }; - std::shared_ptr region_info_; - comment_type comments_; -}; - -// default toml::value and default array/table. -// TOML11_DEFAULT_COMMENT_STRATEGY is defined in comments.hpp -using value = basic_value; -using array = typename value::array_type; -using table = typename value::table_type; - -template class T, template class A> -inline bool -operator==(const basic_value& lhs, const basic_value& rhs) -{ - if(lhs.type() != rhs.type()) {return false;} - if(lhs.comments() != rhs.comments()) {return false;} - - switch(lhs.type()) - { - case value_t::boolean : - { - return lhs.as_boolean() == rhs.as_boolean(); - } - case value_t::integer : - { - return lhs.as_integer() == rhs.as_integer(); - } - case value_t::floating : - { - return lhs.as_floating() == rhs.as_floating(); - } - case value_t::string : - { - return lhs.as_string() == rhs.as_string(); - } - case value_t::offset_datetime: - { - return lhs.as_offset_datetime() == rhs.as_offset_datetime(); - } - case value_t::local_datetime: - { - return lhs.as_local_datetime() == rhs.as_local_datetime(); - } - case value_t::local_date: - { - return lhs.as_local_date() == rhs.as_local_date(); - } - case value_t::local_time: - { - return lhs.as_local_time() == rhs.as_local_time(); - } - case value_t::array : - { - return lhs.as_array() == rhs.as_array(); - } - case value_t::table : - { - return lhs.as_table() == rhs.as_table(); - } - case value_t::empty : {return true; } - default: {return false;} - } -} - -template class T, template class A> -inline bool operator!=(const basic_value& lhs, const basic_value& rhs) -{ - return !(lhs == rhs); -} - -template class T, template class A> -typename std::enable_if::array_type>, - detail::is_comparable::table_type> - >::value, bool>::type -operator<(const basic_value& lhs, const basic_value& rhs) -{ - if(lhs.type() != rhs.type()){return (lhs.type() < rhs.type());} - switch(lhs.type()) - { - case value_t::boolean : - { - return lhs.as_boolean() < rhs.as_boolean() || - (lhs.as_boolean() == rhs.as_boolean() && - lhs.comments() < rhs.comments()); - } - case value_t::integer : - { - return lhs.as_integer() < rhs.as_integer() || - (lhs.as_integer() == rhs.as_integer() && - lhs.comments() < rhs.comments()); - } - case value_t::floating : - { - return lhs.as_floating() < rhs.as_floating() || - (lhs.as_floating() == rhs.as_floating() && - lhs.comments() < rhs.comments()); - } - case value_t::string : - { - return lhs.as_string() < rhs.as_string() || - (lhs.as_string() == rhs.as_string() && - lhs.comments() < rhs.comments()); - } - case value_t::offset_datetime: - { - return lhs.as_offset_datetime() < rhs.as_offset_datetime() || - (lhs.as_offset_datetime() == rhs.as_offset_datetime() && - lhs.comments() < rhs.comments()); - } - case value_t::local_datetime: - { - return lhs.as_local_datetime() < rhs.as_local_datetime() || - (lhs.as_local_datetime() == rhs.as_local_datetime() && - lhs.comments() < rhs.comments()); - } - case value_t::local_date: - { - return lhs.as_local_date() < rhs.as_local_date() || - (lhs.as_local_date() == rhs.as_local_date() && - lhs.comments() < rhs.comments()); - } - case value_t::local_time: - { - return lhs.as_local_time() < rhs.as_local_time() || - (lhs.as_local_time() == rhs.as_local_time() && - lhs.comments() < rhs.comments()); - } - case value_t::array : - { - return lhs.as_array() < rhs.as_array() || - (lhs.as_array() == rhs.as_array() && - lhs.comments() < rhs.comments()); - } - case value_t::table : - { - return lhs.as_table() < rhs.as_table() || - (lhs.as_table() == rhs.as_table() && - lhs.comments() < rhs.comments()); - } - case value_t::empty : - { - return lhs.comments() < rhs.comments(); - } - default: - { - return lhs.comments() < rhs.comments(); - } - } -} - -template class T, template class A> -typename std::enable_if::array_type>, - detail::is_comparable::table_type> - >::value, bool>::type -operator<=(const basic_value& lhs, const basic_value& rhs) -{ - return (lhs < rhs) || (lhs == rhs); -} -template class T, template class A> -typename std::enable_if::array_type>, - detail::is_comparable::table_type> - >::value, bool>::type -operator>(const basic_value& lhs, const basic_value& rhs) -{ - return !(lhs <= rhs); -} -template class T, template class A> -typename std::enable_if::array_type>, - detail::is_comparable::table_type> - >::value, bool>::type -operator>=(const basic_value& lhs, const basic_value& rhs) -{ - return !(lhs < rhs); -} - -template class T, template class A> -inline std::string format_error(const std::string& err_msg, - const basic_value& v, const std::string& comment, - std::vector hints = {}, - const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) -{ - return detail::format_underline(err_msg, {{v.location(), comment}}, - std::move(hints), colorize); -} - -template class T, template class A> -inline std::string format_error(const std::string& err_msg, - const toml::basic_value& v1, const std::string& comment1, - const toml::basic_value& v2, const std::string& comment2, - std::vector hints = {}, - const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) -{ - return detail::format_underline(err_msg, { - {v1.location(), comment1}, {v2.location(), comment2} - }, std::move(hints), colorize); -} - -template class T, template class A> -inline std::string format_error(const std::string& err_msg, - const toml::basic_value& v1, const std::string& comment1, - const toml::basic_value& v2, const std::string& comment2, - const toml::basic_value& v3, const std::string& comment3, - std::vector hints = {}, - const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) -{ - return detail::format_underline(err_msg, {{v1.location(), comment1}, - {v2.location(), comment2}, {v3.location(), comment3} - }, std::move(hints), colorize); -} - -template class T, template class A> -detail::return_type_of_t -visit(Visitor&& visitor, const toml::basic_value& v) -{ - switch(v.type()) - { - case value_t::boolean : {return visitor(v.as_boolean ());} - case value_t::integer : {return visitor(v.as_integer ());} - case value_t::floating : {return visitor(v.as_floating ());} - case value_t::string : {return visitor(v.as_string ());} - case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} - case value_t::local_datetime : {return visitor(v.as_local_datetime ());} - case value_t::local_date : {return visitor(v.as_local_date ());} - case value_t::local_time : {return visitor(v.as_local_time ());} - case value_t::array : {return visitor(v.as_array ());} - case value_t::table : {return visitor(v.as_table ());} - case value_t::empty : break; - default: break; - } - throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " - "does not have any valid basic_value.", v, "here")); -} - -template class T, template class A> -detail::return_type_of_t -visit(Visitor&& visitor, toml::basic_value& v) -{ - switch(v.type()) - { - case value_t::boolean : {return visitor(v.as_boolean ());} - case value_t::integer : {return visitor(v.as_integer ());} - case value_t::floating : {return visitor(v.as_floating ());} - case value_t::string : {return visitor(v.as_string ());} - case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} - case value_t::local_datetime : {return visitor(v.as_local_datetime ());} - case value_t::local_date : {return visitor(v.as_local_date ());} - case value_t::local_time : {return visitor(v.as_local_time ());} - case value_t::array : {return visitor(v.as_array ());} - case value_t::table : {return visitor(v.as_table ());} - case value_t::empty : break; - default: break; - } - throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " - "does not have any valid basic_value.", v, "here")); -} - -template class T, template class A> -detail::return_type_of_t -visit(Visitor&& visitor, toml::basic_value&& v) -{ - switch(v.type()) - { - case value_t::boolean : {return visitor(std::move(v.as_boolean ()));} - case value_t::integer : {return visitor(std::move(v.as_integer ()));} - case value_t::floating : {return visitor(std::move(v.as_floating ()));} - case value_t::string : {return visitor(std::move(v.as_string ()));} - case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));} - case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));} - case value_t::local_date : {return visitor(std::move(v.as_local_date ()));} - case value_t::local_time : {return visitor(std::move(v.as_local_time ()));} - case value_t::array : {return visitor(std::move(v.as_array ()));} - case value_t::table : {return visitor(std::move(v.as_table ()));} - case value_t::empty : break; - default: break; - } - throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " - "does not have any valid basic_value.", v, "here")); -} - -}// toml -#endif// TOML11_VALUE diff --git a/src/frontend/qt_sdl/toml/toml/version.hpp b/src/frontend/qt_sdl/toml/toml/version.hpp deleted file mode 100644 index 9cbfa39b..00000000 --- a/src/frontend/qt_sdl/toml/toml/version.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TOML11_VERSION_HPP -#define TOML11_VERSION_HPP - -// This file checks C++ version. - -#ifndef __cplusplus -# error "__cplusplus is not defined" -#endif - -// Since MSVC does not define `__cplusplus` correctly unless you pass -// `/Zc:__cplusplus` when compiling, the workaround macros are added. -// Those enables you to define version manually or to use MSVC specific -// version macro automatically. -// -// The value of `__cplusplus` macro is defined in the C++ standard spec, but -// MSVC ignores the value, maybe because of backward compatibility. Instead, -// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in -// the C++ standard. First we check the manual version definition, and then -// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`. -// -// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170 -// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 -// -#if defined(TOML11_ENFORCE_CXX11) -# define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L -#elif defined(TOML11_ENFORCE_CXX14) -# define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L -#elif defined(TOML11_ENFORCE_CXX17) -# define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L -#elif defined(TOML11_ENFORCE_CXX20) -# define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L -#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER -# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG -#else -# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus -#endif - -#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900 -# error "toml11 requires C++11 or later." -#endif - -#endif// TOML11_VERSION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/color.hpp b/src/frontend/qt_sdl/toml/toml11/color.hpp new file mode 100644 index 00000000..d40d7f80 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/color.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_COLOR_HPP +#define TOML11_COLOR_HPP + +#include "fwd/color_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/color_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_COLOR_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/comments.hpp b/src/frontend/qt_sdl/toml/toml11/comments.hpp new file mode 100644 index 00000000..4697f4e3 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/comments.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_COMMENTS_HPP +#define TOML11_COMMENTS_HPP + +#include "fwd/comments_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/comments_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_COMMENTS_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/compat.hpp b/src/frontend/qt_sdl/toml/toml11/compat.hpp new file mode 100644 index 00000000..3308a32d --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/compat.hpp @@ -0,0 +1,751 @@ +#ifndef TOML11_COMPAT_HPP +#define TOML11_COMPAT_HPP + +#include "version.hpp" + +#include +#include +#include +#include +#include + +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE +# if __has_include() +# include +# endif +#endif + +#include + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if __has_cpp_attribute(deprecated) +# define TOML11_HAS_ATTR_DEPRECATED 1 +# endif +#endif + +#if defined(TOML11_HAS_ATTR_DEPRECATED) +# define TOML11_DEPRECATED(msg) [[deprecated(msg)]] +#elif defined(__GNUC__) +# define TOML11_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) +# define TOML11_DEPRECATED(msg) __declspec(deprecated(msg)) +#else +# define TOML11_DEPRECATED(msg) +#endif + +// ---------------------------------------------------------------------------- + +#if defined(__cpp_if_constexpr) +# if __cpp_if_constexpr >= 201606L +# define TOML11_HAS_CONSTEXPR_IF 1 +# endif +#endif + +#if defined(TOML11_HAS_CONSTEXPR_IF) +# define TOML11_CONSTEXPR_IF if constexpr +#else +# define TOML11_CONSTEXPR_IF if +#endif + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if defined(__cpp_lib_make_unique) +# if __cpp_lib_make_unique >= 201304L +# define TOML11_HAS_STD_MAKE_UNIQUE 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ + +#if defined(TOML11_HAS_STD_MAKE_UNIQUE) + +using std::make_unique; + +#else + +template +std::unique_ptr make_unique(Ts&& ... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + +#endif // TOML11_HAS_STD_MAKE_UNIQUE + +} // cxx +} // toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if defined(__cpp_lib_make_reverse_iterator) +# if __cpp_lib_make_reverse_iterator >= 201402L +# define TOML11_HAS_STD_MAKE_REVERSE_ITERATOR 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +# if defined(TOML11_HAS_STD_MAKE_REVERSE_ITERATOR) + +using std::make_reverse_iterator; + +#else + +template +std::reverse_iterator make_reverse_iterator(Iterator iter) +{ + return std::reverse_iterator(iter); +} + +#endif // TOML11_HAS_STD_MAKE_REVERSE_ITERATOR + +} // cxx +} // toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE +# if defined(__cpp_lib_clamp) +# if __cpp_lib_clamp >= 201603L +# define TOML11_HAS_STD_CLAMP 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_CLAMP) + +using std::clamp; + +#else + +template +T clamp(const T& x, const T& low, const T& high) noexcept +{ + assert(low <= high); + return (std::min)((std::max)(x, low), high); +} + +#endif // TOML11_HAS_STD_CLAMP + +} // cxx +} // toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE +# if defined(__cpp_lib_bit_cast) +# if __cpp_lib_bit_cast >= 201806L +# define TOML11_HAS_STD_BIT_CAST 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_BIT_CAST) + +using std::bit_cast; + +#else + +template +U bit_cast(const T& x) noexcept +{ + static_assert(sizeof(T) == sizeof(U), ""); + static_assert(std::is_default_constructible::value, ""); + + U z; + std::memcpy(reinterpret_cast(std::addressof(z)), + reinterpret_cast(std::addressof(x)), + sizeof(T)); + + return z; +} + +#endif // TOML11_HAS_STD_BIT_CAST + +} // cxx +} // toml + +// --------------------------------------------------------------------------- +// C++20 remove_cvref_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE +# if defined(__cpp_lib_remove_cvref) +# if __cpp_lib_remove_cvref >= 201711L +# define TOML11_HAS_STD_REMOVE_CVREF 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_REMOVE_CVREF) + +using std::remove_cvref; +using std::remove_cvref_t; + +#else + +template +struct remove_cvref +{ + using type = typename std::remove_cv< + typename std::remove_reference::type>::type; +}; + +template +using remove_cvref_t = typename remove_cvref::type; + +#endif // TOML11_HAS_STD_REMOVE_CVREF + +} // cxx +} // toml + +// --------------------------------------------------------------------------- +// C++17 and/or/not + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if defined(__cpp_lib_logical_traits) +# if __cpp_lib_logical_traits >= 201510L +# define TOML11_HAS_STD_CONJUNCTION 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_CONJUNCTION) + +using std::conjunction; +using std::disjunction; +using std::negation; + +#else + +template struct conjunction : std::true_type{}; +template struct conjunction : T{}; +template +struct conjunction : + std::conditional(T::value), conjunction, T>::type +{}; + +template struct disjunction : std::false_type{}; +template struct disjunction : T {}; +template +struct disjunction : + std::conditional(T::value), T, disjunction>::type +{}; + +template +struct negation : std::integral_constant(T::value)>{}; + +#endif // TOML11_HAS_STD_CONJUNCTION + +} // cxx +} // toml + +// --------------------------------------------------------------------------- +// C++14 index_sequence + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if defined(__cpp_lib_integer_sequence) +# if __cpp_lib_integer_sequence >= 201304L +# define TOML11_HAS_STD_INTEGER_SEQUENCE 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_INTEGER_SEQUENCE) + +using std::index_sequence; +using std::make_index_sequence; + +#else + +template struct index_sequence{}; + +template +struct double_index_sequence; + +template +struct double_index_sequence> +{ + using type = index_sequence; +}; +template +struct double_index_sequence> +{ + using type = index_sequence; +}; + +template +struct index_sequence_maker +{ + using type = typename double_index_sequence< + N % 2 == 1, N/2, typename index_sequence_maker::type + >::type; +}; +template<> +struct index_sequence_maker<0> +{ + using type = index_sequence<>; +}; + +template +using make_index_sequence = typename index_sequence_maker::type; + +#endif // TOML11_HAS_STD_INTEGER_SEQUENCE + +} // cxx +} // toml + +// --------------------------------------------------------------------------- +// C++14 enable_if_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if defined(__cpp_lib_transformation_trait_aliases) +# if __cpp_lib_transformation_trait_aliases >= 201304L +# define TOML11_HAS_STD_ENABLE_IF_T 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_ENABLE_IF_T) + +using std::enable_if_t; + +#else + +template +using enable_if_t = typename std::enable_if::type; + +#endif // TOML11_HAS_STD_ENABLE_IF_T + +} // cxx +} // toml + +// --------------------------------------------------------------------------- +// return_type_of_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if defined(__cpp_lib_is_invocable) +# if __cpp_lib_is_invocable >= 201703 +# define TOML11_HAS_STD_INVOKE_RESULT 1 +# endif +# endif +#endif + +namespace toml +{ +namespace cxx +{ +#if defined(TOML11_HAS_STD_INVOKE_RESULT) + +template +using return_type_of_t = std::invoke_result_t; + +#else + +// result_of is deprecated after C++17 +template +using return_type_of_t = typename std::result_of::type; + +#endif // TOML11_HAS_STD_INVOKE_RESULT + +} // cxx +} // toml + +// ---------------------------------------------------------------------------- +// (subset of) source_location + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L +# if __has_include() +# define TOML11_HAS_STD_SOURCE_LOCATION +# endif // has_include +#endif // c++20 + +#if ! defined(TOML11_HAS_STD_SOURCE_LOCATION) +# if defined(__GNUC__) && ! defined(__clang__) +# if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE +# if __has_include() +# define TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION +# endif +# endif +# endif // GNU g++ +#endif // not TOML11_HAS_STD_SOURCE_LOCATION + +#if ! defined(TOML11_HAS_STD_SOURCE_LOCATION) && ! defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) && ! defined(__clang__) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) +# define TOML11_HAS_BUILTIN_FILE_LINE 1 +# define TOML11_BUILTIN_LINE_TYPE int +# endif +# elif defined(__clang__) // clang 9.0.0 implements builtin_FILE/LINE +# if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) +# define TOML11_HAS_BUILTIN_FILE_LINE 1 +# define TOML11_BUILTIN_LINE_TYPE unsigned int +# endif +# elif defined(_MSVC_LANG) && defined(_MSC_VER) +# if _MSC_VER > 1926 +# define TOML11_HAS_BUILTIN_FILE_LINE 1 +# define TOML11_BUILTIN_LINE_TYPE int +# endif +# endif +#endif + +#if defined(TOML11_HAS_STD_SOURCE_LOCATION) +#include +namespace toml +{ +namespace cxx +{ +using source_location = std::source_location; + +inline std::string to_string(const source_location& loc) +{ + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); +} +} // cxx +} // toml +#elif defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) +#include +namespace toml +{ +namespace cxx +{ +using source_location = std::experimental::source_location; + +inline std::string to_string(const source_location& loc) +{ + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); +} +} // cxx +} // toml +#elif defined(TOML11_HAS_BUILTIN_FILE_LINE) +namespace toml +{ +namespace cxx +{ +struct source_location +{ + using line_type = TOML11_BUILTIN_LINE_TYPE; + static source_location current(const line_type line = __builtin_LINE(), + const char* file = __builtin_FILE()) + { + return source_location(line, file); + } + + source_location(const line_type line, const char* file) + : line_(line), file_name_(file) + {} + + line_type line() const noexcept {return line_;} + const char* file_name() const noexcept {return file_name_;} + + private: + + line_type line_; + const char* file_name_; +}; + +inline std::string to_string(const source_location& loc) +{ + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); +} +} // cxx +} // toml +#else // no builtin +namespace toml +{ +namespace cxx +{ +struct source_location +{ + static source_location current() { return source_location{}; } +}; + +inline std::string to_string(const source_location&) +{ + return std::string(""); +} +} // cxx +} // toml +#endif // TOML11_HAS_STD_SOURCE_LOCATION + +// ---------------------------------------------------------------------------- +// (subset of) optional + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if __has_include() +# include +# endif // has_include(optional) +#endif // C++17 + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if defined(__cpp_lib_optional) +# if __cpp_lib_optional >= 201606L +# define TOML11_HAS_STD_OPTIONAL 1 +# endif +# endif +#endif + +#if defined(TOML11_HAS_STD_OPTIONAL) + +namespace toml +{ +namespace cxx +{ +using std::optional; + +inline std::nullopt_t make_nullopt() {return std::nullopt;} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const std::nullopt_t&) +{ + os << "nullopt"; + return os; +} + +} // cxx +} // toml + +#else // TOML11_HAS_STD_OPTIONAL + +namespace toml +{ +namespace cxx +{ + +struct nullopt_t{}; +inline nullopt_t make_nullopt() {return nullopt_t{};} + +inline bool operator==(const nullopt_t&, const nullopt_t&) noexcept {return true;} +inline bool operator!=(const nullopt_t&, const nullopt_t&) noexcept {return false;} +inline bool operator< (const nullopt_t&, const nullopt_t&) noexcept {return false;} +inline bool operator<=(const nullopt_t&, const nullopt_t&) noexcept {return true;} +inline bool operator> (const nullopt_t&, const nullopt_t&) noexcept {return false;} +inline bool operator>=(const nullopt_t&, const nullopt_t&) noexcept {return true;} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const nullopt_t&) +{ + os << "nullopt"; + return os; +} + +template +class optional +{ + public: + + using value_type = T; + + public: + + optional() noexcept : has_value_(false), null_('\0') {} + optional(nullopt_t) noexcept : has_value_(false), null_('\0') {} + + optional(const T& x): has_value_(true), value_(x) {} + optional(T&& x): has_value_(true), value_(std::move(x)) {} + + template::value, std::nullptr_t> = nullptr> + explicit optional(U&& x): has_value_(true), value_(std::forward(x)) {} + + optional(const optional& rhs): has_value_(rhs.has_value_) + { + if(rhs.has_value_) + { + this->assigner(rhs.value_); + } + } + optional(optional&& rhs): has_value_(rhs.has_value_) + { + if(this->has_value_) + { + this->assigner(std::move(rhs.value_)); + } + } + + optional& operator=(const optional& rhs) + { + if(this == std::addressof(rhs)) {return *this;} + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if(this->has_value_) + { + this->assigner(rhs.value_); + } + return *this; + } + optional& operator=(optional&& rhs) + { + if(this == std::addressof(rhs)) {return *this;} + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if(this->has_value_) + { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + + template>, std::is_constructible + >::value, std::nullptr_t> = nullptr> + explicit optional(const optional& rhs): has_value_(rhs.has_value_), null_('\0') + { + if(rhs.has_value_) + { + this->assigner(rhs.value_); + } + } + template>, std::is_constructible + >::value, std::nullptr_t> = nullptr> + explicit optional(optional&& rhs): has_value_(rhs.has_value_), null_('\0') + { + if(this->has_value_) + { + this->assigner(std::move(rhs.value_)); + } + } + + template>, std::is_constructible + >::value, std::nullptr_t> = nullptr> + optional& operator=(const optional& rhs) + { + if(this == std::addressof(rhs)) {return *this;} + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if(this->has_value_) + { + this->assigner(rhs.value_); + } + return *this; + } + + template>, std::is_constructible + >::value, std::nullptr_t> = nullptr> + optional& operator=(optional&& rhs) + { + if(this == std::addressof(rhs)) {return *this;} + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if(this->has_value_) + { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + ~optional() noexcept + { + this->cleanup(); + } + + explicit operator bool() const noexcept + { + return has_value_; + } + + bool has_value() const noexcept {return has_value_;} + + value_type const& value(source_location loc = source_location::current()) const + { + if( ! this->has_value_) + { + throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + value_type& value(source_location loc = source_location::current()) + { + if( ! this->has_value_) + { + throw std::runtime_error("optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + + value_type const& value_or(const value_type& opt) const + { + if(this->has_value_) {return this->value_;} else {return opt;} + } + value_type& value_or(value_type& opt) + { + if(this->has_value_) {return this->value_;} else {return opt;} + } + + private: + + void cleanup() noexcept + { + if(this->has_value_) + { + value_.~T(); + } + } + + template + void assigner(U&& x) + { + const auto tmp = ::new(std::addressof(this->value_)) value_type(std::forward(x)); + assert(tmp == std::addressof(this->value_)); + (void)tmp; + } + + private: + + bool has_value_; + union + { + char null_; + T value_; + }; +}; +} // cxx +} // toml +#endif // TOML11_HAS_STD_OPTIONAL + +#endif // TOML11_COMPAT_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/context.hpp b/src/frontend/qt_sdl/toml/toml11/context.hpp new file mode 100644 index 00000000..cda038fb --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/context.hpp @@ -0,0 +1,68 @@ +#ifndef TOML11_CONTEXT_HPP +#define TOML11_CONTEXT_HPP + +#include "error_info.hpp" +#include "spec.hpp" + +#include + +namespace toml +{ +namespace detail +{ + +template +class context +{ + public: + + explicit context(const spec& toml_spec) + : toml_spec_(toml_spec), errors_{} + {} + + bool has_error() const noexcept {return !errors_.empty();} + + std::vector const& errors() const noexcept {return errors_;} + + semantic_version& toml_version() noexcept {return toml_spec_.version;} + semantic_version const& toml_version() const noexcept {return toml_spec_.version;} + + spec& toml_spec() noexcept {return toml_spec_;} + spec const& toml_spec() const noexcept {return toml_spec_;} + + void report_error(error_info err) + { + this->errors_.push_back(std::move(err)); + } + + error_info pop_last_error() + { + assert( ! errors_.empty()); + auto e = std::move(errors_.back()); + errors_.pop_back(); + return e; + } + + private: + + spec toml_spec_; + std::vector errors_; +}; + +} // detail +} // toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml +{ +struct type_config; +struct ordered_type_config; +namespace detail +{ +extern template class context<::toml::type_config>; +extern template class context<::toml::ordered_type_config>; +} // detail +} // toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_CONTEXT_HPP diff --git a/src/frontend/qt_sdl/toml/toml/macros.hpp b/src/frontend/qt_sdl/toml/toml11/conversion.hpp similarity index 77% rename from src/frontend/qt_sdl/toml/toml/macros.hpp rename to src/frontend/qt_sdl/toml/toml11/conversion.hpp index e8f91aec..819a7658 100644 --- a/src/frontend/qt_sdl/toml/toml/macros.hpp +++ b/src/frontend/qt_sdl/toml/toml11/conversion.hpp @@ -1,5 +1,105 @@ -#ifndef TOML11_MACROS_HPP -#define TOML11_MACROS_HPP +#ifndef TOML11_CONVERSION_HPP +#define TOML11_CONVERSION_HPP + +#include "find.hpp" +#include "from.hpp" // IWYU pragma: keep +#include "into.hpp" // IWYU pragma: keep + +#if defined(TOML11_HAS_OPTIONAL) + +#include + +namespace toml +{ +namespace detail +{ + +template +inline constexpr bool is_optional_v = false; + +template +inline constexpr bool is_optional_v> = true; + +template +void find_member_variable_from_value(T& obj, const basic_value& v, const char* var_name) +{ + if constexpr(is_optional_v) + { + if(v.contains(var_name)) + { + obj = toml::find(v, var_name); + } + else + { + obj = std::nullopt; + } + } + else + { + obj = toml::find(v, var_name); + } +} + +template +void assign_member_variable_to_value(const T& obj, basic_value& v, const char* var_name) +{ + if constexpr(is_optional_v) + { + if(obj.has_value()) + { + v[var_name] = obj.value(); + } + } + else + { + v[var_name] = obj; + } +} + +} // detail +} // toml + +#else + +namespace toml +{ +namespace detail +{ + +template +void find_member_variable_from_value(T& obj, const basic_value& v, const char* var_name) +{ + obj = toml::find(v, var_name); +} + +template +void assign_member_variable_to_value(const T& obj, basic_value& v, const char* var_name) +{ + v[var_name] = obj; +} + +} // detail +} // toml + +#endif // optional + +// use it in the following way. +// ```cpp +// namespace foo +// { +// struct Foo +// { +// std::string s; +// double d; +// int i; +// }; +// } // foo +// +// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i) +// ``` +// +// And then you can use `toml::get(v)` and `toml::find(file, "foo");` +// #define TOML11_STRINGIZE_AUX(x) #x #define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x) @@ -65,39 +165,20 @@ #define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\ TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__) -// ---------------------------------------------------------------------------- -// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE -// use it in the following way. -// ```cpp -// namespace foo -// { -// struct Foo -// { -// std::string s; -// double d; -// int i; -// }; -// } // foo -// -// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i) -// ``` -// And then you can use `toml::find(file, "foo");` -// #define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\ - obj.VAR_NAME = toml::find(v, TOML11_STRINGIZE(VAR_NAME)); + toml::detail::find_member_variable_from_value(obj.VAR_NAME, v, TOML11_STRINGIZE(VAR_NAME)); #define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\ - v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME; + toml::detail::assign_member_variable_to_value(obj.VAR_NAME, v, TOML11_STRINGIZE(VAR_NAME)); #define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\ namespace toml { \ template<> \ struct from \ { \ - template class T, \ - template class A> \ - static NAME from_toml(const basic_value& v) \ + template \ + static NAME from_toml(const basic_value& v) \ { \ NAME obj; \ TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \ @@ -107,9 +188,10 @@ template<> \ struct into \ { \ - static value into_toml(const NAME& obj) \ + template \ + static basic_value into_toml(const NAME& obj) \ { \ - ::toml::value v = ::toml::table{}; \ + ::toml::basic_value v = typename ::toml::basic_value::table_type{}; \ TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \ return v; \ } \ @@ -118,4 +200,4 @@ #endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE -#endif// TOML11_MACROS_HPP +#endif // TOML11_CONVERSION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/datetime.hpp b/src/frontend/qt_sdl/toml/toml11/datetime.hpp new file mode 100644 index 00000000..08411800 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/datetime.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_DATETIME_HPP +#define TOML11_DATETIME_HPP + +#include "fwd/datetime_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/datetime_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_DATETIME_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/error_info.hpp b/src/frontend/qt_sdl/toml/toml11/error_info.hpp new file mode 100644 index 00000000..4575f7ac --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/error_info.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_ERROR_INFO_HPP +#define TOML11_ERROR_INFO_HPP + +#include "fwd/error_info_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/error_info_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_ERROR_INFO_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/exception.hpp b/src/frontend/qt_sdl/toml/toml11/exception.hpp new file mode 100644 index 00000000..7149eb3c --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/exception.hpp @@ -0,0 +1,17 @@ +#ifndef TOML11_EXCEPTION_HPP +#define TOML11_EXCEPTION_HPP + +#include + +namespace toml +{ + +struct exception : public std::exception +{ + public: + virtual ~exception() noexcept override = default; + virtual const char* what() const noexcept override {return "";} +}; + +} // toml +#endif // TOMl11_EXCEPTION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/find.hpp b/src/frontend/qt_sdl/toml/toml11/find.hpp new file mode 100644 index 00000000..560db2a7 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/find.hpp @@ -0,0 +1,377 @@ +#ifndef TOML11_FIND_HPP +#define TOML11_FIND_HPP + +#include + +#include "get.hpp" +#include "value.hpp" + +#if defined(TOML11_HAS_STRING_VIEW) +#include +#endif + +namespace toml +{ + +// ---------------------------------------------------------------------------- +// find(value, key); + +template +decltype(::toml::get(std::declval const&>())) +find(const basic_value& v, const typename basic_value::key_type& ky) +{ + return ::toml::get(v.at(ky)); +} + +template +decltype(::toml::get(std::declval&>())) +find(basic_value& v, const typename basic_value::key_type& ky) +{ + return ::toml::get(v.at(ky)); +} + +template +decltype(::toml::get(std::declval&&>())) +find(basic_value&& v, const typename basic_value::key_type& ky) +{ + return ::toml::get(std::move(v.at(ky))); +} + +// ---------------------------------------------------------------------------- +// find(value, idx) + +template +decltype(::toml::get(std::declval const&>())) +find(const basic_value& v, const std::size_t idx) +{ + return ::toml::get(v.at(idx)); +} +template +decltype(::toml::get(std::declval&>())) +find(basic_value& v, const std::size_t idx) +{ + return ::toml::get(v.at(idx)); +} +template +decltype(::toml::get(std::declval&&>())) +find(basic_value&& v, const std::size_t idx) +{ + return ::toml::get(std::move(v.at(idx))); +} + +// ---------------------------------------------------------------------------- +// find(value, key/idx), w/o conversion + +template +cxx::enable_if_t::value, basic_value>& +find(basic_value& v, const typename basic_value::key_type& ky) +{ + return v.at(ky); +} +template +cxx::enable_if_t::value, basic_value> const& +find(basic_value const& v, const typename basic_value::key_type& ky) +{ + return v.at(ky); +} +template +cxx::enable_if_t::value, basic_value> +find(basic_value&& v, const typename basic_value::key_type& ky) +{ + return basic_value(std::move(v.at(ky))); +} + +template +cxx::enable_if_t::value, basic_value>& +find(basic_value& v, const std::size_t idx) +{ + return v.at(idx); +} +template +cxx::enable_if_t::value, basic_value> const& +find(basic_value const& v, const std::size_t idx) +{ + return v.at(idx); +} +template +cxx::enable_if_t::value, basic_value> +find(basic_value&& v, const std::size_t idx) +{ + return basic_value(std::move(v.at(idx))); +} + +// -------------------------------------------------------------------------- +// toml::find(toml::value, toml::key, Ts&& ... keys) + +namespace detail +{ + +// It suppresses warnings by -Wsign-conversion when we pass integer literal +// to toml::find. integer literal `0` is deduced as an int, and will be +// converted to std::size_t. This causes sign-conversion. + +template +std::size_t key_cast(const std::size_t& v) noexcept +{ + return v; +} +template +cxx::enable_if_t>::value, std::size_t> +key_cast(const T& v) noexcept +{ + return static_cast(v); +} + +// for string-like (string, string literal, string_view) + +template +typename basic_value::key_type const& +key_cast(const typename basic_value::key_type& v) noexcept +{ + return v; +} +template +typename basic_value::key_type +key_cast(const typename basic_value::key_type::value_type* v) +{ + return typename basic_value::key_type(v); +} +#if defined(TOML11_HAS_STRING_VIEW) +template +typename basic_value::key_type +key_cast(const std::string_view v) +{ + return typename basic_value::key_type(v); +} +#endif // string_view + +} // detail + +// ---------------------------------------------------------------------------- +// find(v, keys...) + +template +cxx::enable_if_t::value, basic_value> const& +find(const basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); +} +template +cxx::enable_if_t::value, basic_value>& +find(basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); +} +template +cxx::enable_if_t::value, basic_value> +find(basic_value&& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(std::move(v.at(detail::key_cast(k1))), detail::key_cast(k2), ks...); +} + +// ---------------------------------------------------------------------------- +// find(v, keys...) + +template +decltype(::toml::get(std::declval&>())) +find(const basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); +} +template +decltype(::toml::get(std::declval&>())) +find(basic_value& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); +} +template +decltype(::toml::get(std::declval&&>())) +find(basic_value&& v, const K1& k1, const K2& k2, const Ks& ... ks) +{ + return find(std::move(v.at(detail::key_cast(k1))), detail::key_cast(k2), ks...); +} + +// =========================================================================== +// find_or(value, key, fallback) + +// --------------------------------------------------------------------------- +// find_or(v, key, other_v) + +template +cxx::enable_if_t::value, basic_value>& +find_or(basic_value& v, const K& k, basic_value& opt) noexcept +{ + try + { + return ::toml::find(v, detail::key_cast(k)); + } + catch(...) + { + return opt; + } +} +template +cxx::enable_if_t::value, basic_value> const& +find_or(const basic_value& v, const K& k, const basic_value& opt) noexcept +{ + try + { + return ::toml::find(v, detail::key_cast(k)); + } + catch(...) + { + return opt; + } +} +template +cxx::enable_if_t::value, basic_value> +find_or(basic_value&& v, const K& k, basic_value&& opt) noexcept +{ + try + { + return ::toml::find(v, detail::key_cast(k)); + } + catch(...) + { + return opt; + } +} + +// --------------------------------------------------------------------------- +// toml types (return type can be a reference) + +template +cxx::enable_if_t>::value, + cxx::remove_cvref_t const&> +find_or(const basic_value& v, const K& k, const T& opt) +{ + try + { + return ::toml::get(v.at(detail::key_cast(k))); + } + catch(...) + { + return opt; + } +} + +template +cxx::enable_if_t>, + detail::is_exact_toml_type> + >::value, cxx::remove_cvref_t&> +find_or(basic_value& v, const K& k, T& opt) +{ + try + { + return ::toml::get(v.at(detail::key_cast(k))); + } + catch(...) + { + return opt; + } +} + +template +cxx::enable_if_t>::value, + cxx::remove_cvref_t> +find_or(basic_value&& v, const K& k, T opt) +{ + try + { + return ::toml::get(std::move(v.at(detail::key_cast(k)))); + } + catch(...) + { + return T(std::move(opt)); + } +} + +// --------------------------------------------------------------------------- +// string literal (deduced as std::string) + +// XXX to avoid confusion when T is explicitly specified in find_or(), +// we restrict the string type as std::string. +template +cxx::enable_if_t::value, std::string> +find_or(const basic_value& v, const K& k, const char* opt) +{ + try + { + return ::toml::get(v.at(detail::key_cast(k))); + } + catch(...) + { + return std::string(opt); + } +} + +// --------------------------------------------------------------------------- +// other types (requires type conversion and return type cannot be a reference) + +template +cxx::enable_if_t>>, + detail::is_not_toml_type, basic_value>, + cxx::negation, + const typename basic_value::string_type::value_type*>> + >::value, cxx::remove_cvref_t> +find_or(const basic_value& v, const K& ky, T opt) +{ + try + { + return ::toml::get>(v.at(detail::key_cast(ky))); + } + catch(...) + { + return cxx::remove_cvref_t(std::move(opt)); + } +} + +// ---------------------------------------------------------------------------- +// recursive + +namespace detail +{ + +template +auto last_one(Ts&&... args) + -> decltype(std::get(std::forward_as_tuple(std::forward(args)...))) +{ + return std::get(std::forward_as_tuple(std::forward(args)...)); +} + +} // detail + +template +auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&& ... keys) noexcept + -> cxx::enable_if_t< + detail::is_basic_value>::value, + decltype(find_or(v, k2, std::forward(k3), std::forward(keys)...)) + > +{ + try + { + return find_or(v.at(k1), k2, std::forward(k3), std::forward(keys)...); + } + catch(...) + { + return detail::last_one(k3, keys...); + } +} + +template +T find_or(const basic_value& v, const K1& k1, const K2& k2, const K3& k3, const Ks& ... keys) noexcept +{ + try + { + return find_or(v.at(k1), k2, k3, keys...); + } + catch(...) + { + return static_cast(detail::last_one(k3, keys...)); + } +} + +} // toml +#endif // TOML11_FIND_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/format.hpp b/src/frontend/qt_sdl/toml/toml11/format.hpp new file mode 100644 index 00000000..6662220d --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/format.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_FORMAT_HPP +#define TOML11_FORMAT_HPP + +#include "fwd/format_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/format_impl.hpp" // IWYU pragma: export +#endif + +#endif// TOML11_FORMAT_HPP diff --git a/src/frontend/qt_sdl/toml/toml/from.hpp b/src/frontend/qt_sdl/toml/toml11/from.hpp similarity index 78% rename from src/frontend/qt_sdl/toml/toml/from.hpp rename to src/frontend/qt_sdl/toml/toml11/from.hpp index 10815caf..d2e0e132 100644 --- a/src/frontend/qt_sdl/toml/toml/from.hpp +++ b/src/frontend/qt_sdl/toml/toml11/from.hpp @@ -1,5 +1,3 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. #ifndef TOML11_FROM_HPP #define TOML11_FROM_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/color_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/color_fwd.hpp new file mode 100644 index 00000000..ed711c0d --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/color_fwd.hpp @@ -0,0 +1,88 @@ +#ifndef TOML11_COLOR_FWD_HPP +#define TOML11_COLOR_FWD_HPP + +#include + +#ifdef TOML11_COLORIZE_ERROR_MESSAGE +#define TOML11_ERROR_MESSAGE_COLORIZED true +#else +#define TOML11_ERROR_MESSAGE_COLORIZED false +#endif + +#ifdef TOML11_USE_THREAD_LOCAL_COLORIZATION +#define TOML11_THREAD_LOCAL_COLORIZATION thread_local +#else +#define TOML11_THREAD_LOCAL_COLORIZATION +#endif + +namespace toml +{ +namespace color +{ +// put ANSI escape sequence to ostream +inline namespace ansi +{ +namespace detail +{ + +// Control color mode globally +class color_mode +{ + public: + + void enable() noexcept + { + should_color_ = true; + } + void disable() noexcept + { + should_color_ = false; + } + bool should_color() const noexcept + { + return should_color_; + } + + private: + + bool should_color_ = TOML11_ERROR_MESSAGE_COLORIZED; +}; + +inline color_mode& color_status() noexcept +{ + static TOML11_THREAD_LOCAL_COLORIZATION color_mode status; + return status; +} + +} // detail + +std::ostream& reset (std::ostream& os); +std::ostream& bold (std::ostream& os); +std::ostream& grey (std::ostream& os); +std::ostream& gray (std::ostream& os); +std::ostream& red (std::ostream& os); +std::ostream& green (std::ostream& os); +std::ostream& yellow (std::ostream& os); +std::ostream& blue (std::ostream& os); +std::ostream& magenta(std::ostream& os); +std::ostream& cyan (std::ostream& os); +std::ostream& white (std::ostream& os); + +} // ansi + +inline void enable() +{ + return detail::color_status().enable(); +} +inline void disable() +{ + return detail::color_status().disable(); +} +inline bool should_color() +{ + return detail::color_status().should_color(); +} + +} // color +} // toml +#endif // TOML11_COLOR_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml/comments.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/comments_fwd.hpp similarity index 86% rename from src/frontend/qt_sdl/toml/toml/comments.hpp rename to src/frontend/qt_sdl/toml/toml11/fwd/comments_fwd.hpp index ec250411..bbc9926b 100644 --- a/src/frontend/qt_sdl/toml/toml/comments.hpp +++ b/src/frontend/qt_sdl/toml/toml11/fwd/comments_fwd.hpp @@ -1,7 +1,10 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. -#ifndef TOML11_COMMENTS_HPP -#define TOML11_COMMENTS_HPP +#ifndef TOML11_COMMENTS_FWD_HPP +#define TOML11_COMMENTS_FWD_HPP + +// to use __has_builtin +#include "../version.hpp" // IWYU pragma: keep + +#include #include #include #include @@ -9,12 +12,7 @@ #include #include #include - -#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT -# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments -#else -# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments -#endif +#include // This file provides mainly two classes, `preserve_comments` and `discard_comments`. // Those two are a container that have the same interface as `std::vector` @@ -25,16 +23,11 @@ // error whenever you access to the element. namespace toml { -struct discard_comments; // forward decl +class discard_comments; // forward decl -// use it in the following way -// -// const toml::basic_value data = -// toml::parse("example.toml"); -// -// the interface is almost the same as std::vector. -struct preserve_comments +class preserve_comments { + public: // `container_type` is not provided in discard_comments. // do not use this inner-type in a generic code. using container_type = std::vector; @@ -51,6 +44,8 @@ struct preserve_comments using reverse_iterator = container_type::reverse_iterator; using const_reverse_iterator = container_type::const_reverse_iterator; + public: + preserve_comments() = default; ~preserve_comments() = default; preserve_comments(preserve_comments const&) = default; @@ -90,11 +85,9 @@ struct preserve_comments // Related to the issue #97. // - // It is known that `std::vector::insert` and `std::vector::erase` in - // the standard library implementation included in GCC 4.8.5 takes - // `std::vector::iterator` instead of `std::vector::const_iterator`. - // Because of the const-correctness, we cannot convert a `const_iterator` to - // an `iterator`. It causes compilation error in GCC 4.8.5. + // `std::vector::insert` and `std::vector::erase` in the STL implementation + // included in GCC 4.8.5 takes `std::vector::iterator` instead of + // `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5. #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__) # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805 # define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION @@ -233,39 +226,18 @@ struct preserve_comments container_type comments; }; -inline bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;} -inline bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;} -inline bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;} -inline bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;} -inline bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;} -inline bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;} +bool operator==(const preserve_comments& lhs, const preserve_comments& rhs); +bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs); +bool operator< (const preserve_comments& lhs, const preserve_comments& rhs); +bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs); +bool operator> (const preserve_comments& lhs, const preserve_comments& rhs); +bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs); -inline void swap(preserve_comments& lhs, preserve_comments& rhs) -{ - lhs.swap(rhs); - return; -} -inline void swap(preserve_comments& lhs, std::vector& rhs) -{ - lhs.comments.swap(rhs); - return; -} -inline void swap(std::vector& lhs, preserve_comments& rhs) -{ - lhs.swap(rhs.comments); - return; -} +void swap(preserve_comments& lhs, preserve_comments& rhs); +void swap(preserve_comments& lhs, std::vector& rhs); +void swap(std::vector& lhs, preserve_comments& rhs); -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const preserve_comments& com) -{ - for(const auto& c : com) - { - os << '#' << c << '\n'; - } - return os; -} +std::ostream& operator<<(std::ostream& os, const preserve_comments& com); namespace detail { @@ -349,8 +321,9 @@ operator+(const empty_iterator& lhs, typename empty_iterator::differ // efficiency, this is chosen as a default. // // To reduce the memory footprint, later we can try empty base optimization (EBO). -struct discard_comments +class discard_comments { + public: using size_type = std::size_t; using difference_type = std::ptrdiff_t; using value_type = std::string; @@ -363,6 +336,7 @@ struct discard_comments using reverse_iterator = detail::empty_iterator; using const_reverse_iterator = detail::empty_iterator; + public: discard_comments() = default; ~discard_comments() = default; discard_comments(discard_comments const&) = default; @@ -425,14 +399,14 @@ struct discard_comments // empty, so accessing through operator[], front/back, data causes address // error. - reference operator[](const size_type) noexcept {return *data();} - const_reference operator[](const size_type) const noexcept {return *data();} + reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");} + const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");} reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");} const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");} - reference front() noexcept {return *data();} - const_reference front() const noexcept {return *data();} - reference back() noexcept {return *data();} - const_reference back() const noexcept {return *data();} + reference front() noexcept {never_call("toml::discard_comment::front");} + const_reference front() const noexcept {never_call("toml::discard_comment::front");} + reference back() noexcept {never_call("toml::discard_comment::back");} + const_reference back() const noexcept {never_call("toml::discard_comment::back");} pointer data() noexcept {return nullptr;} const_pointer data() const noexcept {return nullptr;} @@ -450,6 +424,16 @@ struct discard_comments const_reverse_iterator rend() const noexcept {return const_iterator{};} const_reverse_iterator crbegin() const noexcept {return const_iterator{};} const_reverse_iterator crend() const noexcept {return const_iterator{};} + + private: + + [[noreturn]] static void never_call(const char *const this_function) + { +#if __has_builtin(__builtin_unreachable) + __builtin_unreachable(); +#endif + throw std::logic_error{this_function}; + } }; inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;} @@ -461,12 +445,7 @@ inline bool operator>=(const discard_comments&, const discard_comments&) noexcep inline void swap(const discard_comments&, const discard_comments&) noexcept {return;} -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const discard_comments&) -{ - return os; -} +inline std::ostream& operator<<(std::ostream& os, const discard_comments&) {return os;} } // toml11 -#endif// TOML11_COMMENTS_HPP +#endif // TOML11_COMMENTS_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/datetime_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/datetime_fwd.hpp new file mode 100644 index 00000000..44616a17 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/datetime_fwd.hpp @@ -0,0 +1,261 @@ +#ifndef TOML11_DATETIME_FWD_HPP +#define TOML11_DATETIME_FWD_HPP + +#include +#include +#include + +#include +#include +#include + +namespace toml +{ + +enum class month_t : std::uint8_t +{ + Jan = 0, + Feb = 1, + Mar = 2, + Apr = 3, + May = 4, + Jun = 5, + Jul = 6, + Aug = 7, + Sep = 8, + Oct = 9, + Nov = 10, + Dec = 11 +}; + +// ---------------------------------------------------------------------------- + +struct local_date +{ + std::int16_t year{0}; // A.D. (like, 2018) + std::uint8_t month{0}; // [0, 11] + std::uint8_t day{0}; // [1, 31] + + local_date(int y, month_t m, int d) + : year {static_cast(y)}, + month{static_cast(m)}, + day {static_cast(d)} + {} + + explicit local_date(const std::tm& t) + : year {static_cast(t.tm_year + 1900)}, + month{static_cast(t.tm_mon)}, + day {static_cast(t.tm_mday)} + {} + + explicit local_date(const std::chrono::system_clock::time_point& tp); + explicit local_date(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_date() = default; + ~local_date() = default; + local_date(local_date const&) = default; + local_date(local_date&&) = default; + local_date& operator=(local_date const&) = default; + local_date& operator=(local_date&&) = default; +}; +bool operator==(const local_date& lhs, const local_date& rhs); +bool operator!=(const local_date& lhs, const local_date& rhs); +bool operator< (const local_date& lhs, const local_date& rhs); +bool operator<=(const local_date& lhs, const local_date& rhs); +bool operator> (const local_date& lhs, const local_date& rhs); +bool operator>=(const local_date& lhs, const local_date& rhs); + +std::ostream& operator<<(std::ostream& os, const local_date& date); +std::string to_string(const local_date& date); + +// ----------------------------------------------------------------------------- + +struct local_time +{ + std::uint8_t hour{0}; // [0, 23] + std::uint8_t minute{0}; // [0, 59] + std::uint8_t second{0}; // [0, 60] + std::uint16_t millisecond{0}; // [0, 999] + std::uint16_t microsecond{0}; // [0, 999] + std::uint16_t nanosecond{0}; // [0, 999] + + local_time(int h, int m, int s, + int ms = 0, int us = 0, int ns = 0) + : hour {static_cast(h)}, + minute{static_cast(m)}, + second{static_cast(s)}, + millisecond{static_cast(ms)}, + microsecond{static_cast(us)}, + nanosecond {static_cast(ns)} + {} + + explicit local_time(const std::tm& t) + : hour {static_cast(t.tm_hour)}, + minute{static_cast(t.tm_min )}, + second{static_cast(t.tm_sec )}, + millisecond{0}, microsecond{0}, nanosecond{0} + {} + + template + explicit local_time(const std::chrono::duration& t) + { + const auto h = std::chrono::duration_cast(t); + this->hour = static_cast(h.count()); + const auto t2 = t - h; + const auto m = std::chrono::duration_cast(t2); + this->minute = static_cast(m.count()); + const auto t3 = t2 - m; + const auto s = std::chrono::duration_cast(t3); + this->second = static_cast(s.count()); + const auto t4 = t3 - s; + const auto ms = std::chrono::duration_cast(t4); + this->millisecond = static_cast(ms.count()); + const auto t5 = t4 - ms; + const auto us = std::chrono::duration_cast(t5); + this->microsecond = static_cast(us.count()); + const auto t6 = t5 - us; + const auto ns = std::chrono::duration_cast(t6); + this->nanosecond = static_cast(ns.count()); + } + + operator std::chrono::nanoseconds() const; + + local_time() = default; + ~local_time() = default; + local_time(local_time const&) = default; + local_time(local_time&&) = default; + local_time& operator=(local_time const&) = default; + local_time& operator=(local_time&&) = default; +}; + +bool operator==(const local_time& lhs, const local_time& rhs); +bool operator!=(const local_time& lhs, const local_time& rhs); +bool operator< (const local_time& lhs, const local_time& rhs); +bool operator<=(const local_time& lhs, const local_time& rhs); +bool operator> (const local_time& lhs, const local_time& rhs); +bool operator>=(const local_time& lhs, const local_time& rhs); + +std::ostream& operator<<(std::ostream& os, const local_time& time); +std::string to_string(const local_time& time); + +// ---------------------------------------------------------------------------- + +struct time_offset +{ + std::int8_t hour{0}; // [-12, 12] + std::int8_t minute{0}; // [-59, 59] + + time_offset(int h, int m) + : hour {static_cast(h)}, + minute{static_cast(m)} + {} + + operator std::chrono::minutes() const; + + time_offset() = default; + ~time_offset() = default; + time_offset(time_offset const&) = default; + time_offset(time_offset&&) = default; + time_offset& operator=(time_offset const&) = default; + time_offset& operator=(time_offset&&) = default; +}; + +bool operator==(const time_offset& lhs, const time_offset& rhs); +bool operator!=(const time_offset& lhs, const time_offset& rhs); +bool operator< (const time_offset& lhs, const time_offset& rhs); +bool operator<=(const time_offset& lhs, const time_offset& rhs); +bool operator> (const time_offset& lhs, const time_offset& rhs); +bool operator>=(const time_offset& lhs, const time_offset& rhs); + +std::ostream& operator<<(std::ostream& os, const time_offset& offset); + +std::string to_string(const time_offset& offset); + +// ----------------------------------------------------------------------------- + +struct local_datetime +{ + local_date date{}; + local_time time{}; + + local_datetime(local_date d, local_time t): date{d}, time{t} {} + + explicit local_datetime(const std::tm& t): date{t}, time{t}{} + + explicit local_datetime(const std::chrono::system_clock::time_point& tp); + explicit local_datetime(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_datetime() = default; + ~local_datetime() = default; + local_datetime(local_datetime const&) = default; + local_datetime(local_datetime&&) = default; + local_datetime& operator=(local_datetime const&) = default; + local_datetime& operator=(local_datetime&&) = default; +}; + +bool operator==(const local_datetime& lhs, const local_datetime& rhs); +bool operator!=(const local_datetime& lhs, const local_datetime& rhs); +bool operator< (const local_datetime& lhs, const local_datetime& rhs); +bool operator<=(const local_datetime& lhs, const local_datetime& rhs); +bool operator> (const local_datetime& lhs, const local_datetime& rhs); +bool operator>=(const local_datetime& lhs, const local_datetime& rhs); + +std::ostream& operator<<(std::ostream& os, const local_datetime& dt); + +std::string to_string(const local_datetime& dt); + +// ----------------------------------------------------------------------------- + +struct offset_datetime +{ + local_date date{}; + local_time time{}; + time_offset offset{}; + + offset_datetime(local_date d, local_time t, time_offset o) + : date{d}, time{t}, offset{o} + {} + offset_datetime(const local_datetime& dt, time_offset o) + : date{dt.date}, time{dt.time}, offset{o} + {} + // use the current local timezone offset + explicit offset_datetime(const local_datetime& ld); + explicit offset_datetime(const std::chrono::system_clock::time_point& tp); + explicit offset_datetime(const std::time_t& t); + explicit offset_datetime(const std::tm& t); + + operator std::chrono::system_clock::time_point() const; + + operator std::time_t() const; + + offset_datetime() = default; + ~offset_datetime() = default; + offset_datetime(offset_datetime const&) = default; + offset_datetime(offset_datetime&&) = default; + offset_datetime& operator=(offset_datetime const&) = default; + offset_datetime& operator=(offset_datetime&&) = default; + + private: + + static time_offset get_local_offset(const std::time_t* tp); +}; + +bool operator==(const offset_datetime& lhs, const offset_datetime& rhs); +bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs); +bool operator< (const offset_datetime& lhs, const offset_datetime& rhs); +bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs); +bool operator> (const offset_datetime& lhs, const offset_datetime& rhs); +bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs); + +std::ostream& operator<<(std::ostream& os, const offset_datetime& dt); + +std::string to_string(const offset_datetime& dt); + +}//toml +#endif // TOML11_DATETIME_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/error_info_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/error_info_fwd.hpp new file mode 100644 index 00000000..5b8600cb --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/error_info_fwd.hpp @@ -0,0 +1,97 @@ +#ifndef TOML11_ERROR_INFO_FWD_HPP +#define TOML11_ERROR_INFO_FWD_HPP + +#include "../source_location.hpp" +#include "../utility.hpp" + +namespace toml +{ + +// error info returned from parser. +struct error_info +{ + error_info(std::string t, source_location l, std::string m, std::string s = "") + : title_(std::move(t)), locations_{std::make_pair(std::move(l), std::move(m))}, + suffix_(std::move(s)) + {} + + error_info(std::string t, std::vector> l, + std::string s = "") + : title_(std::move(t)), locations_(std::move(l)), suffix_(std::move(s)) + {} + + std::string const& title() const noexcept {return title_;} + std::string & title() noexcept {return title_;} + + std::vector> const& + locations() const noexcept {return locations_;} + + void add_locations(source_location loc, std::string msg) noexcept + { + locations_.emplace_back(std::move(loc), std::move(msg)); + } + + std::string const& suffix() const noexcept {return suffix_;} + std::string & suffix() noexcept {return suffix_;} + + private: + + std::string title_; + std::vector> locations_; + std::string suffix_; // hint or something like that +}; + +// forward decl +template +class basic_value; + +namespace detail +{ +inline error_info make_error_info_rec(error_info e) +{ + return e; +} +inline error_info make_error_info_rec(error_info e, std::string s) +{ + e.suffix() = s; + return e; +} + +template +error_info make_error_info_rec(error_info e, + const basic_value& v, std::string msg, Ts&& ... tail); + +template +error_info make_error_info_rec(error_info e, + source_location loc, std::string msg, Ts&& ... tail) +{ + e.add_locations(std::move(loc), std::move(msg)); + return make_error_info_rec(std::move(e), std::forward(tail)...); +} + +} // detail + +template +error_info make_error_info( + std::string title, source_location loc, std::string msg, Ts&& ... tail) +{ + error_info ei(std::move(title), std::move(loc), std::move(msg)); + return detail::make_error_info_rec(ei, std::forward(tail) ... ); +} + +std::string format_error(const std::string& errkind, const error_info& err); +std::string format_error(const error_info& err); + +// for custom error message +template +std::string format_error(std::string title, + source_location loc, std::string msg, Ts&& ... tail) +{ + return format_error("", make_error_info(std::move(title), + std::move(loc), std::move(msg), std::forward(tail)...)); +} + +std::ostream& operator<<(std::ostream& os, const error_info& e); + +} // toml +#endif // TOML11_ERROR_INFO_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/format_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/format_fwd.hpp new file mode 100644 index 00000000..d478d96f --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/format_fwd.hpp @@ -0,0 +1,250 @@ +#ifndef TOML11_FORMAT_FWD_HPP +#define TOML11_FORMAT_FWD_HPP + +#include +#include +#include + +#include +#include + +namespace toml +{ + +// toml types with serialization info + +enum class indent_char : std::uint8_t +{ + space, // use space + tab, // use tab + none // no indent +}; + +std::ostream& operator<<(std::ostream& os, const indent_char& c); +std::string to_string(const indent_char c); + +// ---------------------------------------------------------------------------- +// boolean + +struct boolean_format_info +{ + // nothing, for now +}; + +inline bool operator==(const boolean_format_info&, const boolean_format_info&) noexcept +{ + return true; +} +inline bool operator!=(const boolean_format_info&, const boolean_format_info&) noexcept +{ + return false; +} + +// ---------------------------------------------------------------------------- +// integer + +enum class integer_format : std::uint8_t +{ + dec = 0, + bin = 1, + oct = 2, + hex = 3, +}; + +std::ostream& operator<<(std::ostream& os, const integer_format f); +std::string to_string(const integer_format); + +struct integer_format_info +{ + integer_format fmt = integer_format::dec; + bool uppercase = true; // hex with uppercase + std::size_t width = 0; // minimal width (may exceed) + std::size_t spacer = 0; // position of `_` (if 0, no spacer) + std::string suffix = ""; // _suffix (library extension) +}; + +bool operator==(const integer_format_info&, const integer_format_info&) noexcept; +bool operator!=(const integer_format_info&, const integer_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// floating + +enum class floating_format : std::uint8_t +{ + defaultfloat = 0, + fixed = 1, // does not include exponential part + scientific = 2, // always include exponential part + hex = 3 // hexfloat extension +}; + +std::ostream& operator<<(std::ostream& os, const floating_format f); +std::string to_string(const floating_format); + +struct floating_format_info +{ + floating_format fmt = floating_format::defaultfloat; + std::size_t prec = 0; // precision (if 0, use the default) + std::string suffix = ""; // 1.0e+2_suffix (library extension) +}; + +bool operator==(const floating_format_info&, const floating_format_info&) noexcept; +bool operator!=(const floating_format_info&, const floating_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// string + +enum class string_format : std::uint8_t +{ + basic = 0, + literal = 1, + multiline_basic = 2, + multiline_literal = 3 +}; + +std::ostream& operator<<(std::ostream& os, const string_format f); +std::string to_string(const string_format); + +struct string_format_info +{ + string_format fmt = string_format::basic; + bool start_with_newline = false; +}; + +bool operator==(const string_format_info&, const string_format_info&) noexcept; +bool operator!=(const string_format_info&, const string_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// datetime + +enum class datetime_delimiter_kind : std::uint8_t +{ + upper_T = 0, + lower_t = 1, + space = 2, +}; +std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d); +std::string to_string(const datetime_delimiter_kind); + +struct offset_datetime_format_info +{ + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] +}; + +bool operator==(const offset_datetime_format_info&, const offset_datetime_format_info&) noexcept; +bool operator!=(const offset_datetime_format_info&, const offset_datetime_format_info&) noexcept; + +struct local_datetime_format_info +{ + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] +}; + +bool operator==(const local_datetime_format_info&, const local_datetime_format_info&) noexcept; +bool operator!=(const local_datetime_format_info&, const local_datetime_format_info&) noexcept; + +struct local_date_format_info +{ + // nothing, for now +}; + +bool operator==(const local_date_format_info&, const local_date_format_info&) noexcept; +bool operator!=(const local_date_format_info&, const local_date_format_info&) noexcept; + +struct local_time_format_info +{ + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] +}; + +bool operator==(const local_time_format_info&, const local_time_format_info&) noexcept; +bool operator!=(const local_time_format_info&, const local_time_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// array + +enum class array_format : std::uint8_t +{ + default_format = 0, + oneline = 1, + multiline = 2, + array_of_tables = 3 // [[format.in.this.way]] +}; + +std::ostream& operator<<(std::ostream& os, const array_format f); +std::string to_string(const array_format); + +struct array_format_info +{ + array_format fmt = array_format::default_format; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 4; // indent in case of multiline + std::int32_t closing_indent = 0; // indent of `]` +}; + +bool operator==(const array_format_info&, const array_format_info&) noexcept; +bool operator!=(const array_format_info&, const array_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// table + +enum class table_format : std::uint8_t +{ + multiline = 0, // [foo] \n bar = "baz" + oneline = 1, // foo = {bar = "baz"} + dotted = 2, // foo.bar = "baz" + multiline_oneline = 3, // foo = { \n bar = "baz" \n } + implicit = 4 // [x] defined by [x.y.z]. skip in serializer. +}; + +std::ostream& operator<<(std::ostream& os, const table_format f); +std::string to_string(const table_format); + +struct table_format_info +{ + table_format fmt = table_format::multiline; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 0; // indent of values + std::int32_t name_indent = 0; // indent of [table] + std::int32_t closing_indent = 0; // in case of {inline-table} +}; + +bool operator==(const table_format_info&, const table_format_info&) noexcept; +bool operator!=(const table_format_info&, const table_format_info&) noexcept; + +// ---------------------------------------------------------------------------- +// wrapper + +namespace detail +{ +template +struct value_with_format +{ + using value_type = T; + using format_type = F; + + value_with_format() = default; + ~value_with_format() = default; + value_with_format(const value_with_format&) = default; + value_with_format(value_with_format&&) = default; + value_with_format& operator=(const value_with_format&) = default; + value_with_format& operator=(value_with_format&&) = default; + + value_with_format(value_type v, format_type f) + : value{std::move(v)}, format{std::move(f)} + {} + + template + value_with_format(value_with_format other) + : value{std::move(other.value)}, format{std::move(other.format)} + {} + + value_type value; + format_type format; +}; +} // detail + +} // namespace toml +#endif // TOML11_FORMAT_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/literal_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/literal_fwd.hpp new file mode 100644 index 00000000..e46612ce --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/literal_fwd.hpp @@ -0,0 +1,33 @@ +#ifndef TOML11_LITERAL_FWD_HPP +#define TOML11_LITERAL_FWD_HPP + +#include "../location.hpp" +#include "../types.hpp" +#include "../version.hpp" // IWYU pragma: keep for TOML11_HAS_CHAR8_T + +namespace toml +{ + +namespace detail +{ +// implementation +::toml::value literal_internal_impl(location loc); +} // detail + +inline namespace literals +{ +inline namespace toml_literals +{ + +::toml::value operator"" _toml(const char* str, std::size_t len); + +#if defined(TOML11_HAS_CHAR8_T) +// value of u8"" literal has been changed from char to char8_t and char8_t is +// NOT compatible to char +::toml::value operator"" _toml(const char8_t* str, std::size_t len); +#endif + +} // toml_literals +} // literals +} // toml +#endif // TOML11_LITERAL_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/location_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/location_fwd.hpp new file mode 100644 index 00000000..f6dbfdbc --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/location_fwd.hpp @@ -0,0 +1,145 @@ +#ifndef TOML11_LOCATION_FWD_HPP +#define TOML11_LOCATION_FWD_HPP + +#include "../result.hpp" + +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +class region; // fwd decl + +// +// To represent where we are reading in the parse functions. +// Since it "points" somewhere in the input stream, the length is always 1. +// +class location +{ + public: + + using char_type = unsigned char; // must be unsigned + using container_type = std::vector; + using difference_type = typename container_type::difference_type; // to suppress sign-conversion warning + using source_ptr = std::shared_ptr; + + public: + + location(source_ptr src, std::string src_name) + : source_(std::move(src)), source_name_(std::move(src_name)), + location_(0), line_number_(1) + {} + + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + void advance(std::size_t n = 1) noexcept; + void retrace(std::size_t n = 1) noexcept; + + bool is_ok() const noexcept { return static_cast(this->source_); } + + bool eof() const noexcept; + char_type current() const; + + char_type peek(); + + std::size_t get_location() const noexcept + { + return this->location_; + } + void set_location(const std::size_t loc) noexcept; + + std::size_t line_number() const noexcept + { + return this->line_number_; + } + std::string get_line() const; + std::size_t column_number() const noexcept; + + source_ptr const& source() const noexcept {return this->source_;} + std::string const& source_name() const noexcept {return this->source_name_;} + + private: + + void advance_line_number(const std::size_t n); + void retrace_line_number(const std::size_t n); + + private: + + friend region; + + private: + + source_ptr source_; + std::string source_name_; + std::size_t location_; // std::vector<>::difference_type is signed + std::size_t line_number_; +}; + +bool operator==(const location& lhs, const location& rhs) noexcept; +bool operator!=(const location& lhs, const location& rhs); + +location prev(const location& loc); +location next(const location& loc); +location make_temporary_location(const std::string& str) noexcept; + +template +result +find_if(const location& first, const location& last, const F& func) noexcept +{ + if(first.source() != last.source()) { return err(); } + if(first.get_location() >= last.get_location()) { return err(); } + + auto loc = first; + while(loc.get_location() != last.get_location()) + { + if(func(loc.current())) + { + return ok(loc); + } + loc.advance(); + } + return err(); +} + +template +result +rfind_if(location first, const location& last, const F& func) +{ + if(first.source() != last.source()) { return err(); } + if(first.get_location() >= last.get_location()) { return err(); } + + auto loc = last; + while(loc.get_location() != first.get_location()) + { + if(func(loc.current())) + { + return ok(loc); + } + loc.retrace(); + } + if(func(first.current())) + { + return ok(first); + } + return err(); +} + +result find(const location& first, const location& last, + const location::char_type val); +result rfind(const location& first, const location& last, + const location::char_type val); + +std::size_t count(const location& first, const location& last, + const location::char_type& c); + +} // detail +} // toml +#endif // TOML11_LOCATION_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/region_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/region_fwd.hpp new file mode 100644 index 00000000..b40317d2 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/region_fwd.hpp @@ -0,0 +1,104 @@ +#ifndef TOML11_REGION_FWD_HPP +#define TOML11_REGION_FWD_HPP + +#include "../location.hpp" + +#include +#include + +#include + +namespace toml +{ +namespace detail +{ + +// +// To represent where is a toml::value defined, or where does an error occur. +// Stored in toml::value. source_location will be constructed based on this. +// +class region +{ + public: + + using char_type = location::char_type; + using container_type = location::container_type; + using difference_type = location::difference_type; + using source_ptr = location::source_ptr; + + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + + public: + + // a value that is constructed manually does not have input stream info + region() + : source_(nullptr), source_name_(""), length_(0), + first_line_(0), first_column_(0), last_line_(0), last_column_(0) + {} + + // a value defined in [first, last). + // Those source must be the same. Instread, `region` does not make sense. + region(const location& first, const location& last); + + // shorthand of [loc, loc+1) + explicit region(const location& loc); + + ~region() = default; + region(const region&) = default; + region(region&&) = default; + region& operator=(const region&) = default; + region& operator=(region&&) = default; + + bool is_ok() const noexcept { return static_cast(this->source_); } + + operator bool() const noexcept { return this->is_ok(); } + + std::size_t length() const noexcept {return this->length_;} + + std::size_t first_line_number() const noexcept + { + return this->first_line_; + } + std::size_t first_column_number() const noexcept + { + return this->first_column_; + } + std::size_t last_line_number() const noexcept + { + return this->last_line_; + } + std::size_t last_column_number() const noexcept + { + return this->last_column_; + } + + char_type at(std::size_t i) const; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + std::string as_string() const; + std::vector as_lines() const; + + source_ptr const& source() const noexcept {return this->source_;} + std::string const& source_name() const noexcept {return this->source_name_;} + + private: + + source_ptr source_; + std::string source_name_; + std::size_t length_; + std::size_t first_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_; + std::size_t last_line_; + std::size_t last_column_; +}; + +} // namespace detail +} // namespace toml +#endif // TOML11_REGION_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/scanner_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/scanner_fwd.hpp new file mode 100644 index 00000000..a8867277 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/scanner_fwd.hpp @@ -0,0 +1,391 @@ +#ifndef TOML11_SCANNER_FWD_HPP +#define TOML11_SCANNER_FWD_HPP + +#include "../region.hpp" + +#include +#include +#include +#include + +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +class scanner_base +{ + public: + virtual ~scanner_base() = default; + virtual region scan(location& loc) const = 0; + virtual scanner_base* clone() const = 0; + + // returns expected character or set of characters or literal. + // to show the error location, it changes loc (in `sequence`, especially). + virtual std::string expected_chars(location& loc) const = 0; + virtual std::string name() const = 0; +}; + +// make `scanner*` copyable +struct scanner_storage +{ + template>::value, + std::nullptr_t> = nullptr> + explicit scanner_storage(Scanner&& s) + : scanner_(cxx::make_unique>(std::forward(s))) + {} + ~scanner_storage() = default; + + scanner_storage(const scanner_storage& other); + scanner_storage& operator=(const scanner_storage& other); + scanner_storage(scanner_storage&&) = default; + scanner_storage& operator=(scanner_storage&&) = default; + + bool is_ok() const noexcept {return static_cast(scanner_);} + + region scan(location& loc) const; + + std::string expected_chars(location& loc) const; + + scanner_base& get() const noexcept; + + std::string name() const; + + private: + + std::unique_ptr scanner_; +}; + +// ---------------------------------------------------------------------------- + +class character final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit character(const char_type c) noexcept + : value_(c) + {} + ~character() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type value_; +}; + +// ---------------------------------------------------------------------------- + +class character_either final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit character_either(std::initializer_list cs) noexcept + : chars_(std::move(cs)) + { + assert(! this->chars_.empty()); + } + + template + explicit character_either(const char (&cs)[N]) noexcept + : chars_(N-1, '\0') + { + static_assert(N >= 1, ""); + for(std::size_t i=0; i+1 chars_; +}; + +// ---------------------------------------------------------------------------- + +class character_in_range final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit character_in_range(const char_type from, const char_type to) noexcept + : from_(from), to_(to) + {} + ~character_in_range() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type from_; + char_type to_; +}; + +// ---------------------------------------------------------------------------- + +class literal final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + template + explicit literal(const char (&cs)[N]) noexcept + : value_(cs), size_(N-1) // remove null character at the end + {} + ~literal() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + const char* value_; + std::size_t size_; +}; + +// ---------------------------------------------------------------------------- + +class sequence final: public scanner_base +{ + public: + using char_type = location::char_type; + + public: + + template + explicit sequence(Ts&& ... args) + { + push_back_all(std::forward(args)...); + } + sequence(const sequence&) = default; + sequence(sequence&&) = default; + sequence& operator=(const sequence&) = default; + sequence& operator=(sequence&&) = default; + ~sequence() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) + { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + + void push_back_all() + { + return; + } + template + void push_back_all(T&& head, Ts&& ... args) + { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; +}; + +// ---------------------------------------------------------------------------- + +class either final: public scanner_base +{ + public: + using char_type = location::char_type; + + public: + + template + explicit either(Ts&& ... args) + { + push_back_all(std::forward(args)...); + } + either(const either&) = default; + either(either&&) = default; + either& operator=(const either&) = default; + either& operator=(either&&) = default; + ~either() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) + { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + + void push_back_all() + { + return; + } + template + void push_back_all(T&& head, Ts&& ... args) + { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; +}; + +// ---------------------------------------------------------------------------- + +class repeat_exact final: public scanner_base +{ + public: + using char_type = location::char_type; + + public: + + template + repeat_exact(const std::size_t length, Scanner&& other) + : length_(length), other_(std::forward(other)) + {} + repeat_exact(const repeat_exact&) = default; + repeat_exact(repeat_exact&&) = default; + repeat_exact& operator=(const repeat_exact&) = default; + repeat_exact& operator=(repeat_exact&&) = default; + ~repeat_exact() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; +}; + +// ---------------------------------------------------------------------------- + +class repeat_at_least final: public scanner_base +{ + public: + using char_type = location::char_type; + + public: + + template + repeat_at_least(const std::size_t length, Scanner&& s) + : length_(length), other_(std::forward(s)) + {} + repeat_at_least(const repeat_at_least&) = default; + repeat_at_least(repeat_at_least&&) = default; + repeat_at_least& operator=(const repeat_at_least&) = default; + repeat_at_least& operator=(repeat_at_least&&) = default; + ~repeat_at_least() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; +}; + +// ---------------------------------------------------------------------------- + +class maybe final: public scanner_base +{ + public: + using char_type = location::char_type; + + public: + + template + explicit maybe(Scanner&& s) + : other_(std::forward(s)) + {} + maybe(const maybe&) = default; + maybe(maybe&&) = default; + maybe& operator=(const maybe&) = default; + maybe& operator=(maybe&&) = default; + ~maybe() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + scanner_storage other_; +}; + +} // detail +} // toml +#endif // TOML11_SCANNER_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/source_location_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/source_location_fwd.hpp new file mode 100644 index 00000000..77c7579d --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/source_location_fwd.hpp @@ -0,0 +1,115 @@ +#ifndef TOML11_SOURCE_LOCATION_FWD_HPP +#define TOML11_SOURCE_LOCATION_FWD_HPP + +#include "../region.hpp" + +#include +#include +#include + +namespace toml +{ + +// A struct to contain location in a toml file. +struct source_location +{ + public: + + explicit source_location(const detail::region& r); + ~source_location() = default; + source_location(source_location const&) = default; + source_location(source_location &&) = default; + source_location& operator=(source_location const&) = default; + source_location& operator=(source_location &&) = default; + + bool is_ok() const noexcept {return this->is_ok_;} + std::size_t length() const noexcept {return this->length_;} + + std::size_t first_line_number() const noexcept {return this->first_line_;} + std::size_t first_column_number() const noexcept {return this->first_column_;} + std::size_t last_line_number() const noexcept {return this->last_line_;} + std::size_t last_column_number() const noexcept {return this->last_column_;} + + std::string const& file_name() const noexcept {return this->file_name_;} + + std::size_t num_lines() const noexcept {return this->line_str_.size();} + + std::string const& first_line() const; + std::string const& last_line() const; + + std::vector const& lines() const noexcept {return line_str_;} + + private: + + bool is_ok_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_line_; + std::size_t last_column_; + std::size_t length_; + std::string file_name_; + std::vector line_str_; +}; + +namespace detail +{ + +std::size_t integer_width_base10(std::size_t i) noexcept; + +inline std::size_t line_width() noexcept {return 0;} + +template +std::size_t line_width(const source_location& loc, const std::string& /*msg*/, + const Ts& ... tail) noexcept +{ + return (std::max)( + integer_width_base10(loc.last_line_number()), line_width(tail...)); +} + +std::ostringstream& +format_filename(std::ostringstream& oss, const source_location& loc); + +std::ostringstream& +format_empty_line(std::ostringstream& oss, const std::size_t lnw); + +std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, const std::size_t linenum, const std::string& line); + +std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, const std::size_t col, const std::size_t len, + const std::string& msg); + +std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, const std::string& msg); + +inline std::string format_location_rec(const std::size_t, const std::string&) +{ + return ""; +} + +template +std::string format_location_rec(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, const std::string& msg, + const Ts& ... tail) +{ + return format_location_impl(lnw, prev_fname, loc, msg) + + format_location_rec(lnw, loc.file_name(), tail...); +} + +} // namespace detail + +// format a location info without title +template +std::string format_location( + const source_location& loc, const std::string& msg, const Ts& ... tail) +{ + const auto lnw = detail::line_width(loc, msg, tail...); + + const std::string f(""); // at the 1st iteration, no prev_filename is given + return detail::format_location_rec(lnw, f, loc, msg, tail...); +} + +} // toml +#endif // TOML11_SOURCE_LOCATION_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/syntax_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/syntax_fwd.hpp new file mode 100644 index 00000000..35608215 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/syntax_fwd.hpp @@ -0,0 +1,357 @@ +#ifndef TOML11_SYNTAX_FWD_HPP +#define TOML11_SYNTAX_FWD_HPP + +#include "../scanner.hpp" +#include "../spec.hpp" + +namespace toml +{ +namespace detail +{ +namespace syntax +{ + +using char_type = location::char_type; + +// =========================================================================== +// UTF-8 + +// avoid redundant representation and out-of-unicode sequence + +character_in_range utf8_1byte (const spec&); +sequence utf8_2bytes(const spec&); +sequence utf8_3bytes(const spec&); +sequence utf8_4bytes(const spec&); + +class non_ascii final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit non_ascii(const spec& s) noexcept; + ~non_ascii() override = default; + + region scan(location& loc) const override + { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override + { + return "non-ascii utf-8 bytes"; + } + + scanner_base* clone() const override + { + return new non_ascii(*this); + } + + std::string name() const override + { + return "non_ascii"; + } + + private: + + either scanner_; +}; + +// =========================================================================== +// Whitespace + +character_either wschar(const spec&); + +repeat_at_least ws(const spec& s); + +// =========================================================================== +// Newline + +either newline(const spec&); + +// =========================================================================== +// Comments + +either allowed_comment_char(const spec& s); + +// XXX Note that it does not take newline +sequence comment(const spec& s); + +// =========================================================================== +// Boolean + +either boolean(const spec&); + +// =========================================================================== +// Integer + +class digit final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit digit(const spec&) noexcept; + ~digit() override = default; + + region scan(location& loc) const override + { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override + { + return "digit [0-9]"; + } + + scanner_base* clone() const override + { + return new digit(*this); + } + + std::string name() const override + { + return "digit"; + } + + private: + + character_in_range scanner_; +}; + +class alpha final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit alpha(const spec&) noexcept; + ~alpha() override = default; + + region scan(location& loc) const override + { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override + { + return "alpha [a-zA-Z]"; + } + + scanner_base* clone() const override + { + return new alpha(*this); + } + + std::string name() const override + { + return "alpha"; + } + + private: + + either scanner_; +}; + +class hexdig final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit hexdig(const spec& s) noexcept; + ~hexdig() override = default; + + region scan(location& loc) const override + { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override + { + return "hex [0-9a-fA-F]"; + } + + scanner_base* clone() const override + { + return new hexdig(*this); + } + + std::string name() const override + { + return "hexdig"; + } + + private: + + either scanner_; +}; + +sequence num_suffix(const spec& s); + +sequence dec_int(const spec& s); +sequence hex_int(const spec& s); +sequence oct_int(const spec&); +sequence bin_int(const spec&); +either integer(const spec& s); + +// =========================================================================== +// Floating + +sequence zero_prefixable_int(const spec& s); +sequence fractional_part(const spec& s); +sequence exponent_part(const spec& s); +sequence hex_floating(const spec& s); +either floating(const spec& s); + +// =========================================================================== +// Datetime + +sequence local_date(const spec& s); +sequence local_time(const spec& s); +either time_offset(const spec& s); +sequence full_time(const spec& s); +character_either time_delim(const spec&); +sequence local_datetime(const spec& s); +sequence offset_datetime(const spec& s); + +// =========================================================================== +// String + +sequence escaped(const spec& s); + +either basic_char(const spec& s); + +sequence basic_string(const spec& s); + +// --------------------------------------------------------------------------- +// multiline string + +sequence escaped_newline(const spec& s); +sequence ml_basic_string(const spec& s); + +// --------------------------------------------------------------------------- +// literal string + +either literal_char(const spec& s); +sequence literal_string(const spec& s); + +sequence ml_literal_string(const spec& s); + +either string(const spec& s); + +// =========================================================================== +// Keys + +// to keep `expected_chars` simple +class non_ascii_key_char final : public scanner_base +{ + public: + + using char_type = location::char_type; + + private: + + using in_range = character_in_range; // make definition short + + public: + + explicit non_ascii_key_char(const spec& s) noexcept; + ~non_ascii_key_char() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override + { + return "bare key non-ASCII script"; + } + + scanner_base* clone() const override + { + return new non_ascii_key_char(*this); + } + + std::string name() const override + { + return "non-ASCII bare key"; + } + + private: + + std::uint32_t read_utf8(location& loc) const; +}; + + +repeat_at_least unquoted_key(const spec& s); + +either quoted_key(const spec& s); + +either simple_key(const spec& s); + +sequence dot_sep(const spec& s); + +sequence dotted_key(const spec& s); + + +class key final : public scanner_base +{ + public: + + using char_type = location::char_type; + + public: + + explicit key(const spec& s) noexcept; + ~key() override = default; + + region scan(location& loc) const override + { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override + { + return "basic key([a-zA-Z0-9_-]) or quoted key(\" or ')"; + } + + scanner_base* clone() const override + { + return new key(*this); + } + + std::string name() const override + { + return "key"; + } + + private: + + either scanner_; +}; + +sequence keyval_sep(const spec& s); + +// =========================================================================== +// Table key + +sequence std_table(const spec& s); + +sequence array_table(const spec& s); + +// =========================================================================== +// extension: null + +literal null_value(const spec&); + +} // namespace syntax +} // namespace detail +} // namespace toml +#endif // TOML11_SYNTAX_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/fwd/value_t_fwd.hpp b/src/frontend/qt_sdl/toml/toml11/fwd/value_t_fwd.hpp new file mode 100644 index 00000000..fddf8434 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/fwd/value_t_fwd.hpp @@ -0,0 +1,117 @@ +#ifndef TOML11_VALUE_T_FWD_HPP +#define TOML11_VALUE_T_FWD_HPP + +#include "../compat.hpp" +#include "../format.hpp" + +#include +#include +#include + +#include + +namespace toml +{ + +// forward decl +template +class basic_value; + +// ---------------------------------------------------------------------------- +// enum representing toml types + +enum class value_t : std::uint8_t +{ + empty = 0, + boolean = 1, + integer = 2, + floating = 3, + string = 4, + offset_datetime = 5, + local_datetime = 6, + local_date = 7, + local_time = 8, + array = 9, + table = 10 +}; + +std::ostream& operator<<(std::ostream& os, value_t t); +std::string to_string(value_t t); + + +// ---------------------------------------------------------------------------- +// meta functions for internal use + +namespace detail +{ + +template +using value_t_constant = std::integral_constant; + +template +struct type_to_enum : value_t_constant {}; + +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; +template struct type_to_enum : value_t_constant {}; + +template +struct enum_to_type { using type = void; }; + +template struct enum_to_type { using type = typename V::boolean_type ; }; +template struct enum_to_type { using type = typename V::integer_type ; }; +template struct enum_to_type { using type = typename V::floating_type ; }; +template struct enum_to_type { using type = typename V::string_type ; }; +template struct enum_to_type { using type = typename V::offset_datetime_type; }; +template struct enum_to_type { using type = typename V::local_datetime_type ; }; +template struct enum_to_type { using type = typename V::local_date_type ; }; +template struct enum_to_type { using type = typename V::local_time_type ; }; +template struct enum_to_type { using type = typename V::array_type ; }; +template struct enum_to_type { using type = typename V::table_type ; }; + +template +using enum_to_type_t = typename enum_to_type::type; + +template +struct enum_to_fmt_type { using type = void; }; + +template<> struct enum_to_fmt_type { using type = boolean_format_info ; }; +template<> struct enum_to_fmt_type { using type = integer_format_info ; }; +template<> struct enum_to_fmt_type { using type = floating_format_info ; }; +template<> struct enum_to_fmt_type { using type = string_format_info ; }; +template<> struct enum_to_fmt_type { using type = offset_datetime_format_info; }; +template<> struct enum_to_fmt_type { using type = local_datetime_format_info ; }; +template<> struct enum_to_fmt_type { using type = local_date_format_info ; }; +template<> struct enum_to_fmt_type { using type = local_time_format_info ; }; +template<> struct enum_to_fmt_type { using type = array_format_info ; }; +template<> struct enum_to_fmt_type { using type = table_format_info ; }; + +template +using enum_to_fmt_type_t = typename enum_to_fmt_type::type; + +template +struct is_exact_toml_type0 : cxx::disjunction< + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same + >{}; +template struct is_exact_toml_type: is_exact_toml_type0, V> {}; +template struct is_not_toml_type : cxx::negation> {}; + +} // namespace detail +} // namespace toml +#endif // TOML11_VALUE_T_FWD_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/get.hpp b/src/frontend/qt_sdl/toml/toml11/get.hpp new file mode 100644 index 00000000..3805d09f --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/get.hpp @@ -0,0 +1,632 @@ +#ifndef TOML11_GET_HPP +#define TOML11_GET_HPP + +#include + +#include "from.hpp" +#include "types.hpp" +#include "value.hpp" + +#if defined(TOML11_HAS_STRING_VIEW) +#include +#endif // string_view + +namespace toml +{ + +// ============================================================================ +// T is toml::value; identity transformation. + +template +cxx::enable_if_t>::value, T>& +get(basic_value& v) +{ + return v; +} + +template +cxx::enable_if_t>::value, T> const& +get(const basic_value& v) +{ + return v; +} + +template +cxx::enable_if_t>::value, T> +get(basic_value&& v) +{ + return basic_value(std::move(v)); +} + +// ============================================================================ +// exact toml::* type + +template +cxx::enable_if_t>::value, T> & +get(basic_value& v) +{ + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); +} + +template +cxx::enable_if_t>::value, T> const& +get(const basic_value& v) +{ + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); +} + +template +cxx::enable_if_t>::value, T> +get(basic_value&& v) +{ + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(std::move(v)); +} + +// ============================================================================ +// T is toml::basic_value + +template +cxx::enable_if_t, + cxx::negation>> + >::value, T> +get(basic_value v) +{ + return T(std::move(v)); +} + +// ============================================================================ +// integer convertible from toml::value::integer_type + +template +cxx::enable_if_t, + cxx::negation>, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation> + >::value, T> +get(const basic_value& v) +{ + return static_cast(v.as_integer()); +} + +// ============================================================================ +// floating point convertible from toml::value::floating_type + +template +cxx::enable_if_t, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation> + >::value, T> +get(const basic_value& v) +{ + return static_cast(v.as_floating()); +} + +// ============================================================================ +// std::string with different char/trait/allocator + +template +cxx::enable_if_t>, + detail::is_1byte_std_basic_string + >::value, T> +get(const basic_value& v) +{ + return detail::string_conv>(v.as_string()); +} + +// ============================================================================ +// std::string_view + +#if defined(TOML11_HAS_STRING_VIEW) + +template +cxx::enable_if_t::string_type>::value, T> +get(const basic_value& v) +{ + return T(v.as_string()); +} + +#endif // string_view + +// ============================================================================ +// std::chrono::duration from toml::local_time + +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + return std::chrono::duration_cast( + std::chrono::nanoseconds(v.as_local_time())); +} + +// ============================================================================ +// std::chrono::system_clock::time_point from toml::datetime variants + +template +cxx::enable_if_t< + std::is_same::value, T> +get(const basic_value& v) +{ + switch(v.type()) + { + case value_t::local_date: + { + return std::chrono::system_clock::time_point(v.as_local_date()); + } + case value_t::local_datetime: + { + return std::chrono::system_clock::time_point(v.as_local_datetime()); + } + case value_t::offset_datetime: + { + return std::chrono::system_clock::time_point(v.as_offset_datetime()); + } + default: + { + const auto loc = v.location(); + throw type_error(format_error("toml::get: " + "bad_cast to std::chrono::system_clock::time_point", loc, + "the actual type is " + to_string(v.type())), loc); + } + } +} + +// ============================================================================ +// forward declaration to use this recursively. ignore this and go ahead. + +// array-like (w/ push_back) +template +cxx::enable_if_t, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value&); + +// std::array +template +cxx::enable_if_t::value, T> +get(const basic_value&); + +// std::forward_list +template +cxx::enable_if_t::value, T> +get(const basic_value&); + +// std::pair +template +cxx::enable_if_t::value, T> +get(const basic_value&); + +// std::tuple +template +cxx::enable_if_t::value, T> +get(const basic_value&); + +// std::map (key is convertible from toml::value::key_type) +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v); + +// std::map (key is not convertible from toml::value::key_type, but +// is a std::basic_string) +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v); + +// toml::from::from_toml(v) +template +cxx::enable_if_t::value, T> +get(const basic_value&); + +// has T.from_toml(v) but no from +template +cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, T> +get(const basic_value&); + +// T(const toml::value&) and T is not toml::basic_value, +// and it does not have `from` nor `from_toml`. +template +cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, T> +get(const basic_value&); + +// ============================================================================ +// array-like types; most likely STL container, like std::vector, etc. + +template +cxx::enable_if_t, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v) +{ + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + detail::try_reserve(container, a.size()); // if T has .reserve(), call it + + for(const auto& elem : a) + { + container.push_back(get(elem)); + } + return container; +} + +// ============================================================================ +// std::array + +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + if(a.size() != container.size()) + { + const auto loc = v.location(); + throw std::out_of_range(format_error("toml::get: while converting to an array: " + " array size is " + std::to_string(container.size()) + + " but there are " + std::to_string(a.size()) + " elements in toml array.", + loc, "here")); + } + for(std::size_t i=0; i(a.at(i)); + } + return container; +} + +// ============================================================================ +// std::forward_list + +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + using value_type = typename T::value_type; + + T container; + for(const auto& elem : v.as_array()) + { + container.push_front(get(elem)); + } + container.reverse(); + return container; +} + +// ============================================================================ +// std::pair + +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + using first_type = typename T::first_type; + using second_type = typename T::second_type; + + const auto& ar = v.as_array(); + if(ar.size() != 2) + { + const auto loc = v.location(); + throw std::out_of_range(format_error("toml::get: while converting std::pair: " + " but there are " + std::to_string(ar.size()) + " > 2 elements in toml array.", + loc, "here")); + } + return std::make_pair(::toml::get(ar.at(0)), + ::toml::get(ar.at(1))); +} + +// ============================================================================ +// std::tuple. + +namespace detail +{ +template +T get_tuple_impl(const Array& a, cxx::index_sequence) +{ + return std::make_tuple( + ::toml::get::type>(a.at(I))...); +} +} // detail + +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + const auto& ar = v.as_array(); + if(ar.size() != std::tuple_size::value) + { + const auto loc = v.location(); + throw std::out_of_range(format_error("toml::get: while converting std::tuple: " + " there are " + std::to_string(ar.size()) + " > " + + std::to_string(std::tuple_size::value) + " elements in toml array.", + loc, "here")); + } + return detail::get_tuple_impl(ar, + cxx::make_index_sequence::value>{}); +} + +// ============================================================================ +// map-like types; most likely STL map, like std::map or std::unordered_map. + +// key is convertible from toml::value::key_type +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v) +{ + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + static_assert( + std::is_convertible::key_type, key_type>::value, + "toml::get only supports map type of which key_type is " + "convertible from toml::basic_value::key_type."); + + T m; + for(const auto& kv : v.as_table()) + { + m.emplace(key_type(kv.first), get(kv.second)); + } + return m; +} + +// key is NOT convertible from toml::value::key_type but std::basic_string +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v) +{ + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + + T m; + for(const auto& kv : v.as_table()) + { + m.emplace(detail::string_conv(kv.first), get(kv.second)); + } + return m; +} + +// ============================================================================ +// user-defined, but convertible types. + +// toml::from +template +cxx::enable_if_t::value, T> +get(const basic_value& v) +{ + return ::toml::from::from_toml(v); +} + +// has T.from_toml(v) but no from +template +cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, T> +get(const basic_value& v) +{ + T ud; + ud.from_toml(v); + return ud; +} + +// T(const toml::value&) and T is not toml::basic_value, +// and it does not have `from` nor `from_toml`. +template +cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, T> +get(const basic_value& v) +{ + return T(v); +} + +// ============================================================================ +// get_or(value, fallback) + +template +cxx::enable_if_t::value, basic_value> const& +get_or(const basic_value& v, const basic_value&) +{ + return v; +} + +template +cxx::enable_if_t::value, basic_value>& +get_or(basic_value& v, basic_value&) +{ + return v; +} + +template +cxx::enable_if_t::value, basic_value> +get_or(basic_value&& v, basic_value&&) +{ + return v; +} + +// ---------------------------------------------------------------------------- +// specialization for the exact toml types (return type becomes lvalue ref) + +template +cxx::enable_if_t< + detail::is_exact_toml_type>::value, T> const& +get_or(const basic_value& v, const T& opt) noexcept +{ + try + { + return get>(v); + } + catch(...) + { + return opt; + } +} +template +cxx::enable_if_t>, + detail::is_exact_toml_type> + >::value, T>& +get_or(basic_value& v, T& opt) noexcept +{ + try + { + return get>(v); + } + catch(...) + { + return opt; + } +} +template +cxx::enable_if_t, + basic_value>::value, cxx::remove_cvref_t> +get_or(basic_value&& v, T&& opt) noexcept +{ + try + { + return get>(std::move(v)); + } + catch(...) + { + return cxx::remove_cvref_t(std::forward(opt)); + } +} + +// ---------------------------------------------------------------------------- +// specialization for string literal + +// template +// typename basic_value::string_type +// get_or(const basic_value& v, +// const typename basic_value::string_type::value_type (&opt)[N]) +// { +// try +// { +// return v.as_string(); +// } +// catch(...) +// { +// return typename basic_value::string_type(opt); +// } +// } +// +// The above only matches to the literal, like `get_or(v, "foo");` but not +// ```cpp +// const auto opt = "foo"; +// const auto str = get_or(v, opt); +// ``` +// . And the latter causes an error. +// To match to both `"foo"` and `const auto opt = "foo"`, we take a pointer to +// a character here. + +template +typename basic_value::string_type +get_or(const basic_value& v, + const typename basic_value::string_type::value_type* opt) +{ + try + { + return v.as_string(); + } + catch(...) + { + return typename basic_value::string_type(opt); + } +} + +// ---------------------------------------------------------------------------- +// others (require type conversion and return type cannot be lvalue reference) + +template +cxx::enable_if_t>, + cxx::negation>>, + cxx::negation, typename basic_value::string_type::value_type const*>> + >::value, cxx::remove_cvref_t> +get_or(const basic_value& v, T&& opt) +{ + try + { + return get>(v); + } + catch(...) + { + return cxx::remove_cvref_t(std::forward(opt)); + } +} + +} // toml +#endif // TOML11_GET_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/color_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/color_impl.hpp new file mode 100644 index 00000000..4215587f --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/color_impl.hpp @@ -0,0 +1,76 @@ +#ifndef TOML11_COLOR_IMPL_HPP +#define TOML11_COLOR_IMPL_HPP + +#include "../fwd/color_fwd.hpp" +#include "../version.hpp" + +#include + +namespace toml +{ +namespace color +{ +// put ANSI escape sequence to ostream +inline namespace ansi +{ + +TOML11_INLINE std::ostream& reset(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[00m";} + return os; +} +TOML11_INLINE std::ostream& bold(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[01m";} + return os; +} +TOML11_INLINE std::ostream& grey(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[30m";} + return os; +} +TOML11_INLINE std::ostream& gray(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[30m";} + return os; +} +TOML11_INLINE std::ostream& red(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[31m";} + return os; +} +TOML11_INLINE std::ostream& green(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[32m";} + return os; +} +TOML11_INLINE std::ostream& yellow(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[33m";} + return os; +} +TOML11_INLINE std::ostream& blue(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[34m";} + return os; +} +TOML11_INLINE std::ostream& magenta(std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[35m";} + return os; +} +TOML11_INLINE std::ostream& cyan (std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[36m";} + return os; +} +TOML11_INLINE std::ostream& white (std::ostream& os) +{ + if(detail::color_status().should_color()) {os << "\033[37m";} + return os; +} + +} // ansi +} // color +} // toml +#endif // TOML11_COLOR_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/comments_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/comments_impl.hpp new file mode 100644 index 00000000..25023eba --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/comments_impl.hpp @@ -0,0 +1,46 @@ +#ifndef TOML11_COMMENTS_IMPL_HPP +#define TOML11_COMMENTS_IMPL_HPP + +#include "../fwd/comments_fwd.hpp" // IWYU pragma: keep + +namespace toml +{ + +TOML11_INLINE bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;} +TOML11_INLINE bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;} +TOML11_INLINE bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;} +TOML11_INLINE bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;} +TOML11_INLINE bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;} +TOML11_INLINE bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;} + +TOML11_INLINE void swap(preserve_comments& lhs, preserve_comments& rhs) +{ + lhs.swap(rhs); + return; +} +TOML11_INLINE void swap(preserve_comments& lhs, std::vector& rhs) +{ + lhs.comments.swap(rhs); + return; +} +TOML11_INLINE void swap(std::vector& lhs, preserve_comments& rhs) +{ + lhs.swap(rhs.comments); + return; +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const preserve_comments& com) +{ + for(const auto& c : com) + { + if(c.front() != '#') + { + os << '#'; + } + os << c << '\n'; + } + return os; +} + +} // toml11 +#endif // TOML11_COMMENTS_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/datetime_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/datetime_impl.hpp new file mode 100644 index 00000000..50c04557 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/datetime_impl.hpp @@ -0,0 +1,518 @@ +#ifndef TOML11_DATETIME_IMPL_HPP +#define TOML11_DATETIME_IMPL_HPP + +#include "../fwd/datetime_fwd.hpp" +#include "../version.hpp" + +#include +#include +#include +#include +#include + +#include +#include + +namespace toml +{ + +// To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is +// provided in the absolutely same purpose, but C++11 is actually not compatible +// with C11. We need to dispatch the function depending on the OS. +namespace detail +{ +// TODO: find more sophisticated way to handle this +#if defined(_MSC_VER) +TOML11_INLINE std::tm localtime_s(const std::time_t* src) +{ + std::tm dst; + const auto result = ::localtime_s(&dst, src); + if (result) { throw std::runtime_error("localtime_s failed."); } + return dst; +} +TOML11_INLINE std::tm gmtime_s(const std::time_t* src) +{ + std::tm dst; + const auto result = ::gmtime_s(&dst, src); + if (result) { throw std::runtime_error("gmtime_s failed."); } + return dst; +} +#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE) +TOML11_INLINE std::tm localtime_s(const std::time_t* src) +{ + std::tm dst; + const auto result = ::localtime_r(src, &dst); + if (!result) { throw std::runtime_error("localtime_r failed."); } + return dst; +} +TOML11_INLINE std::tm gmtime_s(const std::time_t* src) +{ + std::tm dst; + const auto result = ::gmtime_r(src, &dst); + if (!result) { throw std::runtime_error("gmtime_r failed."); } + return dst; +} +#else // fallback. not threadsafe +TOML11_INLINE std::tm localtime_s(const std::time_t* src) +{ + const auto result = std::localtime(src); + if (!result) { throw std::runtime_error("localtime failed."); } + return *result; +} +TOML11_INLINE std::tm gmtime_s(const std::time_t* src) +{ + const auto result = std::gmtime(src); + if (!result) { throw std::runtime_error("gmtime failed."); } + return *result; +} +#endif +} // detail + +// ---------------------------------------------------------------------------- + +TOML11_INLINE local_date::local_date(const std::chrono::system_clock::time_point& tp) +{ + const auto t = std::chrono::system_clock::to_time_t(tp); + const auto time = detail::localtime_s(&t); + *this = local_date(time); +} + +TOML11_INLINE local_date::local_date(const std::time_t t) + : local_date{std::chrono::system_clock::from_time_t(t)} +{} + +TOML11_INLINE local_date::operator std::chrono::system_clock::time_point() const +{ + // std::mktime returns date as local time zone. no conversion needed + std::tm t; + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_mday = static_cast(this->day); + t.tm_mon = static_cast(this->month); + t.tm_year = static_cast(this->year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + return std::chrono::system_clock::from_time_t(std::mktime(&t)); +} + +TOML11_INLINE local_date::operator std::time_t() const +{ + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); +} + +TOML11_INLINE bool operator==(const local_date& lhs, const local_date& rhs) +{ + return std::make_tuple(lhs.year, lhs.month, lhs.day) == + std::make_tuple(rhs.year, rhs.month, rhs.day); +} +TOML11_INLINE bool operator!=(const local_date& lhs, const local_date& rhs) +{ + return !(lhs == rhs); +} +TOML11_INLINE bool operator< (const local_date& lhs, const local_date& rhs) +{ + return std::make_tuple(lhs.year, lhs.month, lhs.day) < + std::make_tuple(rhs.year, rhs.month, rhs.day); +} +TOML11_INLINE bool operator<=(const local_date& lhs, const local_date& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +TOML11_INLINE bool operator> (const local_date& lhs, const local_date& rhs) +{ + return !(lhs <= rhs); +} +TOML11_INLINE bool operator>=(const local_date& lhs, const local_date& rhs) +{ + return !(lhs < rhs); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_date& date) +{ + os << std::setfill('0') << std::setw(4) << static_cast(date.year ) << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.month) + 1 << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.day ) ; + return os; +} + +TOML11_INLINE std::string to_string(const local_date& date) +{ + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << date; + return oss.str(); +} + +// ----------------------------------------------------------------------------- + +TOML11_INLINE local_time::operator std::chrono::nanoseconds() const +{ + return std::chrono::nanoseconds (this->nanosecond) + + std::chrono::microseconds(this->microsecond) + + std::chrono::milliseconds(this->millisecond) + + std::chrono::seconds(this->second) + + std::chrono::minutes(this->minute) + + std::chrono::hours(this->hour); +} + +TOML11_INLINE bool operator==(const local_time& lhs, const local_time& rhs) +{ + return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) == + std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond); +} +TOML11_INLINE bool operator!=(const local_time& lhs, const local_time& rhs) +{ + return !(lhs == rhs); +} +TOML11_INLINE bool operator< (const local_time& lhs, const local_time& rhs) +{ + return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) < + std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond); +} +TOML11_INLINE bool operator<=(const local_time& lhs, const local_time& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +TOML11_INLINE bool operator> (const local_time& lhs, const local_time& rhs) +{ + return !(lhs <= rhs); +} +TOML11_INLINE bool operator>=(const local_time& lhs, const local_time& rhs) +{ + return !(lhs < rhs); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_time& time) +{ + os << std::setfill('0') << std::setw(2) << static_cast(time.hour ) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.minute) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.second); + if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0) + { + os << '.'; + os << std::setfill('0') << std::setw(3) << static_cast(time.millisecond); + if(time.microsecond != 0 || time.nanosecond != 0) + { + os << std::setfill('0') << std::setw(3) << static_cast(time.microsecond); + if(time.nanosecond != 0) + { + os << std::setfill('0') << std::setw(3) << static_cast(time.nanosecond); + } + } + } + return os; +} + +TOML11_INLINE std::string to_string(const local_time& time) +{ + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << time; + return oss.str(); +} + +// ---------------------------------------------------------------------------- + +TOML11_INLINE time_offset::operator std::chrono::minutes() const +{ + return std::chrono::minutes(this->minute) + + std::chrono::hours(this->hour); +} + +TOML11_INLINE bool operator==(const time_offset& lhs, const time_offset& rhs) +{ + return std::make_tuple(lhs.hour, lhs.minute) == + std::make_tuple(rhs.hour, rhs.minute); +} +TOML11_INLINE bool operator!=(const time_offset& lhs, const time_offset& rhs) +{ + return !(lhs == rhs); +} +TOML11_INLINE bool operator< (const time_offset& lhs, const time_offset& rhs) +{ + return std::make_tuple(lhs.hour, lhs.minute) < + std::make_tuple(rhs.hour, rhs.minute); +} +TOML11_INLINE bool operator<=(const time_offset& lhs, const time_offset& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +TOML11_INLINE bool operator> (const time_offset& lhs, const time_offset& rhs) +{ + return !(lhs <= rhs); +} +TOML11_INLINE bool operator>=(const time_offset& lhs, const time_offset& rhs) +{ + return !(lhs < rhs); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const time_offset& offset) +{ + if(offset.hour == 0 && offset.minute == 0) + { + os << 'Z'; + return os; + } + int minute = static_cast(offset.hour) * 60 + offset.minute; + if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';} + os << std::setfill('0') << std::setw(2) << minute / 60 << ':'; + os << std::setfill('0') << std::setw(2) << minute % 60; + return os; +} + +TOML11_INLINE std::string to_string(const time_offset& offset) +{ + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << offset; + return oss.str(); +} + +// ----------------------------------------------------------------------------- + +TOML11_INLINE local_datetime::local_datetime(const std::chrono::system_clock::time_point& tp) +{ + const auto t = std::chrono::system_clock::to_time_t(tp); + std::tm ltime = detail::localtime_s(&t); + + this->date = local_date(ltime); + this->time = local_time(ltime); + + // std::tm lacks subsecond information, so diff between tp and tm + // can be used to get millisecond & microsecond information. + const auto t_diff = tp - + std::chrono::system_clock::from_time_t(std::mktime(<ime)); + this->time.millisecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.microsecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.nanosecond = static_cast( + std::chrono::duration_cast(t_diff).count()); +} + +TOML11_INLINE local_datetime::local_datetime(const std::time_t t) + : local_datetime{std::chrono::system_clock::from_time_t(t)} +{} + +TOML11_INLINE local_datetime::operator std::chrono::system_clock::time_point() const +{ + using internal_duration = + typename std::chrono::system_clock::time_point::duration; + + // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator + // of local_date and local_time independently, the conversion fails if + // it is the day when DST begins or ends. Since local_date considers the + // time is 00:00 A.M. and local_time does not consider DST because it + // does not have any date information. We need to consider both date and + // time information at the same time to convert it correctly. + + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + + // std::mktime returns date as local time zone. no conversion needed + auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t)); + dt += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds (this->time.nanosecond)); + return dt; +} + +TOML11_INLINE local_datetime::operator std::time_t() const +{ + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); +} + +TOML11_INLINE bool operator==(const local_datetime& lhs, const local_datetime& rhs) +{ + return std::make_tuple(lhs.date, lhs.time) == + std::make_tuple(rhs.date, rhs.time); +} +TOML11_INLINE bool operator!=(const local_datetime& lhs, const local_datetime& rhs) +{ + return !(lhs == rhs); +} +TOML11_INLINE bool operator< (const local_datetime& lhs, const local_datetime& rhs) +{ + return std::make_tuple(lhs.date, lhs.time) < + std::make_tuple(rhs.date, rhs.time); +} +TOML11_INLINE bool operator<=(const local_datetime& lhs, const local_datetime& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +TOML11_INLINE bool operator> (const local_datetime& lhs, const local_datetime& rhs) +{ + return !(lhs <= rhs); +} +TOML11_INLINE bool operator>=(const local_datetime& lhs, const local_datetime& rhs) +{ + return !(lhs < rhs); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_datetime& dt) +{ + os << dt.date << 'T' << dt.time; + return os; +} + +TOML11_INLINE std::string to_string(const local_datetime& dt) +{ + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); +} + +// ----------------------------------------------------------------------------- + + +TOML11_INLINE offset_datetime::offset_datetime(const local_datetime& ld) + : date{ld.date}, time{ld.time}, offset{get_local_offset(nullptr)} + // use the current local timezone offset +{} +TOML11_INLINE offset_datetime::offset_datetime(const std::chrono::system_clock::time_point& tp) + : offset{0, 0} // use gmtime +{ + const auto timet = std::chrono::system_clock::to_time_t(tp); + const auto tm = detail::gmtime_s(&timet); + this->date = local_date(tm); + this->time = local_time(tm); +} +TOML11_INLINE offset_datetime::offset_datetime(const std::time_t& t) + : offset{0, 0} // use gmtime +{ + const auto tm = detail::gmtime_s(&t); + this->date = local_date(tm); + this->time = local_time(tm); +} +TOML11_INLINE offset_datetime::offset_datetime(const std::tm& t) + : offset{0, 0} // assume gmtime +{ + this->date = local_date(t); + this->time = local_time(t); +} + +TOML11_INLINE offset_datetime::operator std::chrono::system_clock::time_point() const +{ + // get date-time + using internal_duration = + typename std::chrono::system_clock::time_point::duration; + + // first, convert it to local date-time information in the same way as + // local_datetime does. later we will use time_t to adjust time offset. + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + const std::time_t tp_loc = std::mktime(std::addressof(t)); + + auto tp = std::chrono::system_clock::from_time_t(tp_loc); + tp += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds (this->time.nanosecond)); + + // Since mktime uses local time zone, it should be corrected. + // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if + // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need + // to add `+09:00` to `03:00:00Z`. + // Here, it uses the time_t converted from date-time info to handle + // daylight saving time. + const auto ofs = get_local_offset(std::addressof(tp_loc)); + tp += std::chrono::hours (ofs.hour); + tp += std::chrono::minutes(ofs.minute); + + // We got `12:00:00Z` by correcting local timezone applied by mktime. + // Then we will apply the offset. Let's say `12:00:00-08:00` is given. + // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`. + // So we need to subtract the offset. + tp -= std::chrono::minutes(this->offset); + return tp; +} + +TOML11_INLINE offset_datetime::operator std::time_t() const +{ + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); +} + +TOML11_INLINE time_offset offset_datetime::get_local_offset(const std::time_t* tp) +{ + // get local timezone with the same date-time information as mktime + const auto t = detail::localtime_s(tp); + + std::array buf; + const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0 + if(result != 5) + { + throw std::runtime_error("toml::offset_datetime: cannot obtain " + "timezone information of current env"); + } + const int ofs = std::atoi(buf.data()); + const int ofs_h = ofs / 100; + const int ofs_m = ofs - (ofs_h * 100); + return time_offset(ofs_h, ofs_m); +} + +TOML11_INLINE bool operator==(const offset_datetime& lhs, const offset_datetime& rhs) +{ + return std::make_tuple(lhs.date, lhs.time, lhs.offset) == + std::make_tuple(rhs.date, rhs.time, rhs.offset); +} +TOML11_INLINE bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs) +{ + return !(lhs == rhs); +} +TOML11_INLINE bool operator< (const offset_datetime& lhs, const offset_datetime& rhs) +{ + return std::make_tuple(lhs.date, lhs.time, lhs.offset) < + std::make_tuple(rhs.date, rhs.time, rhs.offset); +} +TOML11_INLINE bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +TOML11_INLINE bool operator> (const offset_datetime& lhs, const offset_datetime& rhs) +{ + return !(lhs <= rhs); +} +TOML11_INLINE bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs) +{ + return !(lhs < rhs); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const offset_datetime& dt) +{ + os << dt.date << 'T' << dt.time << dt.offset; + return os; +} + +TOML11_INLINE std::string to_string(const offset_datetime& dt) +{ + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); +} + +}//toml +#endif // TOML11_DATETIME_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/error_info_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/error_info_impl.hpp new file mode 100644 index 00000000..b87f4776 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/error_info_impl.hpp @@ -0,0 +1,75 @@ +#ifndef TOML11_ERROR_INFO_IMPL_HPP +#define TOML11_ERROR_INFO_IMPL_HPP + +#include "../fwd/error_info_fwd.hpp" +#include "../fwd/color_fwd.hpp" + +#include + +namespace toml +{ + +TOML11_INLINE std::string format_error(const std::string& errkind, const error_info& err) +{ + std::string errmsg; + if( ! errkind.empty()) + { + errmsg = errkind; + errmsg += ' '; + } + errmsg += err.title(); + errmsg += '\n'; + + const auto lnw = [&err]() { + std::size_t width = 0; + for(const auto& l : err.locations()) + { + width = (std::max)(detail::integer_width_base10(l.first.last_line_number()), width); + } + return width; + }(); + + bool first = true; + std::string prev_fname; + for(const auto& lm : err.locations()) + { + if( ! first) + { + std::ostringstream oss; + oss << detail::make_string(lnw + 1, ' ') + << color::bold << color::blue << " |" << color::reset + << color::bold << " ...\n" << color::reset; + oss << detail::make_string(lnw + 1, ' ') + << color::bold << color::blue << " |\n" << color::reset; + errmsg += oss.str(); + } + + const auto& l = lm.first; + const auto& m = lm.second; + + errmsg += detail::format_location_impl(lnw, prev_fname, l, m); + + prev_fname = l.file_name(); + first = false; + } + + errmsg += err.suffix(); + + return errmsg; +} + +TOML11_INLINE std::string format_error(const error_info& err) +{ + std::ostringstream oss; + oss << color::red << color::bold << "[error]" << color::reset; + return format_error(oss.str(), err); +} + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const error_info& e) +{ + os << format_error(e); + return os; +} + +} // toml +#endif // TOML11_ERROR_INFO_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/format_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/format_impl.hpp new file mode 100644 index 00000000..c4985faf --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/format_impl.hpp @@ -0,0 +1,297 @@ +#ifndef TOML11_FORMAT_IMPL_HPP +#define TOML11_FORMAT_IMPL_HPP + +#include "../fwd/format_fwd.hpp" +#include "../version.hpp" + +#include +#include + +namespace toml +{ + +// toml types with serialization info + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const indent_char& c) +{ + switch(c) + { + case indent_char::space: {os << "space" ; break;} + case indent_char::tab: {os << "tab" ; break;} + case indent_char::none: {os << "none" ; break;} + default: + { + os << "unknown indent char: " << static_cast(c); + } + } + return os; +} + +TOML11_INLINE std::string to_string(const indent_char c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +// ---------------------------------------------------------------------------- +// boolean + +// ---------------------------------------------------------------------------- +// integer + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const integer_format f) +{ + switch(f) + { + case integer_format::dec: {os << "dec"; break;} + case integer_format::bin: {os << "bin"; break;} + case integer_format::oct: {os << "oct"; break;} + case integer_format::hex: {os << "hex"; break;} + default: + { + os << "unknown integer_format: " << static_cast(f); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const integer_format c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + + +TOML11_INLINE bool operator==(const integer_format_info& lhs, const integer_format_info& rhs) noexcept +{ + return lhs.fmt == rhs.fmt && + lhs.uppercase == rhs.uppercase && + lhs.width == rhs.width && + lhs.spacer == rhs.spacer && + lhs.suffix == rhs.suffix ; +} +TOML11_INLINE bool operator!=(const integer_format_info& lhs, const integer_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +// ---------------------------------------------------------------------------- +// floating + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const floating_format f) +{ + switch(f) + { + case floating_format::defaultfloat: {os << "defaultfloat"; break;} + case floating_format::fixed : {os << "fixed" ; break;} + case floating_format::scientific : {os << "scientific" ; break;} + case floating_format::hex : {os << "hex" ; break;} + default: + { + os << "unknown floating_format: " << static_cast(f); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const floating_format c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +TOML11_INLINE bool operator==(const floating_format_info& lhs, const floating_format_info& rhs) noexcept +{ + return lhs.fmt == rhs.fmt && + lhs.prec == rhs.prec && + lhs.suffix == rhs.suffix ; +} +TOML11_INLINE bool operator!=(const floating_format_info& lhs, const floating_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +// ---------------------------------------------------------------------------- +// string + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const string_format f) +{ + switch(f) + { + case string_format::basic : {os << "basic" ; break;} + case string_format::literal : {os << "literal" ; break;} + case string_format::multiline_basic : {os << "multiline_basic" ; break;} + case string_format::multiline_literal: {os << "multiline_literal"; break;} + default: + { + os << "unknown string_format: " << static_cast(f); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const string_format c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +TOML11_INLINE bool operator==(const string_format_info& lhs, const string_format_info& rhs) noexcept +{ + return lhs.fmt == rhs.fmt && + lhs.start_with_newline == rhs.start_with_newline ; +} +TOML11_INLINE bool operator!=(const string_format_info& lhs, const string_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} +// ---------------------------------------------------------------------------- +// datetime + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d) +{ + switch(d) + { + case datetime_delimiter_kind::upper_T: { os << "upper_T, "; break; } + case datetime_delimiter_kind::lower_t: { os << "lower_t, "; break; } + case datetime_delimiter_kind::space: { os << "space, "; break; } + default: + { + os << "unknown datetime delimiter: " << static_cast(d); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const datetime_delimiter_kind c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +TOML11_INLINE bool operator==(const offset_datetime_format_info& lhs, const offset_datetime_format_info& rhs) noexcept +{ + return lhs.delimiter == rhs.delimiter && + lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision ; +} +TOML11_INLINE bool operator!=(const offset_datetime_format_info& lhs, const offset_datetime_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +TOML11_INLINE bool operator==(const local_datetime_format_info& lhs, const local_datetime_format_info& rhs) noexcept +{ + return lhs.delimiter == rhs.delimiter && + lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision ; +} +TOML11_INLINE bool operator!=(const local_datetime_format_info& lhs, const local_datetime_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +TOML11_INLINE bool operator==(const local_date_format_info&, const local_date_format_info&) noexcept +{ + return true; +} +TOML11_INLINE bool operator!=(const local_date_format_info& lhs, const local_date_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +TOML11_INLINE bool operator==(const local_time_format_info& lhs, const local_time_format_info& rhs) noexcept +{ + return lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision ; +} +TOML11_INLINE bool operator!=(const local_time_format_info& lhs, const local_time_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +// ---------------------------------------------------------------------------- +// array + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const array_format f) +{ + switch(f) + { + case array_format::default_format : {os << "default_format" ; break;} + case array_format::oneline : {os << "oneline" ; break;} + case array_format::multiline : {os << "multiline" ; break;} + case array_format::array_of_tables: {os << "array_of_tables"; break;} + default: + { + os << "unknown array_format: " << static_cast(f); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const array_format c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +TOML11_INLINE bool operator==(const array_format_info& lhs, const array_format_info& rhs) noexcept +{ + return lhs.fmt == rhs.fmt && + lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.closing_indent == rhs.closing_indent ; +} +TOML11_INLINE bool operator!=(const array_format_info& lhs, const array_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +// ---------------------------------------------------------------------------- +// table + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, const table_format f) +{ + switch(f) + { + case table_format::multiline : {os << "multiline" ; break;} + case table_format::oneline : {os << "oneline" ; break;} + case table_format::dotted : {os << "dotted" ; break;} + case table_format::multiline_oneline: {os << "multiline_oneline"; break;} + case table_format::implicit : {os << "implicit" ; break;} + default: + { + os << "unknown table_format: " << static_cast(f); + break; + } + } + return os; +} +TOML11_INLINE std::string to_string(const table_format c) +{ + std::ostringstream oss; + oss << c; + return oss.str(); +} + +TOML11_INLINE bool operator==(const table_format_info& lhs, const table_format_info& rhs) noexcept +{ + return lhs.fmt == rhs.fmt && + lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.name_indent == rhs.name_indent && + lhs.closing_indent == rhs.closing_indent ; +} +TOML11_INLINE bool operator!=(const table_format_info& lhs, const table_format_info& rhs) noexcept +{ + return !(lhs == rhs); +} + +} // namespace toml +#endif // TOML11_FORMAT_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/literal_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/literal_impl.hpp new file mode 100644 index 00000000..e8298c21 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/literal_impl.hpp @@ -0,0 +1,174 @@ +#ifndef TOML11_LITERAL_IMPL_HPP +#define TOML11_LITERAL_IMPL_HPP + +#include "../fwd/literal_fwd.hpp" +#include "../parser.hpp" +#include "../syntax.hpp" + +namespace toml +{ + +namespace detail +{ +// implementation +TOML11_INLINE ::toml::value literal_internal_impl(location loc) +{ + const auto s = ::toml::spec::default_version(); + context ctx(s); + + const auto front = loc; + + // ------------------------------------------------------------------------ + // check if it is a raw value. + + // skip empty lines and comment lines + auto sp = skip_multiline_spacer(loc, ctx); + if(loc.eof()) + { + ::toml::value val; + if(sp.has_value()) + { + for(std::size_t i=0; i(str), + reinterpret_cast(str + len), + c.begin()); + if( ! c.empty() && c.back()) + { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared(std::move(c)), + "TOML literal encoded in a C++ code")); +} + +#if defined(__cpp_char8_t) +# if __cpp_char8_t >= 201811L +# define TOML11_HAS_CHAR8_T 1 +# endif +#endif + +#if defined(TOML11_HAS_CHAR8_T) +// value of u8"" literal has been changed from char to char8_t and char8_t is +// NOT compatible to char +TOML11_INLINE ::toml::value +operator"" _toml(const char8_t* str, std::size_t len) +{ + if(len == 0) + { + return ::toml::value{}; + } + + ::toml::detail::location::container_type c(len); + std::copy(reinterpret_cast(str), + reinterpret_cast(str + len), + c.begin()); + if( ! c.empty() && c.back()) + { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared(std::move(c)), + "TOML literal encoded in a C++ code")); +} +#endif + +} // toml_literals +} // literals +} // toml +#endif // TOML11_LITERAL_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/location_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/location_impl.hpp new file mode 100644 index 00000000..19c418ab --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/location_impl.hpp @@ -0,0 +1,226 @@ +#ifndef TOML11_LOCATION_IMPL_HPP +#define TOML11_LOCATION_IMPL_HPP + +#include "../fwd/location_fwd.hpp" +#include "../utility.hpp" +#include "../version.hpp" + +namespace toml +{ +namespace detail +{ + +TOML11_INLINE void location::advance(std::size_t n) noexcept +{ + assert(this->is_ok()); + if(this->location_ + n < this->source_->size()) + { + this->advance_line_number(n); + this->location_ += n; + } + else + { + this->advance_line_number(this->source_->size() - this->location_); + this->location_ = this->source_->size(); + } +} +TOML11_INLINE void location::retrace(std::size_t n) noexcept +{ + assert(this->is_ok()); + if(this->location_ < n) + { + this->location_ = 0; + this->line_number_ = 1; + } + else + { + this->retrace_line_number(n); + this->location_ -= n; + } +} + +TOML11_INLINE bool location::eof() const noexcept +{ + assert(this->is_ok()); + return this->location_ >= this->source_->size(); +} +TOML11_INLINE location::char_type location::current() const +{ + assert(this->is_ok()); + if(this->eof()) {return '\0';} + + assert(this->location_ < this->source_->size()); + return this->source_->at(this->location_); +} + +TOML11_INLINE location::char_type location::peek() +{ + assert(this->is_ok()); + if(this->location_ >= this->source_->size()) + { + return '\0'; + } + else + { + return this->source_->at(this->location_ + 1); + } +} + +TOML11_INLINE void location::set_location(const std::size_t loc) noexcept +{ + if(this->location_ == loc) + { + return ; + } + + if(loc == 0) + { + this->line_number_ = 1; + } + else if(this->location_ < loc) + { + const auto d = loc - this->location_; + this->advance_line_number(d); + } + else + { + const auto d = this->location_ - loc; + this->retrace_line_number(d); + } + this->location_ = loc; +} + +TOML11_INLINE std::string location::get_line() const +{ + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + const auto next = std::find(iter, this->source_->cend(), char_type('\n')); + + return make_string(std::next(prev.base()), next); +} +TOML11_INLINE std::size_t location::column_number() const noexcept +{ + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + + assert(prev.base() <= iter); + return static_cast(std::distance(prev.base(), iter) + 1); // 1-origin +} + + +TOML11_INLINE void location::advance_line_number(const std::size_t n) +{ + assert(this->is_ok()); + assert(this->location_ + n <= this->source_->size()); + + const auto iter = this->source_->cbegin(); + this->line_number_ += static_cast(std::count( + std::next(iter, static_cast(this->location_)), + std::next(iter, static_cast(this->location_ + n)), + char_type('\n'))); + + return; +} +TOML11_INLINE void location::retrace_line_number(const std::size_t n) +{ + assert(this->is_ok()); + assert(n <= this->location_); // loc - n >= 0 + + const auto iter = this->source_->cbegin(); + const auto dline_num = static_cast(std::count( + std::next(iter, static_cast(this->location_ - n)), + std::next(iter, static_cast(this->location_)), + char_type('\n'))); + + if(this->line_number_ <= dline_num) + { + this->line_number_ = 1; + } + else + { + this->line_number_ -= dline_num; + } + return; +} + +TOML11_INLINE bool operator==(const location& lhs, const location& rhs) noexcept +{ + if( ! lhs.is_ok() || ! rhs.is_ok()) + { + return (!lhs.is_ok()) && (!rhs.is_ok()); + } + return lhs.source() == rhs.source() && + lhs.source_name() == rhs.source_name() && + lhs.get_location() == rhs.get_location(); +} +TOML11_INLINE bool operator!=(const location& lhs, const location& rhs) +{ + return !(lhs == rhs); +} + +TOML11_INLINE location prev(const location& loc) +{ + location p(loc); + p.retrace(1); + return p; +} +TOML11_INLINE location next(const location& loc) +{ + location p(loc); + p.advance(1); + return p; +} + +TOML11_INLINE location make_temporary_location(const std::string& str) noexcept +{ + location::container_type cont(str.size()); + std::transform(str.begin(), str.end(), cont.begin(), + [](const std::string::value_type& c) { + return cxx::bit_cast(c); + }); + return location(std::make_shared( + std::move(cont)), "internal temporary"); +} + +TOML11_INLINE result +find(const location& first, const location& last, const location::char_type val) +{ + return find_if(first, last, [val](const location::char_type c) { + return c == val; + }); +} +TOML11_INLINE result +rfind(const location& first, const location& last, const location::char_type val) +{ + return rfind_if(first, last, [val](const location::char_type c) { + return c == val; + }); +} + +TOML11_INLINE std::size_t +count(const location& first, const location& last, const location::char_type& c) +{ + if(first.source() != last.source()) { return 0; } + if(first.get_location() >= last.get_location()) { return 0; } + + auto loc = first; + std::size_t num = 0; + while(loc.get_location() != last.get_location()) + { + if(loc.current() == c) + { + num += 1; + } + loc.advance(); + } + return num; +} + +} // detail +} // toml +#endif // TOML11_LOCATION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/region_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/region_impl.hpp new file mode 100644 index 00000000..08147e25 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/region_impl.hpp @@ -0,0 +1,188 @@ +#ifndef TOML11_REGION_IMPL_HPP +#define TOML11_REGION_IMPL_HPP + +#include "../fwd/region_fwd.hpp" +#include "../utility.hpp" + +#include +#include +#include +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +// a value defined in [first, last). +// Those source must be the same. Instread, `region` does not make sense. +TOML11_INLINE region::region(const location& first, const location& last) + : source_(first.source()), source_name_(first.source_name()), + length_(last.get_location() - first.get_location()), + first_(first.get_location()), + first_line_(first.line_number()), + first_column_(first.column_number()), + last_(last.get_location()), + last_line_(last.line_number()), + last_column_(last.column_number()) +{ + assert(first.source() == last.source()); + assert(first.source_name() == last.source_name()); +} + + // shorthand of [loc, loc+1) +TOML11_INLINE region::region(const location& loc) + : source_(loc.source()), source_name_(loc.source_name()), length_(0), + first_line_(0), first_column_(0), last_line_(0), last_column_(0) +{ + // if the file ends with LF, the resulting region points no char. + if(loc.eof()) + { + if(loc.get_location() == 0) + { + this->length_ = 0; + this->first_ = 0; + this->first_line_ = 0; + this->first_column_ = 0; + this->last_ = 0; + this->last_line_ = 0; + this->last_column_ = 0; + } + else + { + const auto first = prev(loc); + this->first_ = first.get_location(); + this->first_line_ = first.line_number(); + this->first_column_ = first.column_number(); + this->last_ = loc.get_location(); + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number(); + this->length_ = 1; + } + } + else + { + this->first_ = loc.get_location(); + this->first_line_ = loc.line_number(); + this->first_column_ = loc.column_number(); + this->last_ = loc.get_location() + 1; + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number() + 1; + this->length_ = 1; + } +} + +TOML11_INLINE region::char_type region::at(std::size_t i) const +{ + if(this->last_ <= this->first_ + i) + { + throw std::out_of_range("range::at: index " + std::to_string(i) + + " exceeds length " + std::to_string(this->length_)); + } + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->first_ + i)); + return *iter; +} + +TOML11_INLINE region::const_iterator region::begin() const noexcept +{ + return std::next(this->source_->cbegin(), + static_cast(this->first_)); +} +TOML11_INLINE region::const_iterator region::end() const noexcept +{ + return std::next(this->source_->cbegin(), + static_cast(this->last_)); +} +TOML11_INLINE region::const_iterator region::cbegin() const noexcept +{ + return std::next(this->source_->cbegin(), + static_cast(this->first_)); +} +TOML11_INLINE region::const_iterator region::cend() const noexcept +{ + return std::next(this->source_->cbegin(), + static_cast(this->last_)); +} + +TOML11_INLINE std::string region::as_string() const +{ + if(this->is_ok()) + { + const auto begin = std::next(this->source_->cbegin(), static_cast(this->first_)); + const auto end = std::next(this->source_->cbegin(), static_cast(this->last_ )); + return ::toml::detail::make_string(begin, end); + } + else + { + return std::string(""); + } +} + +TOML11_INLINE std::vector region::as_lines() const +{ + assert(this->is_ok()); + if(this->length_ == 0) + { + return std::vector{""}; + } + + // Consider the following toml file + // ``` + // array = [ + // ] # comment + // ``` + // and the region represnets + // ``` + // [ + // ] + // ``` + // but we want to show the following. + // ``` + // array = [ + // ] # comment + // ``` + // So we need to find LFs before `begin` and after `end`. + // + // But, if region ends with LF, it should not include the next line. + // ``` + // a = 42 + // ^^^- with the last LF + // ``` + // So we start from `end-1` when looking for LF. + + const auto begin_idx = static_cast(this->first_); + const auto end_idx = static_cast(this->last_) - 1; + + // length_ != 0, so begin < end. then begin <= end-1 + assert(begin_idx <= end_idx); + + const auto begin = std::next(this->source_->cbegin(), begin_idx); + const auto end = std::next(this->source_->cbegin(), end_idx); + + const auto line_begin = std::find(cxx::make_reverse_iterator(begin), this->source_->crend(), char_type('\n')).base(); + const auto line_end = std::find(end, this->source_->cend(), char_type('\n')); + + const auto reg_lines = make_string(line_begin, line_end); + + if(reg_lines == "") // the region is an empty line that only contains LF + { + return std::vector{""}; + } + + std::istringstream iss(reg_lines); + + std::vector lines; + std::string line; + while(std::getline(iss, line)) + { + lines.push_back(line); + } + return lines; +} + +} // namespace detail +} // namespace toml +#endif // TOML11_REGION_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/scanner_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/scanner_impl.hpp new file mode 100644 index 00000000..d97d3178 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/scanner_impl.hpp @@ -0,0 +1,473 @@ +#ifndef TOML11_SCANNER_IMPL_HPP +#define TOML11_SCANNER_IMPL_HPP + +#include "../fwd/scanner_fwd.hpp" +#include "../utility.hpp" + +namespace toml +{ +namespace detail +{ + +TOML11_INLINE scanner_storage::scanner_storage(const scanner_storage& other) + : scanner_(nullptr) +{ + if(other.is_ok()) + { + scanner_.reset(other.get().clone()); + } +} +TOML11_INLINE scanner_storage& scanner_storage::operator=(const scanner_storage& other) +{ + if(this == std::addressof(other)) {return *this;} + if(other.is_ok()) + { + scanner_.reset(other.get().clone()); + } + return *this; +} + +TOML11_INLINE region scanner_storage::scan(location& loc) const +{ + assert(this->is_ok()); + return this->scanner_->scan(loc); +} + +TOML11_INLINE std::string scanner_storage::expected_chars(location& loc) const +{ + assert(this->is_ok()); + return this->scanner_->expected_chars(loc); +} + +TOML11_INLINE scanner_base& scanner_storage::get() const noexcept +{ + assert(this->is_ok()); + return *scanner_; +} + +TOML11_INLINE std::string scanner_storage::name() const +{ + assert(this->is_ok()); + return this->scanner_->name(); +} + +// ---------------------------------------------------------------------------- + +TOML11_INLINE region character::scan(location& loc) const +{ + if(loc.eof()) {return region{};} + + if(loc.current() == this->value_) + { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region{}; +} + +TOML11_INLINE std::string character::expected_chars(location&) const +{ + return show_char(value_); +} + +TOML11_INLINE scanner_base* character::clone() const +{ + return new character(*this); +} + +TOML11_INLINE std::string character::name() const +{ + return "character{" + show_char(value_) + "}"; +} + +// ---------------------------------------------------------------------------- + +TOML11_INLINE region character_either::scan(location& loc) const +{ + if(loc.eof()) {return region{};} + + for(const auto c : this->chars_) + { + if(loc.current() == c) + { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + } + return region{}; +} + +TOML11_INLINE std::string character_either::expected_chars(location&) const +{ + assert( ! chars_.empty()); + + std::string expected; + if(chars_.size() == 1) + { + expected += show_char(chars_.at(0)); + } + else if(chars_.size() == 2) + { + expected += show_char(chars_.at(0)) + " or " + show_char(chars_.at(1)); + } + else + { + for(std::size_t i=0; ichars_) + { + n += show_char(c); + n += ", "; + } + if( ! this->chars_.empty()) + { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; +} + +// ---------------------------------------------------------------------------- +// character_in_range + +TOML11_INLINE region character_in_range::scan(location& loc) const +{ + if(loc.eof()) {return region{};} + + const auto curr = loc.current(); + if(this->from_ <= curr && curr <= this->to_) + { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region{}; +} + +TOML11_INLINE std::string character_in_range::expected_chars(location&) const +{ + std::string expected("from `"); + expected += show_char(from_); + expected += "` to `"; + expected += show_char(to_); + expected += "`"; + return expected; +} + +TOML11_INLINE scanner_base* character_in_range::clone() const +{ + return new character_in_range(*this); +} + +TOML11_INLINE std::string character_in_range::name() const +{ + return "character_in_range{" + show_char(from_) + "," + show_char(to_) + "}"; +} + +// ---------------------------------------------------------------------------- +// literal + +TOML11_INLINE region literal::scan(location& loc) const +{ + const auto first = loc; + for(std::size_t i=0; iothers_.empty()) + { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; +} + +// ---------------------------------------------------------------------------- +// either + +TOML11_INLINE region either::scan(location& loc) const +{ + for(const auto& other : others_) + { + const auto reg = other.scan(loc); + if(reg.is_ok()) + { + return reg; + } + } + return region{}; +} + +TOML11_INLINE std::string either::expected_chars(location& loc) const +{ + assert( ! others_.empty()); + + std::string expected = others_.at(0).expected_chars(loc); + if(others_.size() == 2) + { + expected += " or "; + expected += others_.at(1).expected_chars(loc); + } + else + { + for(std::size_t i=1; iothers_.empty()) + { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; +} + +// ---------------------------------------------------------------------------- +// repeat_exact + +TOML11_INLINE region repeat_exact::scan(location& loc) const +{ + const auto first = loc; + for(std::size_t i=0; i +#include +#include +#include + +#include + +namespace toml +{ + +TOML11_INLINE source_location::source_location(const detail::region& r) + : is_ok_(false), + first_line_(1), + first_column_(1), + last_line_(1), + last_column_(1), + length_(0), + file_name_("unknown file") +{ + if(r.is_ok()) + { + this->is_ok_ = true; + this->file_name_ = r.source_name(); + this->first_line_ = r.first_line_number(); + this->first_column_ = r.first_column_number(); + this->last_line_ = r.last_line_number(); + this->last_column_ = r.last_column_number(); + this->length_ = r.length(); + this->line_str_ = r.as_lines(); + } +} + +TOML11_INLINE std::string const& source_location::first_line() const +{ + if(this->line_str_.size() == 0) + { + throw std::out_of_range("toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.front(); +} +TOML11_INLINE std::string const& source_location::last_line() const +{ + if(this->line_str_.size() == 0) + { + throw std::out_of_range("toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.back(); +} + +namespace detail +{ + +TOML11_INLINE std::size_t integer_width_base10(std::size_t i) noexcept +{ + std::size_t width = 0; + while(i != 0) + { + i /= 10; + width += 1; + } + return width; +} + +TOML11_INLINE std::ostringstream& +format_filename(std::ostringstream& oss, const source_location& loc) +{ + // --> example.toml + oss << color::bold << color::blue << " --> " << color::reset + << color::bold << loc.file_name() << '\n' << color::reset; + return oss; +} + +TOML11_INLINE std::ostringstream& format_empty_line(std::ostringstream& oss, + const std::size_t lnw) +{ + // | + oss << detail::make_string(lnw + 1, ' ') + << color::bold << color::blue << " |\n" << color::reset; + return oss; +} + +TOML11_INLINE std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, const std::size_t linenum, const std::string& line) +{ + // 10 | key = "value" + oss << ' ' << color::bold << color::blue + << std::setw(static_cast(lnw)) + << std::right << linenum << " | " << color::reset; + for(const char c : line) + { + if(std::isgraph(c) || c == ' ') + { + oss << c; + } + else + { + oss << show_char(c); + } + } + oss << '\n'; + return oss; +} +TOML11_INLINE std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, const std::size_t col, const std::size_t len, + const std::string& msg) +{ + // | ^^^^^^^-- this part + oss << make_string(lnw + 1, ' ') + << color::bold << color::blue << " | " << color::reset; + + oss << make_string(col-1 /*1-origin*/, ' ') + << color::bold << color::red + << make_string(len, '^') << "-- " + << color::reset << msg << '\n'; + + return oss; +} + +TOML11_INLINE std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, const std::string& msg) +{ + std::ostringstream oss; + + if(loc.file_name() != prev_fname) + { + format_filename(oss, loc); + if( ! loc.lines().empty()) + { + format_empty_line(oss, lnw); + } + } + + if(loc.lines().size() == 1) + { + // when column points LF, it exceeds the size of the first line. + std::size_t underline_limit = 1; + if(loc.first_line().size() < loc.first_column_number()) + { + underline_limit = 1; + } + else + { + underline_limit = loc.first_line().size() - loc.first_column_number() + 1; + } + const auto underline_len = (std::min)(underline_limit, loc.length()); + + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), underline_len, msg); + } + else if(loc.lines().size() == 2) + { + const auto first_underline_len = + loc.first_line().size() - loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), + first_underline_len, ""); + + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } + else if(loc.lines().size() > 2) + { + const auto first_underline_len = + loc.first_line().size() - loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), + first_underline_len, "and"); + + if(loc.lines().size() == 3) + { + format_line(oss, lnw, loc.first_line_number()+1, loc.lines().at(1)); + format_underline(oss, lnw, 1, loc.lines().at(1).size(), "and"); + } + else + { + format_line(oss, lnw, loc.first_line_number()+1, " ..."); + format_empty_line(oss, lnw); + } + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } + // if loc is empty, do nothing. + return oss.str(); +} + +} // namespace detail +} // toml +#endif // TOML11_SOURCE_LOCATION_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/syntax_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/syntax_impl.hpp new file mode 100644 index 00000000..7dd3b81f --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/syntax_impl.hpp @@ -0,0 +1,732 @@ +#ifndef TOML11_SYNTAX_IMPL_HPP +#define TOML11_SYNTAX_IMPL_HPP + +#include "../fwd/syntax_fwd.hpp" +#include "../scanner.hpp" +#include "../spec.hpp" + +namespace toml +{ +namespace detail +{ +namespace syntax +{ + +using char_type = location::char_type; + +// =========================================================================== +// UTF-8 + +// avoid redundant representation and out-of-unicode sequence + +TOML11_INLINE character_in_range utf8_1byte(const spec&) +{ + return character_in_range(0x00, 0x7F); +} + +TOML11_INLINE sequence utf8_2bytes(const spec&) +{ + return sequence(character_in_range(0xC2, 0xDF), + character_in_range(0x80, 0xBF)); +} + +TOML11_INLINE sequence utf8_3bytes(const spec&) +{ + return sequence(/*1~2 bytes = */either( + sequence(character (0xE0), character_in_range(0xA0, 0xBF)), + sequence(character_in_range(0xE1, 0xEC), character_in_range(0x80, 0xBF)), + sequence(character (0xED), character_in_range(0x80, 0x9F)), + sequence(character_in_range(0xEE, 0xEF), character_in_range(0x80, 0xBF)) + ), /*3rd byte = */ character_in_range(0x80, 0xBF)); +} + +TOML11_INLINE sequence utf8_4bytes(const spec&) +{ + return sequence(/*1~2 bytes = */either( + sequence(character (0xF0), character_in_range(0x90, 0xBF)), + sequence(character_in_range(0xF1, 0xF3), character_in_range(0x80, 0xBF)), + sequence(character (0xF4), character_in_range(0x80, 0x8F)) + ), character_in_range(0x80, 0xBF), character_in_range(0x80, 0xBF)); +} + +TOML11_INLINE non_ascii::non_ascii(const spec& s) noexcept + : scanner_(utf8_2bytes(s), utf8_3bytes(s), utf8_4bytes(s)) +{} + + +// =========================================================================== +// Whitespace + +TOML11_INLINE character_either wschar(const spec&) +{ + return character_either{char_type(' '), char_type('\t')}; +} + +TOML11_INLINE repeat_at_least ws(const spec& s) +{ + return repeat_at_least(0, wschar(s)); +} + +// =========================================================================== +// Newline + +TOML11_INLINE either newline(const spec&) +{ + return either(character(char_type('\n')), literal("\r\n")); +} + +// =========================================================================== +// Comments + +TOML11_INLINE either allowed_comment_char(const spec& s) +{ + if(s.v1_1_0_allow_control_characters_in_comments) + { + return either( + character_in_range(0x01, 0x09), + character_in_range(0x0E, 0x7F), + non_ascii(s) + ); + } + else + { + return either( + character(0x09), + character_in_range(0x20, 0x7E), + non_ascii(s) + ); + } +} + +// XXX Note that it does not take newline +TOML11_INLINE sequence comment(const spec& s) +{ + return sequence(character(char_type('#')), + repeat_at_least(0, allowed_comment_char(s))); +} + +// =========================================================================== +// Boolean + +TOML11_INLINE either boolean(const spec&) +{ + return either(literal("true"), literal("false")); +} + +// =========================================================================== +// Integer + +TOML11_INLINE digit::digit(const spec&) noexcept + : scanner_(char_type('0'), char_type('9')) +{} + +TOML11_INLINE alpha::alpha(const spec&) noexcept + : scanner_( + character_in_range(char_type('a'), char_type('z')), + character_in_range(char_type('A'), char_type('Z')) + ) +{} + +TOML11_INLINE hexdig::hexdig(const spec& s) noexcept + : scanner_( + digit(s), + character_in_range(char_type('a'), char_type('f')), + character_in_range(char_type('A'), char_type('F')) + ) +{} + +// non-digit-graph = ([a-zA-Z]|unicode mb char) +// graph = ([a-zA-Z0-9]|unicode mb char) +// suffix = _ non-digit-graph (graph | _graph) +TOML11_INLINE sequence num_suffix(const spec& s) +{ + const auto non_digit_graph = [&s]() { + return either( + alpha(s), + non_ascii(s) + ); + }; + const auto graph = [&s]() { + return either( + alpha(s), + digit(s), + non_ascii(s) + ); + }; + + return sequence( + character(char_type('_')), + non_digit_graph(), + repeat_at_least(0, + either( + sequence(character(char_type('_')), graph()), + graph() + ) + ) + ); +} + +TOML11_INLINE sequence dec_int(const spec& s) +{ + const auto digit19 = []() { + return character_in_range(char_type('1'), char_type('9')); + }; + return sequence( + maybe(character_either{char_type('-'), char_type('+')}), + either( + sequence( + digit19(), + repeat_at_least(1, + either( + digit(s), + sequence(character(char_type('_')), digit(s)) + ) + ) + ), + digit(s) + ) + ); +} + +TOML11_INLINE sequence hex_int(const spec& s) +{ + return sequence( + literal("0x"), + hexdig(s), + repeat_at_least(0, + either( + hexdig(s), + sequence(character(char_type('_')), hexdig(s)) + ) + ) + ); +} + +TOML11_INLINE sequence oct_int(const spec&) +{ + const auto digit07 = []() { + return character_in_range(char_type('0'), char_type('7')); + }; + return sequence( + literal("0o"), + digit07(), + repeat_at_least(0, + either( + digit07(), + sequence(character(char_type('_')), digit07()) + ) + ) + ); +} + +TOML11_INLINE sequence bin_int(const spec&) +{ + const auto digit01 = []() { + return character_either{char_type('0'), char_type('1')}; + }; + return sequence( + literal("0b"), + digit01(), + repeat_at_least(0, + either( + digit01(), + sequence(character(char_type('_')), digit01()) + ) + ) + ); +} + +TOML11_INLINE either integer(const spec& s) +{ + return either( + hex_int(s), + oct_int(s), + bin_int(s), + dec_int(s) + ); +} + + +// =========================================================================== +// Floating + +TOML11_INLINE sequence zero_prefixable_int(const spec& s) +{ + return sequence( + digit(s), + repeat_at_least(0, + either( + digit(s), + sequence(character('_'), digit(s)) + ) + ) + ); +} + +TOML11_INLINE sequence fractional_part(const spec& s) +{ + return sequence( + character('.'), + zero_prefixable_int(s) + ); +} + +TOML11_INLINE sequence exponent_part(const spec& s) +{ + return sequence( + character_either{char_type('e'), char_type('E')}, + maybe(character_either{char_type('+'), char_type('-')}), + zero_prefixable_int(s) + ); +} + +TOML11_INLINE sequence hex_floating(const spec& s) +{ + // C99 hexfloat (%a) + // [+-]? 0x ( [0-9a-fA-F]*\.[0-9a-fA-F]+ | [0-9a-fA-F]+\.? ) [pP] [+-]? [0-9]+ + + // - 0x(int).(frac)p[+-](int) + // - 0x(int).p[+-](int) + // - 0x.(frac)p[+-](int) + // - 0x(int)p[+-](int) + + return sequence( + maybe(character_either{char_type('+'), char_type('-')}), + character('0'), + character_either{char_type('x'), char_type('X')}, + either( + sequence( + repeat_at_least(0, hexdig(s)), + character('.'), + repeat_at_least(1, hexdig(s)) + ), + sequence( + repeat_at_least(1, hexdig(s)), + maybe(character('.')) + ) + ), + character_either{char_type('p'), char_type('P')}, + maybe(character_either{char_type('+'), char_type('-')}), + repeat_at_least(1, character_in_range('0', '9')) + ); +} + +TOML11_INLINE either floating(const spec& s) +{ + return either( + sequence( + dec_int(s), + either( + exponent_part(s), + sequence(fractional_part(s), maybe(exponent_part(s))) + ) + ), + sequence( + maybe(character_either{char_type('-'), char_type('+')}), + either(literal("inf"), literal("nan")) + ) + ); +} + +// =========================================================================== +// Datetime + +TOML11_INLINE sequence local_date(const spec& s) +{ + return sequence( + repeat_exact(4, digit(s)), + character('-'), + repeat_exact(2, digit(s)), + character('-'), + repeat_exact(2, digit(s)) + ); +} +TOML11_INLINE sequence local_time(const spec& s) +{ + auto time = sequence( + repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s)) + ); + + if(s.v1_1_0_make_seconds_optional) + { + time.push_back(maybe(sequence( + character(':'), + repeat_exact(2, digit(s)), + maybe(sequence(character('.'), repeat_at_least(1, digit(s)))) + ))); + } + else + { + time.push_back(character(':')); + time.push_back(repeat_exact(2, digit(s))); + time.push_back( + maybe(sequence(character('.'), repeat_at_least(1, digit(s)))) + ); + } + + return time; +} +TOML11_INLINE either time_offset(const spec& s) +{ + return either( + character_either{'Z', 'z'}, + sequence(character_either{'+', '-'}, + repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s)) + ) + ); +} +TOML11_INLINE sequence full_time(const spec& s) +{ + return sequence(local_time(s), time_offset(s)); +} +TOML11_INLINE character_either time_delim(const spec&) +{ + return character_either{'T', 't', ' '}; +} +TOML11_INLINE sequence local_datetime(const spec& s) +{ + return sequence(local_date(s), time_delim(s), local_time(s)); +} +TOML11_INLINE sequence offset_datetime(const spec& s) +{ + return sequence(local_date(s), time_delim(s), full_time(s)); +} + +// =========================================================================== +// String + +TOML11_INLINE sequence escaped(const spec& s) +{ + character_either escape_char{ + '\"','\\', 'b', 'f', 'n', 'r', 't' + }; + if(s.v1_1_0_add_escape_sequence_e) + { + escape_char.push_back(char_type('e')); + } + + either escape_seq( + std::move(escape_char), + sequence(character('u'), repeat_exact(4, hexdig(s))), + sequence(character('U'), repeat_exact(8, hexdig(s))) + ); + + if(s.v1_1_0_add_escape_sequence_x) + { + escape_seq.push_back( + sequence(character('x'), repeat_exact(2, hexdig(s))) + ); + } + + return sequence( + character('\\'), + std::move(escape_seq) + ); +} + +TOML11_INLINE either basic_char(const spec& s) +{ + const auto basic_unescaped = [&s]() { + return either( + wschar(s), + character(0x21), // 22 is " + character_in_range(0x23, 0x5B), // 5C is backslash + character_in_range(0x5D, 0x7E), // 7F is DEL + non_ascii(s) + ); + }; + return either(basic_unescaped(), escaped(s)); +} + +TOML11_INLINE sequence basic_string(const spec& s) +{ + return sequence( + character('"'), + repeat_at_least(0, basic_char(s)), + character('"') + ); +} + +// --------------------------------------------------------------------------- +// multiline string + +TOML11_INLINE sequence escaped_newline(const spec& s) +{ + return sequence( + character('\\'), ws(s), newline(s), + repeat_at_least(0, either(wschar(s), newline(s))) + ); +} + +TOML11_INLINE sequence ml_basic_string(const spec& s) +{ + const auto mlb_content = [&s]() { + return either(basic_char(s), newline(s), escaped_newline(s)); + }; + const auto mlb_quotes = []() { + return either(literal("\"\""), character('\"')); + }; + + return sequence( + literal("\"\"\""), + maybe(newline(s)), + repeat_at_least(0, mlb_content()), + repeat_at_least(0, + sequence( + mlb_quotes(), + repeat_at_least(1, mlb_content()) + ) + ), + // XXX """ and mlb_quotes are intentionally reordered to avoid + // unexpected match of mlb_quotes + literal("\"\"\""), + maybe(mlb_quotes()) + ); +} + +// --------------------------------------------------------------------------- +// literal string + +TOML11_INLINE either literal_char(const spec& s) +{ + return either( + character (0x09), + character_in_range(0x20, 0x26), + character_in_range(0x28, 0x7E), + non_ascii(s) + ); +} + +TOML11_INLINE sequence literal_string(const spec& s) +{ + return sequence( + character('\''), + repeat_at_least(0, literal_char(s)), + character('\'') + ); +} + +TOML11_INLINE sequence ml_literal_string(const spec& s) +{ + const auto mll_quotes = []() { + return either(literal("''"), character('\'')); + }; + const auto mll_content = [&s]() { + return either(literal_char(s), newline(s)); + }; + + return sequence( + literal("'''"), + maybe(newline(s)), + repeat_at_least(0, mll_content()), + repeat_at_least(0, sequence( + mll_quotes(), + repeat_at_least(1, mll_content()) + ) + ), + literal("'''"), + maybe(mll_quotes()) + // XXX ''' and mll_quotes are intentionally reordered to avoid + // unexpected match of mll_quotes + ); +} + +TOML11_INLINE either string(const spec& s) +{ + return either( + ml_basic_string(s), + ml_literal_string(s), + basic_string(s), + literal_string(s) + ); +} + +// =========================================================================== +// Keys + +// to keep `expected_chars` simple +TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept +{ + assert(s.v1_1_0_allow_non_english_in_bare_keys); + (void)s; // for NDEBUG +} + +TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const +{ + // U+0000 ... U+0079 ; 0xxx_xxxx + // U+0080 ... U+07FF ; 110y_yyyx 10xx_xxxx; + // U+0800 ... U+FFFF ; 1110_yyyy 10yx_xxxx 10xx_xxxx + // U+010000 ... U+10FFFF; 1111_0yyy 10yy_xxxx 10xx_xxxx 10xx_xxxx + + const unsigned char b1 = loc.current(); loc.advance(1); + if(b1 < 0x80) + { + return static_cast(b1); + } + else if((b1 >> 5) == 6) // 0b110 == 6 + { + const auto b2 = loc.current(); loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 5) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 6) + c2; + + if(codep < 0x80) + { + return 0xFFFFFFFF; + } + return codep; + } + else if((b1 >> 4) == 14) // 0b1110 == 14 + { + const auto b2 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;} + const auto b3 = loc.current(); loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 4) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + + const std::uint32_t codep = (c1 << 12) + (c2 << 6) + c3; + if(codep < 0x800) + { + return 0xFFFFFFFF; + } + return codep; + } + else if((b1 >> 3) == 30) // 0b11110 == 30 + { + const auto b2 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;} + const auto b3 = loc.current(); loc.advance(1); if(loc.eof()) {return 0xFFFFFFFF;} + const auto b4 = loc.current(); loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 3) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + const std::uint32_t c4 = b4 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; + + if(codep < 0x10000) + { + return 0xFFFFFFFF; + } + return codep; + } + else // not a Unicode codepoint in UTF-8 + { + return 0xFFFFFFFF; + } +} + +TOML11_INLINE region non_ascii_key_char::scan(location& loc) const +{ + if(loc.eof()) {return region{};} + + const auto first = loc; + + const auto cp = read_utf8(loc); + + if(cp == 0xFFFFFFFF) + { + return region{}; + } + + // ALPHA / DIGIT / %x2D / %x5F ; a-z A-Z 0-9 - _ + // / %xB2 / %xB3 / %xB9 / %xBC-BE ; superscript digits, fractions + // / %xC0-D6 / %xD8-F6 / %xF8-37D ; non-symbol chars in Latin block + // / %x37F-1FFF ; exclude GREEK QUESTION MARK, which is basically a semi-colon + // / %x200C-200D / %x203F-2040 ; from General Punctuation Block, include the two tie symbols and ZWNJ, ZWJ + // / %x2070-218F / %x2460-24FF ; include super-/subscripts, letterlike/numberlike forms, enclosed alphanumerics + // / %x2C00-2FEF / %x3001-D7FF ; skip arrows, math, box drawing etc, skip 2FF0-3000 ideographic up/down markers and spaces + // / %xF900-FDCF / %xFDF0-FFFD ; skip D800-DFFF surrogate block, E000-F8FF Private Use area, FDD0-FDEF intended for process-internal use (unicode) + // / %x10000-EFFFF ; all chars outside BMP range, excluding Private Use planes (F0000-10FFFF) + + if(cp == 0xB2 || cp == 0xB3 || cp == 0xB9 || (0xBC <= cp && cp <= 0xBE) || + (0xC0 <= cp && cp <= 0xD6 ) || (0xD8 <= cp && cp <= 0xF6) || (0xF8 <= cp && cp <= 0x37D) || + (0x37F <= cp && cp <= 0x1FFF) || + (0x200C <= cp && cp <= 0x200D) || (0x203F <= cp && cp <= 0x2040) || + (0x2070 <= cp && cp <= 0x218F) || (0x2460 <= cp && cp <= 0x24FF) || + (0x2C00 <= cp && cp <= 0x2FEF) || (0x3001 <= cp && cp <= 0xD7FF) || + (0xF900 <= cp && cp <= 0xFDCF) || (0xFDF0 <= cp && cp <= 0xFFFD) || + (0x10000 <= cp && cp <= 0xEFFFF) ) + { + return region(first, loc); + } + loc = first; + return region{}; +} + +TOML11_INLINE repeat_at_least unquoted_key(const spec& s) +{ + auto keychar = either( + alpha(s), digit(s), character{0x2D}, character{0x5F} + ); + + if(s.v1_1_0_allow_non_english_in_bare_keys) + { + keychar.push_back(non_ascii_key_char(s)); + } + + return repeat_at_least(1, std::move(keychar)); +} + +TOML11_INLINE either quoted_key(const spec& s) +{ + return either(basic_string(s), literal_string(s)); +} + +TOML11_INLINE either simple_key(const spec& s) +{ + return either(unquoted_key(s), quoted_key(s)); +} + +TOML11_INLINE sequence dot_sep(const spec& s) +{ + return sequence(ws(s), character('.'), ws(s)); +} + +TOML11_INLINE sequence dotted_key(const spec& s) +{ + return sequence( + simple_key(s), + repeat_at_least(1, sequence(dot_sep(s), simple_key(s))) + ); +} + +TOML11_INLINE key::key(const spec& s) noexcept + : scanner_(dotted_key(s), simple_key(s)) +{} + +TOML11_INLINE sequence keyval_sep(const spec& s) +{ + return sequence(ws(s), character('='), ws(s)); +} + +// =========================================================================== +// Table key + +TOML11_INLINE sequence std_table(const spec& s) +{ + return sequence(character('['), ws(s), key(s), ws(s), character(']')); +} + +TOML11_INLINE sequence array_table(const spec& s) +{ + return sequence(literal("[["), ws(s), key(s), ws(s), literal("]]")); +} + +// =========================================================================== +// extension: null + +TOML11_INLINE literal null_value(const spec&) +{ + return literal("null"); +} + +} // namespace syntax +} // namespace detail +} // namespace toml +#endif // TOML11_SYNTAX_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/impl/value_t_impl.hpp b/src/frontend/qt_sdl/toml/toml11/impl/value_t_impl.hpp new file mode 100644 index 00000000..784dc8b2 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/impl/value_t_impl.hpp @@ -0,0 +1,40 @@ +#ifndef TOML11_VALUE_T_IMPL_HPP +#define TOML11_VALUE_T_IMPL_HPP + +#include "../fwd/value_t_fwd.hpp" + +#include +#include +#include + +namespace toml +{ + +TOML11_INLINE std::ostream& operator<<(std::ostream& os, value_t t) +{ + switch(t) + { + case value_t::boolean : os << "boolean"; return os; + case value_t::integer : os << "integer"; return os; + case value_t::floating : os << "floating"; return os; + case value_t::string : os << "string"; return os; + case value_t::offset_datetime : os << "offset_datetime"; return os; + case value_t::local_datetime : os << "local_datetime"; return os; + case value_t::local_date : os << "local_date"; return os; + case value_t::local_time : os << "local_time"; return os; + case value_t::array : os << "array"; return os; + case value_t::table : os << "table"; return os; + case value_t::empty : os << "empty"; return os; + default : os << "unknown"; return os; + } +} + +TOML11_INLINE std::string to_string(value_t t) +{ + std::ostringstream oss; + oss << t; + return oss.str(); +} + +} // namespace toml +#endif // TOML11_VALUE_T_IMPL_HPP diff --git a/src/frontend/qt_sdl/toml/toml/into.hpp b/src/frontend/qt_sdl/toml/toml11/into.hpp similarity index 79% rename from src/frontend/qt_sdl/toml/toml/into.hpp rename to src/frontend/qt_sdl/toml/toml11/into.hpp index 74495560..86a0020e 100644 --- a/src/frontend/qt_sdl/toml/toml/into.hpp +++ b/src/frontend/qt_sdl/toml/toml11/into.hpp @@ -1,5 +1,3 @@ -// Copyright Toru Niina 2019. -// Distributed under the MIT License. #ifndef TOML11_INTO_HPP #define TOML11_INTO_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/literal.hpp b/src/frontend/qt_sdl/toml/toml11/literal.hpp new file mode 100644 index 00000000..e30e7a83 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/literal.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_LITERAL_HPP +#define TOML11_LITERAL_HPP + +#include "fwd/literal_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/literal_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_LITERAL_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/location.hpp b/src/frontend/qt_sdl/toml/toml11/location.hpp new file mode 100644 index 00000000..fd232744 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/location.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_LOCATION_HPP +#define TOML11_LOCATION_HPP + +#include "fwd/location_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/location_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_LOCATION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/ordered_map.hpp b/src/frontend/qt_sdl/toml/toml11/ordered_map.hpp new file mode 100644 index 00000000..b9cd3042 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/ordered_map.hpp @@ -0,0 +1,265 @@ +#ifndef TOML11_ORDERED_MAP_HPP +#define TOML11_ORDERED_MAP_HPP + +#include +#include +#include +#include + +namespace toml +{ + +namespace detail +{ +template +struct ordered_map_ebo_container +{ + Cmp cmp_; // empty base optimization for empty Cmp type +}; +} // detail + +template, + typename Allocator = std::allocator>> +class ordered_map : detail::ordered_map_ebo_container +{ + public: + using key_type = Key; + using mapped_type = Val; + using value_type = std::pair; + + using key_compare = Cmp; + using allocator_type = Allocator; + + using container_type = std::vector; + using reference = typename container_type::reference; + using pointer = typename container_type::pointer; + using const_reference = typename container_type::const_reference; + using const_pointer = typename container_type::const_pointer; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + + private: + + using ebo_base = detail::ordered_map_ebo_container; + + public: + + ordered_map() = default; + ~ordered_map() = default; + ordered_map(const ordered_map&) = default; + ordered_map(ordered_map&&) = default; + ordered_map& operator=(const ordered_map&) = default; + ordered_map& operator=(ordered_map&&) = default; + + ordered_map(const ordered_map& other, const Allocator& alloc) + : container_(other.container_, alloc) + {} + ordered_map(ordered_map&& other, const Allocator& alloc) + : container_(std::move(other.container_), alloc) + {} + + explicit ordered_map(const Cmp& cmp, const Allocator& alloc = Allocator()) + : ebo_base{cmp}, container_(alloc) + {} + explicit ordered_map(const Allocator& alloc) + : container_(alloc) + {} + + template + ordered_map(InputIterator first, InputIterator last, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator()) + : ebo_base{cmp}, container_(first, last, alloc) + {} + template + ordered_map(InputIterator first, InputIterator last, const Allocator& alloc) + : container_(first, last, alloc) + {} + + ordered_map(std::initializer_list v, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator()) + : ebo_base{cmp}, container_(std::move(v), alloc) + {} + ordered_map(std::initializer_list v, const Allocator& alloc) + : container_(std::move(v), alloc) + {} + ordered_map& operator=(std::initializer_list v) + { + this->container_ = std::move(v); + return *this; + } + + iterator begin() noexcept {return container_.begin();} + iterator end() noexcept {return container_.end();} + const_iterator begin() const noexcept {return container_.begin();} + const_iterator end() const noexcept {return container_.end();} + const_iterator cbegin() const noexcept {return container_.cbegin();} + const_iterator cend() const noexcept {return container_.cend();} + + bool empty() const noexcept {return container_.empty();} + std::size_t size() const noexcept {return container_.size();} + std::size_t max_size() const noexcept {return container_.max_size();} + + void clear() {container_.clear();} + + void push_back(const value_type& v) + { + if(this->contains(v.first)) + { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(v); + } + void push_back(value_type&& v) + { + if(this->contains(v.first)) + { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(v)); + } + void emplace_back(key_type k, mapped_type v) + { + if(this->contains(k)) + { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + void pop_back() {container_.pop_back();} + + void insert(value_type kv) + { + if(this->contains(kv.first)) + { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(kv)); + } + void emplace(key_type k, mapped_type v) + { + if(this->contains(k)) + { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + + std::size_t count(const key_type& key) const + { + if(this->find(key) != this->end()) + { + return 1; + } + else + { + return 0; + } + } + bool contains(const key_type& key) const + { + return this->find(key) != this->end(); + } + iterator find(const key_type& key) noexcept + { + return std::find_if(this->begin(), this->end(), + [&key, this](const value_type& v) {return this->cmp_(v.first, key);}); + } + const_iterator find(const key_type& key) const noexcept + { + return std::find_if(this->begin(), this->end(), + [&key, this](const value_type& v) {return this->cmp_(v.first, key);}); + } + + mapped_type& at(const key_type& k) + { + const auto iter = this->find(k); + if(iter == this->end()) + { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + mapped_type const& at(const key_type& k) const + { + const auto iter = this->find(k); + if(iter == this->end()) + { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + mapped_type& operator[](const key_type& k) + { + const auto iter = this->find(k); + if(iter == this->end()) + { + this->container_.emplace_back(k, mapped_type{}); + return this->container_.back().second; + } + return iter->second; + } + + mapped_type const& operator[](const key_type& k) const + { + const auto iter = this->find(k); + if(iter == this->end()) + { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + key_compare key_comp() const {return this->cmp_;} + + void swap(ordered_map& other) + { + container_.swap(other.container_); + } + + private: + + container_type container_; +}; + +template +bool operator==(const ordered_map& lhs, const ordered_map& rhs) +{ + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} +template +bool operator!=(const ordered_map& lhs, const ordered_map& rhs) +{ + return !(lhs == rhs); +} +template +bool operator<(const ordered_map& lhs, const ordered_map& rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} +template +bool operator>(const ordered_map& lhs, const ordered_map& rhs) +{ + return rhs < lhs; +} +template +bool operator<=(const ordered_map& lhs, const ordered_map& rhs) +{ + return !(lhs > rhs); +} +template +bool operator>=(const ordered_map& lhs, const ordered_map& rhs) +{ + return !(lhs < rhs); +} + +template +void swap(ordered_map& lhs, ordered_map& rhs) +{ + lhs.swap(rhs); + return; +} + + +} // toml +#endif // TOML11_ORDERED_MAP_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/parser.hpp b/src/frontend/qt_sdl/toml/toml11/parser.hpp new file mode 100644 index 00000000..6d147311 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/parser.hpp @@ -0,0 +1,3829 @@ +#ifndef TOML11_PARSER_HPP +#define TOML11_PARSER_HPP + +#include "context.hpp" +#include "datetime.hpp" +#include "error_info.hpp" +#include "region.hpp" +#include "result.hpp" +#include "scanner.hpp" +#include "skip.hpp" +#include "syntax.hpp" +#include "value.hpp" + +#include +#include + +#include +#include + +#if defined(TOML11_HAS_FILESYSTEM) && TOML11_HAS_FILESYSTEM +#include +#endif + +namespace toml +{ + +struct syntax_error final : public ::toml::exception +{ + public: + syntax_error(std::string what_arg, std::vector err) + : what_(std::move(what_arg)), err_(std::move(err)) + {} + ~syntax_error() noexcept override = default; + + const char* what() const noexcept override {return what_.c_str();} + + std::vector const& errors() const noexcept + { + return err_; + } + + private: + std::string what_; + std::vector err_; +}; + +struct file_io_error final : public ::toml::exception +{ + public: + + file_io_error(const std::string& msg, const std::string& fname) + : errno_(cxx::make_nullopt()), + what_(msg + " \"" + fname + "\"") + {} + file_io_error(int errnum, const std::string& msg, const std::string& fname) + : errno_(errnum), + what_(msg + " \"" + fname + "\": errno=" + std::to_string(errnum)) + {} + ~file_io_error() noexcept override = default; + + const char* what() const noexcept override {return what_.c_str();} + + bool has_errno() const noexcept {return errno_.has_value();} + int get_errno() const noexcept {return errno_.value_or(0);} + + private: + + cxx::optional errno_; + std::string what_; +}; + +namespace detail +{ + +/* ============================================================================ + * __ ___ _ __ _ __ ___ _ _ + * / _/ _ \ ' \| ' \/ _ \ ' \ + * \__\___/_|_|_|_|_|_\___/_||_| + */ + +template +error_info make_syntax_error(std::string title, + const S& scanner, location loc, std::string suffix = "") +{ + auto msg = std::string("expected ") + scanner.expected_chars(loc); + auto src = source_location(region(loc)); + return make_error_info( + std::move(title), std::move(src), std::move(msg), std::move(suffix)); +} + + +/* ============================================================================ + * _ + * __ ___ _ __ _ __ ___ _ _| |_ + * / _/ _ \ ' \| ' \/ -_) ' \ _| + * \__\___/_|_|_|_|_|_\___|_||_\__| + */ + +template +result, error_info> +parse_comment_line(location& loc, context& ctx) +{ + const auto& spec = ctx.toml_spec(); + const auto first = loc; + + skip_whitespace(loc, ctx); + + const auto com_reg = syntax::comment(spec).scan(loc); + if(com_reg.is_ok()) + { + // once comment started, newline must follow (or reach EOF). + if( ! loc.eof() && ! syntax::newline(spec).scan(loc).is_ok()) + { + while( ! loc.eof()) // skip until newline to continue parsing + { + loc.advance(); + if(loc.current() == '\n') { /*skip LF*/ loc.advance(); break; } + } + return err(make_error_info("toml::parse_comment_line: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), "but got this", + "Hint: most of the control characters are not allowed in comments")); + } + return ok(cxx::optional(com_reg.as_string())); + } + else + { + loc = first; // rollback whitespace to parse indent + return ok(cxx::optional(cxx::make_nullopt())); + } +} + +/* ============================================================================ + * ___ _ + * | _ ) ___ ___| |___ __ _ _ _ + * | _ \/ _ \/ _ \ / -_) _` | ' \ + * |___/\___/\___/_\___\__,_|_||_| + */ + +template +result, error_info> +parse_boolean(location& loc, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::boolean(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_boolean: " + "invalid boolean: boolean must be `true` or `false`, in lowercase. " + "string must be surrounded by `\"`", syntax::boolean(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + const auto val = [&str]() { + if(str == "true") + { + return true; + } + else + { + assert(str == "false"); + return false; + } + }(); + + // ---------------------------------------------------------------------- + // no format info for boolean + boolean_format_info fmt; + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); +} + +/* ============================================================================ + * ___ _ + * |_ _|_ _| |_ ___ __ _ ___ _ _ + * | || ' \ _/ -_) _` / -_) '_| + * |___|_||_\__\___\__, \___|_| + * |___/ + */ + +template +result, error_info> +parse_bin_integer(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::bin_int(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_bin_integer: " + "invalid integer: bin_int must be like: 0b0101, 0b1111_0000", + syntax::bin_int(spec), loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::bin; + fmt.width = str.size() - 2 - static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if(first_underscore != str.rend()) + { + fmt.spacer = static_cast(std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0b` and zeros and underscores at the MSB + str.erase(str.begin(), std::find(std::next(str.begin(), 2), str.end(), '1')); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0b0000_0000 becomes empty. + if(str.empty()) { str = "0"; } + + const auto val = TC::parse_int(str, source_location(region(loc)), 2); + if(val.is_ok()) + { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } + else + { + loc = first; + return err(val.as_err()); + } +} + +// ---------------------------------------------------------------------------- + +template +result, error_info> +parse_oct_integer(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::oct_int(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_oct_integer: " + "invalid integer: oct_int must be like: 0o775, 0o04_44", + syntax::oct_int(spec), loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::oct; + fmt.width = str.size() - 2 - static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if(first_underscore != str.rend()) + { + fmt.spacer = static_cast(std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0o` and zeros and underscores at the MSB + str.erase(str.begin(), std::find_if( + std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0o0000_0000 becomes empty. + if(str.empty()) { str = "0"; } + + const auto val = TC::parse_int(str, source_location(region(loc)), 8); + if(val.is_ok()) + { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } + else + { + loc = first; + return err(val.as_err()); + } +} + +template +result, error_info> +parse_hex_integer(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::hex_int(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_hex_integer: " + "invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef", + syntax::hex_int(spec), loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::hex; + fmt.width = str.size() - 2 - static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if(first_underscore != str.rend()) + { + fmt.spacer = static_cast(std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0x` and zeros and underscores at the MSB + str.erase(str.begin(), std::find_if( + std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0x0000_0000 becomes empty. + if(str.empty()) { str = "0"; } + + // prefix zero and _ is removed. check if it uses upper/lower case. + // if both upper and lower case letters are found, set upper=true. + const auto lower_not_found = std::find_if(str.begin(), str.end(), + [](const char c) { return std::islower(static_cast(c)) != 0; }) == str.end(); + const auto upper_found = std::find_if(str.begin(), str.end(), + [](const char c) { return std::isupper(static_cast(c)) != 0; }) != str.end(); + fmt.uppercase = lower_not_found || upper_found; + + const auto val = TC::parse_int(str, source_location(region(loc)), 16); + if(val.is_ok()) + { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } + else + { + loc = first; + return err(val.as_err()); + } +} + +template +result, error_info> +parse_dec_integer(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::dec_int(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_dec_integer: " + "invalid integer: dec_int must be like: 42, 123_456_789", + syntax::dec_int(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::dec; + fmt.width = str.size() - static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if(first_underscore != str.rend()) + { + fmt.spacer = static_cast(std::distance(str.rbegin(), first_underscore)); + } + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + auto src = source_location(region(loc)); + const auto val = TC::parse_int(str, src, 10); + if(val.is_err()) + { + loc = first; + return err(val.as_err()); + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if(spec.ext_num_suffix && loc.current() == '_') + { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if( ! sfx_reg.is_ok()) + { + loc = first; + return err(make_error_info("toml::parse_dec_integer: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + source_location(region(loc)), "here")); + } + auto sfx = sfx_reg.as_string(); + assert( ! sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); +} + +template +result, error_info> +parse_integer(location& loc, const context& ctx) +{ + const auto first = loc; + + if( ! loc.eof() && (loc.current() == '+' || loc.current() == '-')) + { + // skip +/- to diagnose +0xDEADBEEF or -0b0011 (invalid). + // without this, +0xDEAD_BEEF will be parsed as a decimal int and + // unexpected "xDEAD_BEEF" will appear after integer "+0". + loc.advance(); + } + + if( ! loc.eof() && loc.current() == '0') + { + loc.advance(); + if(loc.eof()) + { + // `[+-]?0`. parse as an decimal integer. + loc = first; + return parse_dec_integer(loc, ctx); + } + + const auto prefix = loc.current(); + auto prefix_src = source_location(region(loc)); + + loc = first; + + if(prefix == 'b') {return parse_bin_integer(loc, ctx);} + if(prefix == 'o') {return parse_oct_integer(loc, ctx);} + if(prefix == 'x') {return parse_hex_integer(loc, ctx);} + + if(std::isdigit(prefix)) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_integer: " + "leading zero in an decimal integer is not allowed", + std::move(src), "leading zero")); + } + } + + loc = first; + return parse_dec_integer(loc, ctx); +} + +/* ============================================================================ + * ___ _ _ _ + * | __| |___ __ _| |_(_)_ _ __ _ + * | _|| / _ \/ _` | _| | ' \/ _` | + * |_| |_\___/\__,_|\__|_|_||_\__, | + * |___/ + */ + +template +result, error_info> +parse_floating(location& loc, const context& ctx) +{ + using floating_type = typename basic_value::floating_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + bool is_hex = false; + std::string str; + region reg; + if(spec.ext_hex_float && sequence(character('0'), character('x')).scan(loc).is_ok()) + { + loc = first; + is_hex = true; + + reg = syntax::hex_floating(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_floating: " + "invalid hex floating: float must be like: 0xABCp-3f", + syntax::floating(spec), loc)); + } + str = reg.as_string(); + } + else + { + reg = syntax::floating(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_floating: " + "invalid floating: float must be like: -3.14159_26535, 6.022e+23, " + "inf, or nan (lowercase).", syntax::floating(spec), loc)); + } + str = reg.as_string(); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + floating_format_info fmt; + + if(is_hex) + { + fmt.fmt = floating_format::hex; + } + else + { + // since we already checked that the string conforms the TOML standard. + if(std::find(str.begin(), str.end(), 'e') != str.end() || + std::find(str.begin(), str.end(), 'E') != str.end()) + { + fmt.fmt = floating_format::scientific; // use exponent part + } + else + { + fmt.fmt = floating_format::fixed; // do not use exponent part + } + } + + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + floating_type val{0}; + + if(str == "inf" || str == "+inf") + { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) + { + val = std::numeric_limits::infinity(); + } + else + { + return err(make_error_info("toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } + else if(str == "-inf") + { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) + { + val = -std::numeric_limits::infinity(); + } + else + { + return err(make_error_info("toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } + else if(str == "nan" || str == "+nan") + { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) + { + val = std::numeric_limits::quiet_NaN(); + } + else TOML11_CONSTEXPR_IF(std::numeric_limits::has_signaling_NaN) + { + val = std::numeric_limits::signaling_NaN(); + } + else + { + return err(make_error_info("toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } + else if(str == "-nan") + { + using std::copysign; + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) + { + val = copysign(std::numeric_limits::quiet_NaN(), floating_type(-1)); + } + else TOML11_CONSTEXPR_IF(std::numeric_limits::has_signaling_NaN) + { + val = copysign(std::numeric_limits::signaling_NaN(), floating_type(-1)); + } + else + { + return err(make_error_info("toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } + else + { + // set precision + const auto has_sign = ! str.empty() && (str.front() == '+' || str.front() == '-'); + const auto decpoint = std::find(str.begin(), str.end(), '.'); + const auto exponent = std::find_if(str.begin(), str.end(), + [](const char c) { return c == 'e' || c == 'E'; }); + if(decpoint != str.end() && exponent != str.end()) + { + assert(decpoint < exponent); + } + + if(fmt.fmt == floating_format::scientific) + { + // total width + fmt.prec = static_cast(std::distance(str.begin(), exponent)); + if(has_sign) + { + fmt.prec -= 1; + } + if(decpoint != str.end()) + { + fmt.prec -= 1; + } + } + else if(fmt.fmt == floating_format::hex) + { + fmt.prec = std::numeric_limits::max_digits10; + } + else + { + // width after decimal point + fmt.prec = static_cast(std::distance(std::next(decpoint), exponent)); + } + + auto src = source_location(region(loc)); + const auto res = TC::parse_float(str, src, is_hex); + if(res.is_ok()) + { + val = res.as_ok(); + } + else + { + return err(res.as_err()); + } + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if(spec.ext_num_suffix && loc.current() == '_') + { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if( ! sfx_reg.is_ok()) + { + auto src = source_location(region(loc)); + loc = first; + return err(make_error_info("toml::parse_floating: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + std::move(src), "here")); + } + auto sfx = sfx_reg.as_string(); + assert( ! sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); +} + +/* ============================================================================ + * ___ _ _ _ + * | \ __ _| |_ ___| |_(_)_ __ ___ + * | |) / _` | _/ -_) _| | ' \/ -_) + * |___/\__,_|\__\___|\__|_|_|_|_\___| + */ + +// all the offset_datetime, local_datetime, local_date parses date part. +template +result, error_info> +parse_local_date_only(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_date_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_date(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_local_date: " + "invalid date: date must be like: 1234-05-06, yyyy-mm-dd.", + syntax::local_date(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // 0123456789 + // yyyy-mm-dd + const auto year_r = from_string(str.substr(0, 4)); + const auto month_r = from_string(str.substr(5, 2)); + const auto day_r = from_string(str.substr(8, 2)); + + if(year_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read year `" + str.substr(0, 4) + "`", + std::move(src), "here")); + } + if(month_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read month `" + str.substr(5, 2) + "`", + std::move(src), "here")); + } + if(day_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read day `" + str.substr(8, 2) + "`", + std::move(src), "here")); + } + + const auto year = year_r.unwrap(); + const auto month = month_r.unwrap(); + const auto day = day_r.unwrap(); + + { + // We briefly check whether the input date is valid or not. + // Actually, because of the historical reasons, there are several + // edge cases, such as 1582/10/5-1582/10/14 (only in several countries). + // But here, we do not care about it. + // It makes the code complicated and there is only low probability + // that such a specific date is needed in practice. If someone need to + // validate date accurately, that means that the one need a specialized + // library for their purpose in another layer. + + const bool is_leap = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); + const auto max_day = [month, is_leap]() { + if(month == 2) + { + return is_leap ? 29 : 28; + } + if(month == 4 || month == 6 || month == 9 || month == 11) + { + return 30; + } + return 31; + }(); + + if((month < 1 || 12 < month) || (day < 1 || max_day < day)) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: invalid date.", + std::move(src), "month must be 01-12, day must be any of " + "01-28,29,30,31 depending on the month/year.")); + } + } + + return ok(std::make_tuple( + local_date(year, static_cast(month - 1), day), + std::move(fmt), std::move(reg) + )); +} + +template +result, error_info> +parse_local_date(location& loc, const context& ctx) +{ + auto val_fmt_reg = parse_local_date_only(loc, ctx); + if(val_fmt_reg.is_err()) + { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok(basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); +} + +// all the offset_datetime, local_datetime, local_time parses date part. +template +result, error_info> +parse_local_time_only(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_time_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_time(spec).scan(loc); + if( ! reg.is_ok()) + { + if(spec.v1_1_0_make_seconds_optional) + { + return err(make_syntax_error("toml::parse_local_time: " + "invalid time: time must be HH:MM(:SS.sss) (seconds are optional)", + syntax::local_time(spec), loc)); + } + else + { + return err(make_syntax_error("toml::parse_local_time: " + "invalid time: time must be HH:MM:SS(.sss) (subseconds are optional)", + syntax::local_time(spec), loc)); + } + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // at least we have HH:MM. + // 01234 + // HH:MM + const auto hour_r = from_string(str.substr(0, 2)); + const auto minute_r = from_string(str.substr(3, 2)); + + if(hour_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read hour `" + str.substr(0, 2) + "`", + std::move(src), "here")); + } + if(minute_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read minute `" + str.substr(3, 2) + "`", + std::move(src), "here")); + } + + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute)) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: invalid time.", + std::move(src), "hour must be 00-23, minute must be 00-59.")); + } + + // ----------------------------------------------------------------------- + // we have hour and minute. + // Since toml v1.1.0, second and subsecond part becomes optional. + // Check the version and return if second does not exist. + + if(str.size() == 5 && spec.v1_1_0_make_seconds_optional) + { + fmt.has_seconds = false; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, 0), std::move(fmt), std::move(reg))); + } + assert(str.at(5) == ':'); + + // we have at least `:SS` part. `.subseconds` are optional. + + // 0 1 + // 012345678901234 + // HH:MM:SS.subsec + const auto sec_r = from_string(str.substr(6, 2)); + if(sec_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read second `" + str.substr(6, 2) + "`", + std::move(src), "here")); + } + const auto sec = sec_r.unwrap(); + + if(sec < 0 || 60 < sec) // :60 is allowed + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: invalid time.", + std::move(src), "second must be 00-60.")); + } + + if(str.size() == 8) + { + fmt.has_seconds = true; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, sec), std::move(fmt), std::move(reg))); + } + + assert(str.at(8) == '.'); + + auto secfrac = str.substr(9, str.size() - 9); + + fmt.has_seconds = true; + fmt.subsecond_precision = secfrac.size(); + + while(secfrac.size() < 9) + { + secfrac += '0'; + } + assert(9 <= secfrac.size()); + const auto ms_r = from_string(secfrac.substr(0, 3)); + const auto us_r = from_string(secfrac.substr(3, 3)); + const auto ns_r = from_string(secfrac.substr(6, 3)); + + if(ms_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read milliseconds `" + secfrac.substr(0, 3) + "`", + std::move(src), "here")); + } + if(us_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read microseconds`" + str.substr(3, 3) + "`", + std::move(src), "here")); + } + if(ns_r.is_err()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read nanoseconds`" + str.substr(6, 3) + "`", + std::move(src), "here")); + } + const auto ms = ms_r.unwrap(); + const auto us = us_r.unwrap(); + const auto ns = ns_r.unwrap(); + + return ok(std::make_tuple(local_time(hour, minute, sec, ms, us, ns), std::move(fmt), std::move(reg))); +} + +template +result, error_info> +parse_local_time(location& loc, const context& ctx) +{ + const auto first = loc; + + auto val_fmt_reg = parse_local_time_only(loc, ctx); + if(val_fmt_reg.is_err()) + { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok(basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); +} + +template +result, error_info> +parse_local_datetime(location& loc, const context& ctx) +{ + using char_type = location::char_type; + + const auto first = loc; + + local_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if(date_fmt_reg.is_err()) + { + return err(date_fmt_reg.unwrap_err()); + } + + if(loc.current() == char_type('T')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } + else if(loc.current() == char_type('t')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } + else if(loc.current() == char_type(' ')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } + else + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_local_datetime: " + "expect date-time delimiter `T`, `t` or ` `(space).", + std::move(src), "here")); + } + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if(time_fmt_reg.is_err()) + { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + + region reg(first, loc); + local_datetime val(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); +} + +template +result, error_info> +parse_offset_datetime(location& loc, const context& ctx) +{ + using char_type = location::char_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + offset_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + // date part + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if(date_fmt_reg.is_err()) + { + return err(date_fmt_reg.unwrap_err()); + } + + // ---------------------------------------------------------------------- + // delimiter + + if(loc.current() == char_type('T')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } + else if(loc.current() == char_type('t')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } + else if(loc.current() == char_type(' ')) + { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } + else + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "expect date-time delimiter `T` or ` `(space).", std::move(src), "here" + )); + } + + // ---------------------------------------------------------------------- + // time part + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if(time_fmt_reg.is_err()) + { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + // offset part + + const auto ofs_reg = syntax::time_offset(spec).scan(loc); + if( ! ofs_reg.is_ok()) + { + return err(make_syntax_error("toml::parse_offset_datetime: " + "invalid offset: offset must be like: Z, +01:00, or -10:00.", + syntax::time_offset(spec), loc)); + } + + const auto ofs_str = ofs_reg.as_string(); + + time_offset offset(0, 0); + + assert(ofs_str.size() != 0); + + if(ofs_str.at(0) == char_type('+') || ofs_str.at(0) == char_type('-')) + { + const auto hour_r = from_string(ofs_str.substr(1, 2)); + const auto minute_r = from_string(ofs_str.substr(4, 2)); + if(hour_r.is_err()) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset hour part", std::move(src), "here")); + } + if(minute_r.is_err()) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset minute part", std::move(src), "here")); + } + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if(ofs_str.at(0) == '+') + { + offset = time_offset(hour, minute); + } + else + { + offset = time_offset(-hour, -minute); + } + } + else + { + assert(ofs_str.at(0) == char_type('Z') || ofs_str.at(0) == char_type('z')); + } + + if (offset.hour < -24 || 24 < offset.hour || + offset.minute < -60 || 60 < offset.minute) + { + return err(make_error_info("toml::parse_offset_datetime: " + "too large offset: |hour| <= 24, |minute| <= 60", + source_location(region(first, loc)), "here")); + } + + + // ---------------------------------------------------------------------- + + region reg(first, loc); + offset_datetime val(local_datetime(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())), + offset); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); +} + +/* ============================================================================ + * ___ _ _ + * / __| |_ _ _(_)_ _ __ _ + * \__ \ _| '_| | ' \/ _` | + * |___/\__|_| |_|_||_\__, | + * |___/ + */ + +template +result::string_type, error_info> +parse_utf8_codepoint(const region& reg) +{ + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + // assert(reg.as_lines().size() == 1); // XXX heavy check + + const auto str = reg.as_string(); + assert( ! str.empty()); + assert(str.front() == 'u' || str.front() == 'U' || str.front() == 'x'); + + std::uint_least32_t codepoint; + std::istringstream iss(str.substr(1)); + iss >> std::hex >> codepoint; + + const auto to_char = [](const std::uint_least32_t i) noexcept -> char_type { + const auto uc = static_cast(i & 0xFF); + return cxx::bit_cast(uc); + }; + + string_type character; + if(codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII. + { + character += static_cast(codepoint); + } + else if(codepoint < 0x800) //U+0080 ... U+07FF + { + // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 + character += to_char(0xC0|(codepoint >> 6 )); + character += to_char(0x80|(codepoint & 0x3F)); + } + else if(codepoint < 0x10000) // U+0800...U+FFFF + { + if(0xD800 <= codepoint && codepoint <= 0xDFFF) + { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "[0xD800, 0xDFFF] is not a valid UTF-8", + std::move(src), "here")); + } + assert(codepoint < 0xD800 || 0xDFFF < codepoint); + // 1110yyyy 10yxxxxx 10xxxxxx + character += to_char(0xE0| (codepoint >> 12)); + character += to_char(0x80|((codepoint >> 6 ) & 0x3F)); + character += to_char(0x80|((codepoint ) & 0x3F)); + } + else if(codepoint < 0x110000) // U+010000 ... U+10FFFF + { + // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx + character += to_char(0xF0| (codepoint >> 18)); + character += to_char(0x80|((codepoint >> 12) & 0x3F)); + character += to_char(0x80|((codepoint >> 6 ) & 0x3F)); + character += to_char(0x80|((codepoint ) & 0x3F)); + } + else // out of UTF-8 region + { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "input codepoint is too large.", + std::move(src), "must be in range [0x00, 0x10FFFF]")); + } + return ok(character); +} + +template +result::string_type, error_info> +parse_escape_sequence(location& loc, const context& ctx) +{ + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + const auto& spec = ctx.toml_spec(); + + assert( ! loc.eof()); + assert(loc.current() == '\\'); + loc.advance(); // consume the first backslash + + string_type retval; + + if (loc.current() == '\\') { retval += char_type('\\'); loc.advance(); } + else if(loc.current() == '"') { retval += char_type('\"'); loc.advance(); } + else if(loc.current() == 'b') { retval += char_type('\b'); loc.advance(); } + else if(loc.current() == 'f') { retval += char_type('\f'); loc.advance(); } + else if(loc.current() == 'n') { retval += char_type('\n'); loc.advance(); } + else if(loc.current() == 'r') { retval += char_type('\r'); loc.advance(); } + else if(loc.current() == 't') { retval += char_type('\t'); loc.advance(); } + else if(spec.v1_1_0_add_escape_sequence_e && loc.current() == 'e') + { + retval += char_type('\x1b'); + loc.advance(); + } + else if(spec.v1_1_0_add_escape_sequence_x && loc.current() == 'x') + { + auto scanner = sequence(character('x'), repeat_exact(2, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if( ! reg.is_ok()) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\xhh", + std::move(src), "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if(utf8.is_err()) + { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } + else if(loc.current() == 'u') + { + auto scanner = sequence(character('u'), repeat_exact(4, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if( ! reg.is_ok()) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\uhhhh", + std::move(src), "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if(utf8.is_err()) + { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } + else if(loc.current() == 'U') + { + auto scanner = sequence(character('U'), repeat_exact(8, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if( ! reg.is_ok()) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\Uhhhhhhhh", + std::move(src), "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if(utf8.is_err()) + { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } + else + { + auto src = source_location(region(loc)); + std::string escape_seqs = "allowed escape seqs: \\\\, \\\", \\b, \\f, \\n, \\r, \\t"; + if(spec.v1_1_0_add_escape_sequence_e) + { + escape_seqs += ", \\e"; + } + if(spec.v1_1_0_add_escape_sequence_x) + { + escape_seqs += ", \\xhh"; + } + escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh"; + + return err(make_error_info("toml::parse_escape_sequence: " + "unknown escape sequence.", std::move(src), escape_seqs)); + } + return ok(retval); +} + +template +result, error_info> +parse_ml_basic_string(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_basic; + + auto reg = syntax::ml_basic_string(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_ml_basic_string: " + "invalid string format", + syntax::ml_basic_string(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + // we already checked that it starts with """ and ends with """. + assert(str.substr(0, 3) == "\"\"\""); + str.erase(0, 3); + + assert(str.size() >= 3); + assert(str.substr(str.size()-3, 3) == "\"\"\""); + str.erase(str.size()-3, 3); + + // the first newline just after """ is trimmed + if(str.size() >= 1 && str.at(0) == '\n') + { + str.erase(0, 1); + fmt.start_with_newline = true; + } + else if(str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') + { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val; + { + auto iter = str.cbegin(); + while(iter != str.cend()) + { + if(*iter == '\\') // remove whitespaces around escaped-newline + { + // we assume that the string is not too long to copy + auto loc2 = make_temporary_location(make_string(iter, str.cend())); + if(syntax::escaped_newline(spec).scan(loc2).is_ok()) + { + std::advance(iter, loc2.get_location()); // skip escaped newline and indent + // now iter points non-WS char + assert(iter == str.end() || (*iter != ' ' && *iter != '\t')); + } + else // normal escape seq. + { + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if(esc.is_err()) + { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } + } + else // we already checked the syntax. we don't need to check it again. + { + val += static_cast(*iter); + ++iter; + } + } + } + + return ok(basic_value( + std::move(val), std::move(fmt), {}, std::move(reg) + )); +} + +template +result::string_type, region>, error_info> +parse_basic_string_only(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::basic_string(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_basic_string: " + "invalid string format", + syntax::basic_string(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\"'); + str.pop_back(); + assert(str.at(0) == '\"'); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + string_type val; + + { + auto iter = str.begin(); + while(iter != str.end()) + { + if(*iter == '\\') + { + auto loc2 = make_temporary_location(make_string(iter, str.end())); + + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if(esc.is_err()) + { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } + else + { + val += char_type(*iter); // we already checked the syntax. + ++iter; + } + } + } + return ok(std::make_pair(val, reg)); +} + +template +result, error_info> +parse_basic_string(location& loc, const context& ctx) +{ + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::basic; + + auto val_res = parse_basic_string_only(loc, ctx); + if(val_res.is_err()) + { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first ); + auto reg = std::move(val_res.unwrap().second); + + return ok(basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); +} + +template +result, error_info> +parse_ml_literal_string(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_literal; + + auto reg = syntax::ml_literal_string(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_ml_literal_string: " + "invalid string format", + syntax::ml_literal_string(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.substr(0, 3) == "'''"); + assert(str.substr(str.size()-3, 3) == "'''"); + str.erase(0, 3); + str.erase(str.size()-3, 3); + + // the first newline just after """ is trimmed + if(str.size() >= 1 && str.at(0) == '\n') + { + str.erase(0, 1); + fmt.start_with_newline = true; + } + else if(str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') + { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok(basic_value( + std::move(val), std::move(fmt), {}, std::move(reg) + )); +} + +template +result::string_type, region>, error_info> +parse_literal_string_only(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::literal_string(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_literal_string: " + "invalid string format", + syntax::literal_string(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\''); + str.pop_back(); + assert(str.at(0) == '\''); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok(std::make_pair(std::move(val), std::move(reg))); +} + +template +result, error_info> +parse_literal_string(location& loc, const context& ctx) +{ + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::literal; + + auto val_res = parse_literal_string_only(loc, ctx); + if(val_res.is_err()) + { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first ); + auto reg = std::move(val_res.unwrap().second); + + return ok(basic_value( + std::move(val), std::move(fmt), {}, std::move(reg) + )); +} + +template +result, error_info> +parse_string(location& loc, const context& ctx) +{ + const auto first = loc; + + if( ! loc.eof() && loc.current() == '"') + { + if(literal("\"\"\"").scan(loc).is_ok()) + { + loc = first; + return parse_ml_basic_string(loc, ctx); + } + else + { + loc = first; + return parse_basic_string(loc, ctx); + } + } + else if( ! loc.eof() && loc.current() == '\'') + { + if(literal("'''").scan(loc).is_ok()) + { + loc = first; + return parse_ml_literal_string(loc, ctx); + } + else + { + loc = first; + return parse_literal_string(loc, ctx); + } + } + else + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_string: " + "not a string", std::move(src), "here")); + } +} + +template +result, error_info> +parse_null(location& loc, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + if( ! spec.ext_null_value) + { + return err(make_error_info("toml::parse_null: " + "invalid spec: spec.ext_null_value must be true.", + source_location(region(loc)), "here")); + } + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::null_value(spec).scan(loc); + if( ! reg.is_ok()) + { + return err(make_syntax_error("toml::parse_null: " + "invalid null: null must be lowercase. ", + syntax::null_value(spec), loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + // ---------------------------------------------------------------------- + // no format info for boolean + + return ok(basic_value(detail::none_t{}, std::move(reg))); +} + +/* ============================================================================ + * _ __ + * | |/ /___ _ _ + * | ' +result::key_type, error_info> +parse_simple_key(location& loc, const context& ctx) +{ + using key_type = typename basic_value::key_type; + const auto& spec = ctx.toml_spec(); + + if(loc.current() == '\"') + { + auto str_res = parse_basic_string_only(loc, ctx); + if(str_res.is_ok()) + { + return ok(std::move(str_res.unwrap().first)); + } + else + { + return err(std::move(str_res.unwrap_err())); + } + } + else if(loc.current() == '\'') + { + auto str_res = parse_literal_string_only(loc, ctx); + if(str_res.is_ok()) + { + return ok(std::move(str_res.unwrap().first)); + } + else + { + return err(std::move(str_res.unwrap_err())); + } + } + + // bare key. + + if(const auto bare = syntax::unquoted_key(spec).scan(loc)) + { + return ok(string_conv(bare.as_string())); + } + else + { + std::string postfix; + if(spec.v1_1_0_allow_non_english_in_bare_keys) + { + postfix = "Hint: Not all Unicode characters are allowed as bare key.\n"; + } + else + { + postfix = "Hint: non-ASCII scripts are allowed in toml v1.1.0, but not in v1.0.0.\n"; + } + return err(make_syntax_error("toml::parse_simple_key: " + "invalid key: key must be \"quoted\", 'quoted-literal', or bare key.", + syntax::unquoted_key(spec), loc, postfix)); + } +} + +// dotted key become vector of keys +template +result::key_type>, region>, error_info> +parse_key(location& loc, const context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + using key_type = typename basic_value::key_type; + std::vector keys; + while( ! loc.eof()) + { + auto key = parse_simple_key(loc, ctx); + if( ! key.is_ok()) + { + return err(key.unwrap_err()); + } + keys.push_back(std::move(key.unwrap())); + + auto reg = syntax::dot_sep(spec).scan(loc); + if( ! reg.is_ok()) + { + break; + } + } + if(keys.empty()) + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_key: expected a new key, " + "but got nothing", std::move(src), "reached EOF")); + } + + return ok(std::make_pair(std::move(keys), region(first, loc))); +} + +// ============================================================================ + +// forward-decl to implement parse_array and parse_table +template +result, error_info> +parse_value(location&, context& ctx); + +template +result::key_type>, region>, + basic_value + >, error_info> +parse_key_value_pair(location& loc, context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto key_res = parse_key(loc, ctx); + if(key_res.is_err()) + { + loc = first; + return err(key_res.unwrap_err()); + } + + if( ! syntax::keyval_sep(spec).scan(loc).is_ok()) + { + auto e = make_syntax_error("toml::parse_key_value_pair: " + "invalid key value separator `=`", syntax::keyval_sep(spec), loc); + loc = first; + return err(std::move(e)); + } + + auto v_res = parse_value(loc, ctx); + if(v_res.is_err()) + { + // loc = first; + return err(v_res.unwrap_err()); + } + return ok(std::make_pair(std::move(key_res.unwrap()), std::move(v_res.unwrap()))); +} + +/* ============================================================================ + * __ _ _ _ _ _ __ _ _ _ + * / _` | '_| '_/ _` | || | + * \__,_|_| |_| \__,_|\_, | + * |__/ + */ + +// array(and multiline inline table with `{` and `}`) has the following format. +// `[` +// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` +// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` +// ... +// (ws|newline|comment-line)? (value) (ws|newline|comment-line)? (`,`)? +// (ws|newline|comment-line)? `]` +// it skips (ws|newline|comment-line) and returns the token. +template +struct multiline_spacer +{ + using comment_type = typename TC::comment_type; + bool newline_found; + indent_char indent_type; + std::int32_t indent; + comment_type comments; +}; +template +std::ostream& operator<<(std::ostream& os, const multiline_spacer& sp) +{ + os << "{newline=" << sp.newline_found << ", "; + os << "indent_type=" << sp.indent_type << ", "; + os << "indent=" << sp.indent << ", "; + os << "comments=" << sp.comments.size() << "}"; + return os; +} + +template +cxx::optional> +skip_multiline_spacer(location& loc, context& ctx, const bool newline_found = false) +{ + const auto& spec = ctx.toml_spec(); + + multiline_spacer spacer; + spacer.newline_found = newline_found; + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer.comments.clear(); + + bool spacer_found = false; + while( ! loc.eof()) + { + if(auto comm = sequence(syntax::comment(spec), syntax::newline(spec)).scan(loc)) + { + spacer.newline_found = true; + auto comment = comm.as_string(); + if( ! comment.empty() && comment.back() == '\n') + { + comment.pop_back(); + if (!comment.empty() && comment.back() == '\r') + { + comment.pop_back(); + } + } + + spacer.comments.push_back(std::move(comment)); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } + else if(auto nl = syntax::newline(spec).scan(loc)) + { + spacer.newline_found = true; + spacer.comments.clear(); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } + else if(auto sp = repeat_at_least(1, character(cxx::bit_cast(' '))).scan(loc)) + { + spacer.indent_type = indent_char::space; + spacer.indent = static_cast(sp.length()); + spacer_found = true; + } + else if(auto tabs = repeat_at_least(1, character(cxx::bit_cast('\t'))).scan(loc)) + { + spacer.indent_type = indent_char::tab; + spacer.indent = static_cast(tabs.length()); + spacer_found = true; + } + else + { + break; // done + } + } + if( ! spacer_found) + { + return cxx::make_nullopt(); + } + return spacer; +} + +// not an [[array.of.tables]]. It parses ["this", "type"] +template +result, error_info> +parse_array(location& loc, context& ctx) +{ + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + + if(loc.eof() || loc.current() != '[') + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_array: " + "The next token is not an array", std::move(src), "here")); + } + loc.advance(); + + typename basic_value::array_type val; + + array_format_info fmt; + fmt.fmt = array_format::oneline; + fmt.indent_type = indent_char::none; + + auto spacer = skip_multiline_spacer(loc, ctx); + if(spacer.has_value() && spacer.value().newline_found) + { + fmt.fmt = array_format::multiline; + } + + bool comma_found = true; + while( ! loc.eof()) + { + if(loc.current() == location::char_type(']')) + { + if(spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) + { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + break; + } + + if( ! comma_found) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_array: " + "expected value-separator `,` or closing `]`", + std::move(src), "here")); + } + + if(spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) + { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + if(auto elem_res = parse_value(loc, ctx)) + { + auto elem = std::move(elem_res.unwrap()); + + if(spacer.has_value()) // copy previous comments to value + { + elem.comments() = std::move(spacer.value().comments); + } + + // parse spaces between a value and a comma + // array = [ + // 42 , # the answer + // ^^^^ + // 3.14 # pi + // , 2.71 ^^^^ + // ^^ + spacer = skip_multiline_spacer(loc, ctx); + if(spacer.has_value()) + { + for(std::size_t i=0; i( + std::move(val), std::move(fmt), {}, region(first, loc) + )); +} + +/* ============================================================================ + * _ _ _ _ _ _ + * (_)_ _ | (_)_ _ ___ | |_ __ _| |__| |___ + * | | ' \| | | ' \/ -_) | _/ _` | '_ \ / -_) + * |_|_||_|_|_|_||_\___| \__\__,_|_.__/_\___| + */ + +// ---------------------------------------------------------------------------- +// insert_value is the most complicated part of the toml spec. +// +// To parse a toml file correctly, we sometimes need to check an exising value +// is appendable or not. +// +// For example while parsing an inline array of tables, +// +// ```toml +// aot = [ +// {a = "foo"}, +// {a = "bar", b = "baz"}, +// ] +// ``` +// +// this `aot` is appendable until parser reaches to `]`. After that, it becomes +// non-appendable. +// +// On the other hand, a normal array of tables, such as +// +// ```toml +// [[aot]] +// a = "foo" +// +// [[aot]] +// a = "bar" +// b = "baz" +// ``` +// This `[[aot]]` is appendable until the parser reaches to the EOF. +// +// +// It becomes a bit more difficult in case of dotted keys. +// In TOML, it is allowed to append a key-value pair to a table that is +// *implicitly* defined by a subtable definitino. +// +// ```toml +// [x.y.z] +// w = 123 +// +// [x] +// a = "foo" # OK. x is defined implicitly by `[x.y.z]`. +// ``` +// +// But if the table is defined by a dotted keys, it is not appendable. +// +// ```toml +// [x] +// y.z.w = 123 +// +// [x.y] +// # ERROR. x.y is already defined by a dotted table in the previous table. +// ``` +// +// Also, reopening a table using dotted keys is invalid. +// +// ```toml +// [x.y.z] +// w = 123 +// +// [x] +// y.z.v = 42 # ERROR. [x.y.z] is already defined. +// ``` +// +// +// ```toml +// [a] +// b.c = "foo" +// b.d = "bar" +// ``` +// +// +// ```toml +// a.b = "foo" +// [a] +// c = "bar" # ERROR +// ``` +// +// In summary, +// - a table must be defined only once. +// - assignment to an exising table is possible only when: +// - defining a subtable [x.y] to an existing table [x]. +// - defining supertable [x] explicitly after [x.y]. +// - adding dotted keys in the same table. + +enum class inserting_value_kind : std::uint8_t +{ + std_table, // insert [standard.table] + array_table, // insert [[array.of.tables]] + dotted_keys // insert a.b.c = "this" +}; + +template +result*, error_info> +insert_value(const inserting_value_kind kind, + typename basic_value::table_type* current_table_ptr, + const std::vector::key_type>& keys, region key_reg, + basic_value val) +{ + using value_type = basic_value; + using array_type = typename basic_value::array_type; + using table_type = typename basic_value::table_type; + + auto key_loc = source_location(key_reg); + + assert( ! keys.empty()); + + // dotted key can insert to dotted key tables defined at the same level. + // dotted key can NOT reopen a table even if it is implcitly-defined one. + // + // [x.y.z] # define x and x.y implicitly. + // a = 42 + // + // [x] # reopening implcitly defined table + // r.s.t = 3.14 # VALID r and r.s are new tables. + // r.s.u = 2.71 # VALID r and r.s are dotted-key tables. valid. + // + // y.z.b = "foo" # INVALID x.y.z are multiline table, not a dotted key. + // y.c = "bar" # INVALID x.y is implicit multiline table, not a dotted key. + + // a table cannot reopen dotted-key tables. + // + // [t1] + // t2.t3.v = 0 + // [t1.t2] # INVALID t1.t2 is defined as a dotted-key table. + + for(std::size_t i=0; i{}, key_reg)); + + assert(current_table.at(key).is_table()); + current_table_ptr = std::addressof(current_table.at(key).as_table()); + } + else if (found->second.is_table()) + { + const auto fmt = found->second.as_table_fmt().fmt; + if(fmt == table_format::oneline || fmt == table_format::multiline_oneline) + { + // foo = {bar = "baz"} or foo = { \n bar = "baz" \n } + return err(make_error_info("toml::insert_value: " + "failed to insert a value: inline table is immutable", + key_loc, "inserting this", + found->second.location(), "to this table")); + } + // dotted key cannot reopen a table. + if(kind ==inserting_value_kind::dotted_keys && fmt != table_format::dotted) + { + return err(make_error_info("toml::insert_value: " + "reopening a table using dotted keys", + key_loc, "dotted key cannot reopen a table", + found->second.location(), "this table is already closed")); + } + assert(found->second.is_table()); + current_table_ptr = std::addressof(found->second.as_table()); + } + else if(found->second.is_array_of_tables()) + { + // aot = [{this = "type", of = "aot"}] # cannot be reopened + if(found->second.as_array_fmt().fmt != array_format::array_of_tables) + { + return err(make_error_info("toml::insert_value:" + "inline array of tables are immutable", + key_loc, "inserting this", + found->second.location(), "inline array of tables")); + } + // appending to [[aot]] + + if(kind == inserting_value_kind::dotted_keys) + { + // [[array.of.tables]] + // [array.of] # reopening supertable is okay + // tables.x = "foo" # appending `x` to the first table + return err(make_error_info("toml::insert_value:" + "dotted key cannot reopen an array-of-tables", + key_loc, "inserting this", + found->second.location(), "to this array-of-tables.")); + } + + // insert_value_by_dotkeys::std_table + // [[array.of.tables]] + // [array.of.tables.subtable] # appending to the last aot + // + // insert_value_by_dotkeys::array_table + // [[array.of.tables]] + // [[array.of.tables.subtable]] # appending to the last aot + auto& current_array_table = found->second.as_array().back(); + + assert(current_array_table.is_table()); + current_table_ptr = std::addressof(current_array_table.as_table()); + } + else + { + return err(make_error_info("toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, "while inserting this", + found->second.location(), "non-table value already exists")); + } + } + else // this is the last key. insert a new value. + { + switch(kind) + { + case inserting_value_kind::dotted_keys: + { + if(current_table.find(key) != current_table.end()) + { + return err(make_error_info("toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, "inserting this", + current_table.at(key).location(), "but value already exists")); + } + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } + case inserting_value_kind::std_table: + { + // defining a new table or reopening supertable + auto found = current_table.find(key); + if(found == current_table.end()) // define a new aot + { + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } + else // the table is already defined, reopen it + { + // assigning a [std.table]. it must be an implicit table. + auto& target = found->second; + if( ! target.is_table() || // could be an array-of-tables + target.as_table_fmt().fmt != table_format::implicit) + { + return err(make_error_info("toml::insert_value: " + "failed to insert a table, table already defined", + key_loc, "inserting this", + target.location(), "this table is explicitly defined")); + } + + // merge table + for(const auto& kv : val.as_table()) + { + if(target.contains(kv.first)) + { + // [x.y.z] + // w = "foo" + // [x] + // y = "bar" + return err(make_error_info("toml::insert_value: " + "failed to insert a table, table keys conflict to each other", + key_loc, "inserting this table", + kv.second.location(), "having this value", + target.at(kv.first).location(), "already defined here")); + } + else + { + target[kv.first] = kv.second; + } + } + // change implicit -> explicit + target.as_table_fmt().fmt = table_format::multiline; + // change definition region + change_region_of_value(target, val); + + return ok(std::addressof(current_table.at(key))); + } + } + case inserting_value_kind::array_table: + { + auto found = current_table.find(key); + if(found == current_table.end()) // define a new aot + { + array_format_info fmt; + fmt.fmt = array_format::array_of_tables; + fmt.indent_type = indent_char::none; + + current_table.emplace(key, value_type( + array_type{ std::move(val) }, std::move(fmt), + std::vector{}, std::move(key_reg) + )); + + assert( ! current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } + else // the array is already defined, append to it + { + if( ! found->second.is_array_of_tables()) + { + return err(make_error_info("toml::insert_value: " + "failed to insert an array of tables, value already exists", + key_loc, "while inserting this", + found->second.location(), "non-table value already exists")); + } + if(found->second.as_array_fmt().fmt != array_format::array_of_tables) + { + return err(make_error_info("toml::insert_value: " + "failed to insert a table, inline array of tables is immutable", + key_loc, "while inserting this", + found->second.location(), "this is inline array-of-tables")); + } + found->second.as_array().push_back(std::move(val)); + assert( ! current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } + } + default: {assert(false);} + } + } + } + return err(make_error_info("toml::insert_key: no keys found", + std::move(key_loc), "here")); +} + +// ---------------------------------------------------------------------------- + +template +result, error_info> +parse_inline_table(location& loc, context& ctx) +{ + using table_type = typename basic_value::table_type; + + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if(loc.eof() || loc.current() != '{') + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "The next token is not an inline table", std::move(src), "here")); + } + loc.advance(); + + table_type table; + table_format_info fmt; + fmt.fmt = table_format::oneline; + fmt.indent_type = indent_char::none; + + cxx::optional> spacer(cxx::make_nullopt()); + + if(spec.v1_1_0_allow_newlines_in_inline_tables) + { + spacer = skip_multiline_spacer(loc, ctx); + if(spacer.has_value() && spacer.value().newline_found) + { + fmt.fmt = table_format::multiline_oneline; + } + } + else + { + skip_whitespace(loc, ctx); + } + + bool still_empty = true; + bool comma_found = false; + while( ! loc.eof()) + { + // closing! + if(loc.current() == '}') + { + if(comma_found && ! spec.v1_1_0_allow_trailing_comma_in_inline_tables) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: trailing " + "comma is not allowed in TOML-v1.0.0)", std::move(src), "here")); + } + + if(spec.v1_1_0_allow_newlines_in_inline_tables) + { + if(spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) + { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + } + break; + } + + // if we already found a value and didn't found `,` nor `}`, error. + if( ! comma_found && ! still_empty) + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "expected value-separator `,` or closing `}`", + std::move(src), "here")); + } + + // parse indent. + if(spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) + { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + still_empty = false; // parsing a value... + if(auto kv_res = parse_key_value_pair(loc, ctx)) + { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table), keys, std::move(key_reg), std::move(val)); + if(ins_res.is_err()) + { + ctx.report_error(std::move(ins_res.unwrap_err())); + // we need to skip until the next value (or end of the table) + // because we don't have valid kv pair. + while( ! loc.eof()) + { + const auto c = loc.current(); + if(c == ',' || c == '\n' || c == '}') + { + comma_found = (c == ','); + break; + } + loc.advance(); + } + continue; + } + + // if comment line follows immediately(without newline) after `,`, then + // the comment is for the elem. we need to check if comment follows `,`. + // + // (key) = (val) (ws|newline|comment-line)? `,` (ws)? (comment)? + + if(spec.v1_1_0_allow_newlines_in_inline_tables) + { + if(spacer.has_value()) // copy previous comments to value + { + for(std::size_t i=0; icomments().push_back(spacer.value().comments.at(i)); + } + } + spacer = skip_multiline_spacer(loc, ctx); + if(spacer.has_value()) + { + for(std::size_t i=0; icomments().push_back(spacer.value().comments.at(i)); + } + if(spacer.value().newline_found) + { + fmt.fmt = table_format::multiline_oneline; + if(spacer.value().indent_type != indent_char::none) + { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + } + } + } + else + { + skip_whitespace(loc, ctx); + } + + comma_found = character(',').scan(loc).is_ok(); + + if(spec.v1_1_0_allow_newlines_in_inline_tables) + { + auto com_res = parse_comment_line(loc, ctx); + if(com_res.is_err()) + { + ctx.report_error(com_res.unwrap_err()); + } + const bool comment_found = com_res.is_ok() && com_res.unwrap().has_value(); + if(comment_found) + { + fmt.fmt = table_format::multiline_oneline; + ins_res.unwrap()->comments().push_back(com_res.unwrap().value()); + } + if(comma_found) + { + spacer = skip_multiline_spacer(loc, ctx, comment_found); + if(spacer.has_value() && spacer.value().newline_found) + { + fmt.fmt = table_format::multiline_oneline; + } + } + } + else + { + skip_whitespace(loc, ctx); + } + } + else + { + ctx.report_error(std::move(kv_res.unwrap_err())); + while( ! loc.eof()) + { + if(loc.current() == '}') + { + break; + } + if( ! spec.v1_1_0_allow_newlines_in_inline_tables && loc.current() == '\n') + { + break; + } + loc.advance(); + } + break; + } + } + + if(loc.current() != '}') + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "missing closing bracket `}`", + std::move(src), "expected `}`, reached line end")); + } + else + { + loc.advance(); // skip } + } + + // any error reported from this function + if(num_errors < ctx.errors().size()) + { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + + basic_value retval( + std::move(table), std::move(fmt), {}, region(first, loc)); + + return ok(std::move(retval)); +} + +/* ============================================================================ + * _ + * __ ____ _| |_ _ ___ + * \ V / _` | | || / -_) + * \_/\__,_|_|\_,_\___| + */ + +template +result +guess_number_type(const location& first, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + location loc = first; + + if(syntax::offset_datetime(spec).scan(loc).is_ok()) + { + return ok(value_t::offset_datetime); + } + loc = first; + + if(syntax::local_datetime(spec).scan(loc).is_ok()) + { + const auto curr = loc.current(); + // if offset_datetime contains bad offset, it syntax::offset_datetime + // fails to scan it. + if(curr == '+' || curr == '-') + { + return err(make_syntax_error("bad offset: must be [+-]HH:MM or Z", + syntax::time_offset(spec), loc, std::string( + "Hint: valid : +09:00, -05:30\n" + "Hint: invalid: +9:00, -5:30\n"))); + } + return ok(value_t::local_datetime); + } + loc = first; + + if(syntax::local_date(spec).scan(loc).is_ok()) + { + // bad time may appear after this. + + if( ! loc.eof()) + { + const auto c = loc.current(); + if(c == 'T' || c == 't') + { + loc.advance(); + + return err(make_syntax_error("bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), loc, std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + if(c == ' ') + { + // A space is allowed as a delimiter between local time. + // But there is a case where bad time follows a space. + // - invalid: 2019-06-16 7:00:00 + // - valid : 2019-06-16 07:00:00 + loc.advance(); + if( ! loc.eof() && ('0' <= loc.current() && loc.current() <= '9')) + { + return err(make_syntax_error("bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), loc, std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + if('0' <= c && c <= '9') + { + return err(make_syntax_error("bad datetime: missing T or space", + character_either{'T', 't', ' '}, loc, std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + return ok(value_t::local_date); + } + loc = first; + + if(syntax::local_time(spec).scan(loc).is_ok()) + { + return ok(value_t::local_time); + } + loc = first; + + if(syntax::floating(spec).scan(loc).is_ok()) + { + if( ! loc.eof() && loc.current() == '_') + { + if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) + { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + + if(spec.ext_hex_float) + { + if(syntax::hex_floating(spec).scan(loc).is_ok()) + { + if( ! loc.eof() && loc.current() == '_') + { + if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) + { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + } + + if(auto int_reg = syntax::integer(spec).scan(loc)) + { + if( ! loc.eof()) + { + const auto c = loc.current(); + if(c == '_') + { + if(spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) + { + return ok(value_t::integer); + } + + if(int_reg.length() <= 2 && (int_reg.as_string() == "0" || + int_reg.as_string() == "-0" || int_reg.as_string() == "+0")) + { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad integer: leading zero is not allowed in decimal int", + std::move(src), "leading zero", + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } + else + { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad integer: `_` must be surrounded by digits", + std::move(src), "invalid underscore", + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } + } + if('0' <= c && c <= '9') + { + if(loc.current() == '0') + { + loc.retrace(); + return err(make_error_info( + "bad integer: leading zero", + source_location(region(loc)), "leading zero is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n") + )); + } + else // invalid digits, especially in oct/bin ints. + { + return err(make_error_info( + "bad integer: invalid digit after an integer", + source_location(region(loc)), "this digit is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n") + )); + } + } + if(c == ':' || c == '-') + { + auto src = source_location(region(loc)); + return err(make_error_info("bad datetime: invalid format", + std::move(src), "here", + std::string("Hint: valid : 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z\n" + "Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30") + )); + } + if(c == '.' || c == 'e' || c == 'E') + { + auto src = source_location(region(loc)); + return err(make_error_info("bad float: invalid format", + std::move(src), "here", std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"))); + } + } + return ok(value_t::integer); + } + if( ! loc.eof() && loc.current() == '.') + { + auto src = source_location(region(loc)); + return err(make_error_info("bad float: integer part is required before decimal point", + std::move(src), "missing integer part", std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n") + )); + } + if( ! loc.eof() && loc.current() == '_') + { + auto src = source_location(region(loc)); + return err(make_error_info("bad number: `_` must be surrounded by digits", + std::move(src), "digits required before `_`", std::string( + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n") + )); + } + + auto src = source_location(region(loc)); + return err(make_error_info("bad format: unknown value appeared", + std::move(src), "here")); +} + +template +result +guess_value_type(const location& loc, const context& ctx) +{ + const auto& sp = ctx.toml_spec(); + location inner(loc); + + switch(loc.current()) + { + case '"' : {return ok(value_t::string); } + case '\'': {return ok(value_t::string); } + case '[' : {return ok(value_t::array); } + case '{' : {return ok(value_t::table); } + case 't' : + { + return ok(value_t::boolean); + } + case 'f' : + { + return ok(value_t::boolean); + } + case 'T' : // invalid boolean. + { + return err(make_syntax_error("toml::parse_value: " + "`true` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), inner)); + } + case 'F' : + { + return err(make_syntax_error("toml::parse_value: " + "`false` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), inner)); + } + case 'i' : // inf or string without quotes(syntax error). + { + if(literal("inf").scan(inner).is_ok()) + { + return ok(value_t::floating); + } + else + { + return err(make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + } + case 'I' : // Inf or string without quotes(syntax error). + { + return err(make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + case 'n' : // nan or null-extension + { + if(sp.ext_null_value) + { + if(literal("nan").scan(inner).is_ok()) + { + return ok(value_t::floating); + } + else if(literal("null").scan(inner).is_ok()) + { + return ok(value_t::empty); + } + else + { + return err(make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + } + else // must be nan. + { + if(literal("nan").scan(inner).is_ok()) + { + return ok(value_t::floating); + } + else + { + return err(make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + } + } + case 'N' : // nan or null-extension + { + if(sp.ext_null_value) + { + return err(make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + else + { + return err(make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), inner)); + } + } + default : + { + return guess_number_type(loc, ctx); + } + } +} + +template +result, error_info> +parse_value(location& loc, context& ctx) +{ + const auto ty_res = guess_value_type(loc, ctx); + if(ty_res.is_err()) + { + return err(ty_res.unwrap_err()); + } + + switch(ty_res.unwrap()) + { + case value_t::empty: + { + if(ctx.toml_spec().ext_null_value) + { + return parse_null(loc, ctx); + } + else + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_value: unknown value appeared", + std::move(src), "here")); + } + } + case value_t::boolean : {return parse_boolean (loc, ctx);} + case value_t::integer : {return parse_integer (loc, ctx);} + case value_t::floating : {return parse_floating (loc, ctx);} + case value_t::string : {return parse_string (loc, ctx);} + case value_t::offset_datetime: {return parse_offset_datetime(loc, ctx);} + case value_t::local_datetime : {return parse_local_datetime (loc, ctx);} + case value_t::local_date : {return parse_local_date (loc, ctx);} + case value_t::local_time : {return parse_local_time (loc, ctx);} + case value_t::array : {return parse_array (loc, ctx);} + case value_t::table : {return parse_inline_table (loc, ctx);} + default: + { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_value: unknown value appeared", + std::move(src), "here")); + } + } +} + +/* ============================================================================ + * _____ _ _ + * |_ _|_ _| |__| |___ + * | |/ _` | '_ \ / -_) + * |_|\__,_|_.__/_\___| + */ + +template +result::key_type>, region>, error_info> +parse_table_key(location& loc, context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::std_table(spec).scan(loc); + if(!reg.is_ok()) + { + return err(make_syntax_error("toml::parse_table_key: invalid table key", + syntax::std_table(spec), loc)); + } + + loc = first; + loc.advance(); // skip [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if(keys_res.is_err()) + { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); +} + +template +result::key_type>, region>, error_info> +parse_array_table_key(location& loc, context& ctx) +{ + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::array_table(spec).scan(loc); + if(!reg.is_ok()) + { + return err(make_syntax_error("toml::parse_array_table_key: invalid array-of-tables key", + syntax::array_table(spec), loc)); + } + + loc = first; + loc.advance(); // [ + loc.advance(); // [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if(keys_res.is_err()) + { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); +} + +// called after reading [table.keys] and comments around it. +// Since table may already contain a subtable ([x.y.z] can be defined before [x]), +// the table that is being parsed is passed as an argument. +template +result +parse_table(location& loc, context& ctx, basic_value& table) +{ + assert(table.is_table()); + + const auto num_errors = ctx.errors().size(); + const auto& spec = ctx.toml_spec(); + + // clear indent info + table.as_table_fmt().indent_type = indent_char::none; + + bool newline_found = true; + while( ! loc.eof()) + { + const auto start = loc; + + auto sp = skip_multiline_spacer(loc, ctx, newline_found); + + // if reached to EOF, the table ends here. return. + if(loc.eof()) + { + break; + } + // if next table is comming, return. + if(sequence(syntax::ws(spec), character('[')).scan(loc).is_ok()) + { + loc = start; + break; + } + // otherwise, it should be a key-value pair. + newline_found = newline_found || (sp.has_value() && sp.value().newline_found); + if( ! newline_found) + { + return err(make_error_info("toml::parse_table: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), "here")); + } + if(sp.has_value() && sp.value().indent_type != indent_char::none) + { + table.as_table_fmt().indent_type = sp.value().indent_type; + table.as_table_fmt().body_indent = sp.value().indent; + } + + newline_found = false; // reset + if(auto kv_res = parse_key_value_pair(loc, ctx)) + { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + if(sp.has_value()) + { + for(const auto& com : sp.value().comments) + { + val.comments().push_back(com); + } + } + + if(auto com_res = parse_comment_line(loc, ctx)) + { + if(auto com_opt = com_res.unwrap()) + { + val.comments().push_back(com_opt.value()); + newline_found = true; // comment includes newline at the end + } + } + else + { + ctx.report_error(std::move(com_res.unwrap_err())); + } + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table.as_table()), + keys, std::move(key_reg), std::move(val)); + if(ins_res.is_err()) + { + ctx.report_error(std::move(ins_res.unwrap_err())); + } + } + else + { + ctx.report_error(std::move(kv_res.unwrap_err())); + skip_key_value_pair(loc, ctx); + } + } + + if(num_errors < ctx.errors().size()) + { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + return ok(); +} + +template +result, std::vector> +parse_file(location& loc, context& ctx) +{ + using value_type = basic_value; + using table_type = typename value_type::table_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if(loc.eof()) + { + return ok(value_type(table_type(), table_format_info{}, {}, region(loc))); + } + + value_type root(table_type(), table_format_info{}, {}, region(loc)); + root.as_table_fmt().fmt = table_format::multiline; + root.as_table_fmt().indent_type = indent_char::none; + + // parse top comment. + // + // ```toml + // # this is a comment for the top-level table. + // + // key = "the first value" + // ``` + // + // ```toml + // # this is a comment for "the first value". + // key = "the first value" + // ``` + while( ! loc.eof()) + { + if(auto com_res = parse_comment_line(loc, ctx)) + { + if(auto com_opt = com_res.unwrap()) + { + root.comments().push_back(std::move(com_opt.value())); + } + else // no comment found. + { + // if it is not an empty line, clear the root comment. + if( ! sequence(syntax::ws(spec), syntax::newline(spec)).scan(loc).is_ok()) + { + loc = first; + root.comments().clear(); + } + break; + } + } + else + { + ctx.report_error(std::move(com_res.unwrap_err())); + skip_comment_block(loc, ctx); + } + } + + // parse root table + { + const auto res = parse_table(loc, ctx, root); + if(res.is_err()) + { + ctx.report_error(std::move(res.unwrap_err())); + skip_until_next_table(loc, ctx); + } + } + + // parse tables + + while( ! loc.eof()) + { + auto sp = skip_multiline_spacer(loc, ctx, /*newline_found=*/true); + + if(auto key_res = parse_array_table_key(loc, ctx)) + { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if(sp.has_value()) + { + for(std::size_t i=0; i(table_type()); + auto res = parse_table(loc, ctx, tmp); + if(res.is_err()) + { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if(tab_res.is_err()) + { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + + // parse_table first clears `indent_type`. + // to keep header indent info, we must store it later. + if(sp.has_value() && sp.value().indent_type != indent_char::none) + { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + if(auto key_res = parse_table_key(loc, ctx)) + { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if(sp.has_value()) + { + for(std::size_t i=0; i(table_type()); + auto res = parse_table(loc, ctx, tmp); + if(res.is_err()) + { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if(tab_res.is_err()) + { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + if(sp.has_value() && sp.value().indent_type != indent_char::none) + { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + + // does not match array_table nor std_table. report an error. + const auto keytop = loc; + const auto maybe_array_of_tables = literal("[[").scan(loc).is_ok(); + loc = keytop; + + if(maybe_array_of_tables) + { + ctx.report_error(make_syntax_error("toml::parse_file: invalid array-table key", + syntax::array_table(spec), loc)); + } + else + { + ctx.report_error(make_syntax_error("toml::parse_file: invalid table key", + syntax::std_table(spec), loc)); + } + skip_until_next_table(loc, ctx); + } + + if( ! ctx.errors().empty()) + { + return err(std::move(ctx.errors())); + } + return ok(std::move(root)); +} + +template +result, std::vector> +parse_impl(std::vector cs, std::string fname, const spec& s) +{ + using value_type = basic_value; + using table_type = typename value_type::table_type; + + // an empty file is a valid toml file. + if(cs.empty()) + { + auto src = std::make_shared>(std::move(cs)); + location loc(std::move(src), std::move(fname)); + return ok(value_type(table_type(), table_format_info{}, std::vector{}, region(loc))); + } + + // to simplify parser, add newline at the end if there is no LF. + // But, if it has raw CR, the file is invalid (in TOML, CR is not a valid + // newline char). if it ends with CR, do not add LF and report it. + if(cs.back() != '\n' && cs.back() != '\r') + { + cs.push_back('\n'); + } + + auto src = std::make_shared>(std::move(cs)); + + location loc(std::move(src), std::move(fname)); + + // skip BOM if found + if(loc.source()->size() >= 3) + { + auto first = loc.get_location(); + + const auto c0 = loc.current(); loc.advance(); + const auto c1 = loc.current(); loc.advance(); + const auto c2 = loc.current(); loc.advance(); + + const auto bom_found = (c0 == 0xEF) && (c1 == 0xBB) && (c2 == 0xBF); + if( ! bom_found) + { + loc.set_location(first); + } + } + + context ctx(s); + + return parse_file(loc, ctx); +} + +} // detail + +// ----------------------------------------------------------------------------- +// parse(byte array) + +template +result, std::vector> +try_parse(std::vector content, std::string filename, + spec s = spec::default_version()) +{ + return detail::parse_impl(std::move(content), std::move(filename), std::move(s)); +} +template +basic_value +parse(std::vector content, std::string filename, + spec s = spec::default_version()) +{ + auto res = try_parse(std::move(content), std::move(filename), std::move(s)); + if(res.is_ok()) + { + return res.unwrap(); + } + else + { + std::string msg; + for(const auto& err : res.unwrap_err()) + { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } +} + +// ----------------------------------------------------------------------------- +// parse(istream) + +template +result, std::vector> +try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::default_version()) +{ + const auto beg = is.tellg(); + is.seekg(0, std::ios::end); + const auto end = is.tellg(); + const auto fsize = end - beg; + is.seekg(beg); + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize), '\0'); + is.read(reinterpret_cast(letters.data()), static_cast(fsize)); + + return detail::parse_impl(std::move(letters), std::move(fname), std::move(s)); +} + +template +basic_value parse(std::istream& is, std::string fname = "unknown file", spec s = spec::default_version()) +{ + auto res = try_parse(is, std::move(fname), std::move(s)); + if(res.is_ok()) + { + return res.unwrap(); + } + else + { + std::string msg; + for(const auto& err : res.unwrap_err()) + { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } +} + +// ----------------------------------------------------------------------------- +// parse(filename) + +template +result, std::vector> +try_parse(std::string fname, spec s = spec::default_version()) +{ + std::ifstream ifs(fname, std::ios_base::binary); + if(!ifs.good()) + { + std::vector e; + e.push_back(error_info("toml::parse: Error opening file \"" + fname + "\"", {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, std::move(fname), std::move(s)); +} + +template +basic_value parse(std::string fname, spec s = spec::default_version()) +{ + std::ifstream ifs(fname, std::ios_base::binary); + if(!ifs.good()) + { + throw file_io_error("toml::parse: error opening file", fname); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, std::move(fname), std::move(s)); +} + +template +result, std::vector> +try_parse(const char (&fname)[N], spec s = spec::default_version()) +{ + return try_parse(std::string(fname), std::move(s)); +} + +template +basic_value parse(const char (&fname)[N], spec s = spec::default_version()) +{ + return parse(std::string(fname), std::move(s)); +} + +// ---------------------------------------------------------------------------- +// parse_str + +template +result, std::vector> +try_parse_str(std::string content, spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) +{ + std::istringstream iss(std::move(content)); + std::string name("internal string" + cxx::to_string(loc)); + return try_parse(iss, std::move(name), std::move(s)); +} + +template +basic_value parse_str(std::string content, spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) +{ + auto res = try_parse_str(std::move(content), std::move(s), std::move(loc)); + if(res.is_ok()) + { + return res.unwrap(); + } + else + { + std::string msg; + for(const auto& err : res.unwrap_err()) + { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } +} + +// ---------------------------------------------------------------------------- +// filesystem + +#if defined(TOML11_HAS_FILESYSTEM) + +template +cxx::enable_if_t::value, + result, std::vector>> +try_parse(const FSPATH& fpath, spec s = spec::default_version()) +{ + std::ifstream ifs(fpath, std::ios_base::binary); + if(!ifs.good()) + { + std::vector e; + e.push_back(error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, fpath.string(), std::move(s)); +} + +template +cxx::enable_if_t::value, + basic_value> +parse(const FSPATH& fpath, spec s = spec::default_version()) +{ + std::ifstream ifs(fpath, std::ios_base::binary); + if(!ifs.good()) + { + throw file_io_error("toml::parse: error opening file", fpath.string()); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, fpath.string(), std::move(s)); +} +#endif + +// ----------------------------------------------------------------------------- +// FILE* + +template +result, std::vector> +try_parse(FILE* fp, std::string filename, spec s = spec::default_version()) +{ + const long beg = std::ftell(fp); + if (beg == -1L) + { + return err(std::vector{error_info( + std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), {} + )}); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) + { + return err(std::vector{error_info( + std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), {} + )}); + } + + const long end = std::ftell(fp); + if (end == -1L) + { + return err(std::vector{error_info( + std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), {} + )}); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) + { + return err(std::vector{error_info( + std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), {} + )}); + + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize)); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != static_cast(fsize)) + { + return err(std::vector{error_info( + std::string("File size changed: \"") + filename + + std::string("\" make sure that FILE* is in binary mode " + "to avoid LF <-> CRLF conversion"), {} + )}); + } + + return detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); +} + +template +basic_value +parse(FILE* fp, std::string filename, spec s = spec::default_version()) +{ + const long beg = std::ftell(fp); + if (beg == -1L) + { + throw file_io_error(errno, "Failed to access", filename); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) + { + throw file_io_error(errno, "Failed to seek", filename); + } + + const long end = std::ftell(fp); + if (end == -1L) + { + throw file_io_error(errno, "Failed to access", filename); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) + { + throw file_io_error(errno, "Failed to seek", filename); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize)); + const auto actual = std::fread(letters.data(), sizeof(char), static_cast(fsize), fp); + if(actual != static_cast(fsize)) + { + throw file_io_error(errno, "File size changed; make sure that " + "FILE* is in binary mode to avoid LF <-> CRLF conversion", filename); + } + + auto res = detail::parse_impl(std::move(letters), std::move(filename), std::move(s)); + if(res.is_ok()) + { + return res.unwrap(); + } + else + { + std::string msg; + for(const auto& err : res.unwrap_err()) + { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } +} + +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml +{ +struct type_config; +struct ordered_type_config; + +extern template result, std::vector> try_parse(std::vector, std::string, spec); +extern template result, std::vector> try_parse(std::istream&, std::string, spec); +extern template result, std::vector> try_parse(std::string, spec); +extern template result, std::vector> try_parse(FILE*, std::string, spec); +extern template result, std::vector> try_parse_str(std::string, spec, cxx::source_location); + +extern template basic_value parse(std::vector, std::string, spec); +extern template basic_value parse(std::istream&, std::string, spec); +extern template basic_value parse(std::string, spec); +extern template basic_value parse(FILE*, std::string, spec); +extern template basic_value parse_str(std::string, spec, cxx::source_location); + +extern template result, std::vector> try_parse(std::vector, std::string, spec); +extern template result, std::vector> try_parse(std::istream&, std::string, spec); +extern template result, std::vector> try_parse(std::string, spec); +extern template result, std::vector> try_parse(FILE*, std::string, spec); +extern template result, std::vector> try_parse_str(std::string, spec, cxx::source_location); + +extern template basic_value parse(std::vector, std::string, spec); +extern template basic_value parse(std::istream&, std::string, spec); +extern template basic_value parse(std::string, spec); +extern template basic_value parse(FILE*, std::string, spec); +extern template basic_value parse_str(std::string, spec, cxx::source_location); + +#if defined(TOML11_HAS_FILESYSTEM) +extern template cxx::enable_if_t::value, result, std::vector>> try_parse(const std::filesystem::path&, spec); +extern template cxx::enable_if_t::value, result, std::vector>> try_parse(const std::filesystem::path&, spec); +extern template cxx::enable_if_t::value, basic_value > parse (const std::filesystem::path&, spec); +extern template cxx::enable_if_t::value, basic_value > parse (const std::filesystem::path&, spec); +#endif // filesystem + +} // toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_PARSER_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/region.hpp b/src/frontend/qt_sdl/toml/toml11/region.hpp new file mode 100644 index 00000000..b48300c0 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/region.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_REGION_HPP +#define TOML11_REGION_HPP + +#include "fwd/region_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/region_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_REGION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/result.hpp b/src/frontend/qt_sdl/toml/toml11/result.hpp new file mode 100644 index 00000000..e847c4b9 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/result.hpp @@ -0,0 +1,486 @@ +#ifndef TOML11_RESULT_HPP +#define TOML11_RESULT_HPP + +#include "compat.hpp" +#include "exception.hpp" + +#include +#include +#include +#include + +#include + +namespace toml +{ + +struct bad_result_access final : public ::toml::exception +{ + public: + explicit bad_result_access(std::string what_arg) + : what_(std::move(what_arg)) + {} + ~bad_result_access() noexcept override = default; + const char* what() const noexcept override {return what_.c_str();} + + private: + std::string what_; +}; + +// ----------------------------------------------------------------------------- + +template +struct success +{ + static_assert( ! std::is_same::value, ""); + + using value_type = T; + + explicit success(value_type v) + noexcept(std::is_nothrow_move_constructible::value) + : value(std::move(v)) + {} + + template, T>::value, + std::nullptr_t> = nullptr> + explicit success(U&& v): value(std::forward(v)) {} + + template + explicit success(success v): value(std::move(v.value)) {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept {return value;} + value_type const& get() const noexcept {return value;} + + private: + + value_type value; +}; + +template +struct success> +{ + static_assert( ! std::is_same::value, ""); + + using value_type = T; + + explicit success(std::reference_wrapper v) noexcept + : value(std::move(v)) + {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept {return value.get();} + value_type const& get() const noexcept {return value.get();} + + private: + + std::reference_wrapper value; +}; + +template +success::type> ok(T&& v) +{ + return success::type>(std::forward(v)); +} +template +success ok(const char (&literal)[N]) +{ + return success(std::string(literal)); +} + +// ----------------------------------------------------------------------------- + +template +struct failure +{ + using value_type = T; + + explicit failure(value_type v) + noexcept(std::is_nothrow_move_constructible::value) + : value(std::move(v)) + {} + + template, T>::value, + std::nullptr_t> = nullptr> + explicit failure(U&& v): value(std::forward(v)) {} + + template + explicit failure(failure v): value(std::move(v.value)) {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept {return value;} + value_type const& get() const noexcept {return value;} + + private: + + value_type value; +}; + +template +struct failure> +{ + using value_type = T; + + explicit failure(std::reference_wrapper v) noexcept + : value(std::move(v)) + {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept {return value.get();} + value_type const& get() const noexcept {return value.get();} + + private: + + std::reference_wrapper value; +}; + +template +failure::type> err(T&& v) +{ + return failure::type>(std::forward(v)); +} + +template +failure err(const char (&literal)[N]) +{ + return failure(std::string(literal)); +} + +/* ============================================================================ + * _ _ + * _ _ ___ ____ _| | |_ + * | '_/ -_|_-< || | | _| + * |_| \___/__/\_,_|_|\__| + */ + +template +struct result +{ + using success_type = success; + using failure_type = failure; + using value_type = typename success_type::value_type; + using error_type = typename failure_type::value_type; + + result(success_type s): is_ok_(true), succ_(std::move(s)) {} + result(failure_type f): is_ok_(false), fail_(std::move(f)) {} + + template, value_type>>, + std::is_convertible, value_type> + >::value, std::nullptr_t> = nullptr> + result(success s): is_ok_(true), succ_(std::move(s.value)) {} + + template, error_type>>, + std::is_convertible, error_type> + >::value, std::nullptr_t> = nullptr> + result(failure f): is_ok_(false), fail_(std::move(f.value)) {} + + result& operator=(success_type s) + { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(s)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + result& operator=(failure_type f) + { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(f)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + template + result& operator=(success s) + { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(s.value)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + template + result& operator=(failure f) + { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(f.value)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + ~result() noexcept {this->cleanup();} + + result(const result& other): is_ok_(other.is_ok()) + { + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + result(result&& other): is_ok_(other.is_ok()) + { + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + result& operator=(const result& other) + { + this->cleanup(); + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + result& operator=(result&& other) + { + this->cleanup(); + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + template, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type> + >::value, std::nullptr_t> = nullptr> + result(result other): is_ok_(other.is_ok()) + { + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + template, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type> + >::value, std::nullptr_t> = nullptr> + result& operator=(result other) + { + this->cleanup(); + if(other.is_ok()) + { + auto tmp = ::new(std::addressof(this->succ_)) success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } + else + { + auto tmp = ::new(std::addressof(this->fail_)) failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + bool is_ok() const noexcept {return is_ok_;} + bool is_err() const noexcept {return !is_ok_;} + + explicit operator bool() const noexcept {return is_ok_;} + + value_type& unwrap(cxx::source_location loc = cxx::source_location::current()) + { + if(this->is_err()) + { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + value_type const& unwrap(cxx::source_location loc = cxx::source_location::current()) const + { + if(this->is_err()) + { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + + value_type& unwrap_or(value_type& opt) noexcept + { + if(this->is_err()) {return opt;} + return this->succ_.get(); + } + value_type const& unwrap_or(value_type const& opt) const noexcept + { + if(this->is_err()) {return opt;} + return this->succ_.get(); + } + + error_type& unwrap_err(cxx::source_location loc = cxx::source_location::current()) + { + if(this->is_ok()) + { + throw bad_result_access("toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + error_type const& unwrap_err(cxx::source_location loc = cxx::source_location::current()) const + { + if(this->is_ok()) + { + throw bad_result_access("toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + + value_type& as_ok() noexcept + { + assert(this->is_ok()); + return this->succ_.get(); + } + value_type const& as_ok() const noexcept + { + assert(this->is_ok()); + return this->succ_.get(); + } + + error_type& as_err() noexcept + { + assert(this->is_err()); + return this->fail_.get(); + } + error_type const& as_err() const noexcept + { + assert(this->is_err()); + return this->fail_.get(); + } + + private: + + void cleanup() noexcept + { +#if defined(__GNUC__) && ! defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wduplicated-branches" +#endif + + if(this->is_ok_) {this->succ_.~success_type();} + else {this->fail_.~failure_type();} + +#if defined(__GNUC__) && ! defined(__clang__) +#pragma GCC diagnostic pop +#endif + return; + } + + private: + + bool is_ok_; + union + { + success_type succ_; + failure_type fail_; + }; +}; + +// ---------------------------------------------------------------------------- + +namespace detail +{ +struct none_t {}; +inline bool operator==(const none_t&, const none_t&) noexcept {return true;} +inline bool operator!=(const none_t&, const none_t&) noexcept {return false;} +inline bool operator< (const none_t&, const none_t&) noexcept {return false;} +inline bool operator<=(const none_t&, const none_t&) noexcept {return true;} +inline bool operator> (const none_t&, const none_t&) noexcept {return false;} +inline bool operator>=(const none_t&, const none_t&) noexcept {return true;} +inline std::ostream& operator<<(std::ostream& os, const none_t&) +{ + os << "none"; + return os; +} +} // detail + +inline success ok() noexcept +{ + return success(detail::none_t{}); +} +inline failure err() noexcept +{ + return failure(detail::none_t{}); +} + +} // toml +#endif // TOML11_RESULT_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/scanner.hpp b/src/frontend/qt_sdl/toml/toml11/scanner.hpp new file mode 100644 index 00000000..85812d9a --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/scanner.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_SCANNER_HPP +#define TOML11_SCANNER_HPP + +#include "fwd/scanner_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/scanner_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_SCANNER_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/serializer.hpp b/src/frontend/qt_sdl/toml/toml11/serializer.hpp new file mode 100644 index 00000000..a3f148e2 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/serializer.hpp @@ -0,0 +1,1275 @@ +#ifndef TOML11_SERIALIZER_HPP +#define TOML11_SERIALIZER_HPP + +#include "comments.hpp" +#include "error_info.hpp" +#include "exception.hpp" +#include "source_location.hpp" +#include "spec.hpp" +#include "syntax.hpp" +#include "types.hpp" +#include "utility.hpp" +#include "value.hpp" + +#include +#include +#include + +#include +#include + +namespace toml +{ + +struct serialization_error final : public ::toml::exception +{ + public: + explicit serialization_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)), loc_(std::move(loc)) + {} + ~serialization_error() noexcept override = default; + + const char* what() const noexcept override {return what_.c_str();} + source_location const& location() const noexcept {return loc_;} + + private: + std::string what_; + source_location loc_; +}; + +namespace detail +{ +template +class serializer +{ + public: + + using value_type = basic_value; + + using key_type = typename value_type::key_type ; + using comment_type = typename value_type::comment_type ; + using boolean_type = typename value_type::boolean_type ; + using integer_type = typename value_type::integer_type ; + using floating_type = typename value_type::floating_type ; + using string_type = typename value_type::string_type ; + using local_time_type = typename value_type::local_time_type ; + using local_date_type = typename value_type::local_date_type ; + using local_datetime_type = typename value_type::local_datetime_type ; + using offset_datetime_type = typename value_type::offset_datetime_type; + using array_type = typename value_type::array_type ; + using table_type = typename value_type::table_type ; + + using char_type = typename string_type::value_type; + + public: + + explicit serializer(const spec& sp) + : spec_(sp), force_inline_(false), current_indent_(0) + {} + + string_type operator()(const std::vector& ks, const value_type& v) + { + for(const auto& k : ks) + { + this->keys_.push_back(k); + } + return (*this)(v); + } + + string_type operator()(const key_type& k, const value_type& v) + { + this->keys_.push_back(k); + return (*this)(v); + } + + string_type operator()(const value_type& v) + { + switch(v.type()) + { + case value_t::boolean : {return (*this)(v.as_boolean (), v.as_boolean_fmt (), v.location());} + case value_t::integer : {return (*this)(v.as_integer (), v.as_integer_fmt (), v.location());} + case value_t::floating : {return (*this)(v.as_floating (), v.as_floating_fmt (), v.location());} + case value_t::string : {return (*this)(v.as_string (), v.as_string_fmt (), v.location());} + case value_t::offset_datetime: {return (*this)(v.as_offset_datetime(), v.as_offset_datetime_fmt(), v.location());} + case value_t::local_datetime : {return (*this)(v.as_local_datetime (), v.as_local_datetime_fmt (), v.location());} + case value_t::local_date : {return (*this)(v.as_local_date (), v.as_local_date_fmt (), v.location());} + case value_t::local_time : {return (*this)(v.as_local_time (), v.as_local_time_fmt (), v.location());} + case value_t::array : + { + return (*this)(v.as_array(), v.as_array_fmt(), v.comments(), v.location()); + } + case value_t::table : + { + string_type retval; + if(this->keys_.empty()) // it might be the root table. emit comments here. + { + retval += format_comments(v.comments(), v.as_table_fmt().indent_type); + } + if( ! retval.empty()) // we have comment. + { + retval += char_type('\n'); + } + + retval += (*this)(v.as_table(), v.as_table_fmt(), v.comments(), v.location()); + return retval; + } + case value_t::empty: + { + if(this->spec_.ext_null_value) + { + return string_conv("null"); + } + break; + } + default: + { + break; + } + } + throw serialization_error(format_error( + "[error] toml::serializer: toml::basic_value " + "does not have any valid type.", v.location(), "here"), v.location()); + } + + private: + + string_type operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{ + { + if(b) + { + return string_conv("true"); + } + else + { + return string_conv("false"); + } + } // }}} + + string_type operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{ + { + std::ostringstream oss; + this->set_locale(oss); + + const auto insert_spacer = [&fmt](std::string s) -> std::string { + if(fmt.spacer == 0) {return s;} + + std::string sign; + if( ! s.empty() && (s.at(0) == '+' || s.at(0) == '-')) + { + sign += s.at(0); + s.erase(s.begin()); + } + + std::string spaced; + std::size_t counter = 0; + for(auto iter = s.rbegin(); iter != s.rend(); ++iter) + { + if(counter != 0 && counter % fmt.spacer == 0) + { + spaced += '_'; + } + spaced += *iter; + counter += 1; + } + if(!spaced.empty() && spaced.back() == '_') {spaced.pop_back();} + + s.clear(); + std::copy(spaced.rbegin(), spaced.rend(), std::back_inserter(s)); + return sign + s; + }; + + std::string retval; + if(fmt.fmt == integer_format::dec) + { + oss << std::setw(static_cast(fmt.width)) << std::dec << i; + retval = insert_spacer(oss.str()); + + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + retval += '_'; + retval += fmt.suffix; + } + } + else + { + if(i < 0) + { + throw serialization_error(format_error("binary, octal, hexadecimal " + "integer does not allow negative value", loc, "here"), loc); + } + switch(fmt.fmt) + { + case integer_format::hex: + { + oss << std::noshowbase + << std::setw(static_cast(fmt.width)) + << std::setfill('0') + << std::hex; + if(fmt.uppercase) + { + oss << std::uppercase; + } + else + { + oss << std::nouppercase; + } + oss << i; + retval = std::string("0x") + insert_spacer(oss.str()); + break; + } + case integer_format::oct: + { + oss << std::setw(static_cast(fmt.width)) << std::setfill('0') << std::oct << i; + retval = std::string("0o") + insert_spacer(oss.str()); + break; + } + case integer_format::bin: + { + integer_type x{i}; + std::string tmp; + std::size_t bits(0); + while(x != 0) + { + if(fmt.spacer != 0) + { + if(bits != 0 && (bits % fmt.spacer) == 0) {tmp += '_';} + } + if(x % 2 == 1) { tmp += '1'; } else { tmp += '0'; } + x >>= 1; + bits += 1; + } + for(; bits < fmt.width; ++bits) + { + if(fmt.spacer != 0) + { + if(bits != 0 && (bits % fmt.spacer) == 0) {tmp += '_';} + } + tmp += '0'; + } + for(auto iter = tmp.rbegin(); iter != tmp.rend(); ++iter) + { + oss << *iter; + } + retval = std::string("0b") + oss.str(); + break; + } + default: + { + throw serialization_error(format_error( + "none of dec, hex, oct, bin: " + to_string(fmt.fmt), + loc, "here"), loc); + } + } + } + return string_conv(retval); + } // }}} + + string_type operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{ + { + using std::isnan; + using std::isinf; + using std::signbit; + + std::ostringstream oss; + this->set_locale(oss); + + if(isnan(f)) + { + if(signbit(f)) + { + oss << '-'; + } + oss << "nan"; + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + if(isinf(f)) + { + if(signbit(f)) + { + oss << '-'; + } + oss << "inf"; + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + switch(fmt.fmt) + { + case floating_format::defaultfloat: + { + if(fmt.prec != 0) + { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << f; + // since defaultfloat may omit point, we need to add it + std::string s = oss.str(); + if (s.find('.') == std::string::npos && + s.find('e') == std::string::npos && + s.find('E') == std::string::npos ) + { + s += ".0"; + } + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + s += '_'; + s += fmt.suffix; + } + return string_conv(s); + } + case floating_format::fixed: + { + if(fmt.prec != 0) + { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::fixed << f; + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::scientific: + { + if(fmt.prec != 0) + { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::scientific << f; + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::hex: + { + if(this->spec_.ext_hex_float) + { + oss << std::hexfloat << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } + else // no hex allowed. output with max precision. + { + oss << std::setprecision(std::numeric_limits::max_digits10) + << std::scientific << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } + } + default: + { + if(this->spec_.ext_num_suffix && ! fmt.suffix.empty()) + { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + } + } // }}} + + string_type operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{ + { + string_type retval; + switch(fmt.fmt) + { + case string_format::basic: + { + retval += char_type('"'); + retval += this->escape_basic_string(s); + retval += char_type('"'); + return retval; + } + case string_format::literal: + { + if(std::find(s.begin(), s.end(), char_type('\n')) != s.end()) + { + throw serialization_error(format_error("toml::serializer: " + "(non-multiline) literal string cannot have a newline", + loc, "here"), loc); + } + retval += char_type('\''); + retval += s; + retval += char_type('\''); + return retval; + } + case string_format::multiline_basic: + { + retval += string_conv("\"\"\""); + if(fmt.start_with_newline) + { + retval += char_type('\n'); + } + + retval += this->escape_ml_basic_string(s); + + retval += string_conv("\"\"\""); + return retval; + } + case string_format::multiline_literal: + { + retval += string_conv("'''"); + if(fmt.start_with_newline) + { + retval += char_type('\n'); + } + retval += s; + retval += string_conv("'''"); + return retval; + } + default: + { + throw serialization_error(format_error( + "[error] toml::serializer::operator()(string): " + "invalid string_format value", loc, "here"), loc); + } + } + } // }}} + + string_type operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{ + { + std::ostringstream oss; + oss << d; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{ + { + return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision); + } // }}} + + string_type operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{ + { + std::ostringstream oss; + oss << dt.date; + switch(fmt.delimiter) + { + case datetime_delimiter_kind::upper_T: { oss << 'T'; break; } + case datetime_delimiter_kind::lower_t: { oss << 't'; break; } + case datetime_delimiter_kind::space: { oss << ' '; break; } + default: { oss << 'T'; break; } + } + return string_conv(oss.str()) + + this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision); + } // }}} + + string_type operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{ + { + std::ostringstream oss; + oss << odt.date; + switch(fmt.delimiter) + { + case datetime_delimiter_kind::upper_T: { oss << 'T'; break; } + case datetime_delimiter_kind::lower_t: { oss << 't'; break; } + case datetime_delimiter_kind::space: { oss << ' '; break; } + default: { oss << 'T'; break; } + } + oss << string_conv(this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision)); + oss << odt.offset; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ + { + array_format f = fmt.fmt; + if(fmt.fmt == array_format::default_format) + { + // [[in.this.form]], you cannot add a comment to the array itself + // (but you can add a comment to each table). + // To keep comments, we need to avoid multiline array-of-tables + // if array itself has a comment. + if( ! this->keys_.empty() && + ! a.empty() && + com.empty() && + std::all_of(a.begin(), a.end(), [](const value_type& e) {return e.is_table();})) + { + f = array_format::array_of_tables; + } + else + { + f = array_format::oneline; + + // check if it becomes long + std::size_t approx_len = 0; + for(const auto& e : a) + { + // have a comment. cannot be inlined + if( ! e.comments().empty()) + { + f = array_format::multiline; + break; + } + // possibly long types ... + if(e.is_array() || e.is_table() || e.is_offset_datetime() || e.is_local_datetime()) + { + f = array_format::multiline; + break; + } + else if(e.is_boolean()) + { + approx_len += (*this)(e.as_boolean(), e.as_boolean_fmt(), e.location()).size(); + } + else if(e.is_integer()) + { + approx_len += (*this)(e.as_integer(), e.as_integer_fmt(), e.location()).size(); + } + else if(e.is_floating()) + { + approx_len += (*this)(e.as_floating(), e.as_floating_fmt(), e.location()).size(); + } + else if(e.is_string()) + { + if(e.as_string_fmt().fmt == string_format::multiline_basic || + e.as_string_fmt().fmt == string_format::multiline_literal) + { + f = array_format::multiline; + break; + } + approx_len += 2 + (*this)(e.as_string(), e.as_string_fmt(), e.location()).size(); + } + else if(e.is_local_date()) + { + approx_len += 10; // 1234-56-78 + } + else if(e.is_local_time()) + { + approx_len += 15; // 12:34:56.789012 + } + + if(approx_len > 60) // key, ` = `, `[...]` < 80 + { + f = array_format::multiline; + break; + } + approx_len += 2; // `, ` + } + } + } + if(this->force_inline_ && f == array_format::array_of_tables) + { + f = array_format::multiline; + } + if(a.empty() && f == array_format::array_of_tables) + { + f = array_format::oneline; + } + + // -------------------------------------------------------------------- + + if(f == array_format::array_of_tables) + { + if(this->keys_.empty()) + { + throw serialization_error("array of table must have its key. " + "use format(key, v)", loc); + } + string_type retval; + for(const auto& e : a) + { + assert(e.is_table()); + + this->current_indent_ += e.as_table_fmt().name_indent; + retval += this->format_comments(e.comments(), e.as_table_fmt().indent_type); + retval += this->format_indent(e.as_table_fmt().indent_type); + this->current_indent_ -= e.as_table_fmt().name_indent; + + retval += string_conv("[["); + retval += this->format_keys(this->keys_).value(); + retval += string_conv("]]\n"); + + retval += this->format_ml_table(e.as_table(), e.as_table_fmt()); + } + return retval; + } + else if(f == array_format::oneline) + { + // ignore comments. we cannot emit comments + string_type retval; + retval += char_type('['); + for(const auto& e : a) + { + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(", "); + } + if( ! a.empty()) + { + retval.pop_back(); // ` ` + retval.pop_back(); // `,` + } + retval += char_type(']'); + this->force_inline_ = false; + return retval; + } + else + { + assert(f == array_format::multiline); + + string_type retval; + retval += string_conv("[\n"); + + for(const auto& e : a) + { + this->current_indent_ += fmt.body_indent; + retval += this->format_comments(e.comments(), fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.body_indent; + + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(",\n"); + } + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type(']'); + return retval; + } + } // }}} + + string_type operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ + { + if(this->force_inline_) + { + if(fmt.fmt == table_format::multiline_oneline) + { + return this->format_ml_inline_table(t, fmt); + } + else + { + return this->format_inline_table(t, fmt); + } + } + else + { + if(fmt.fmt == table_format::multiline) + { + string_type retval; + // comment is emitted inside format_ml_table + if(auto k = this->format_keys(this->keys_)) + { + this->current_indent_ += fmt.name_indent; + retval += this->format_comments(com, fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.name_indent; + retval += char_type('['); + retval += k.value(); + retval += string_conv("]\n"); + } + // otherwise, its the root. + + retval += this->format_ml_table(t, fmt); + return retval; + } + else if(fmt.fmt == table_format::oneline) + { + return this->format_inline_table(t, fmt); + } + else if(fmt.fmt == table_format::multiline_oneline) + { + return this->format_ml_inline_table(t, fmt); + } + else if(fmt.fmt == table_format::dotted) + { + std::vector keys; + if(this->keys_.empty()) + { + throw serialization_error(format_error("toml::serializer: " + "dotted table must have its key. use format(key, v)", + loc, "here"), loc); + } + keys.push_back(this->keys_.back()); + + const auto retval = this->format_dotted_table(t, fmt, loc, keys); + keys.pop_back(); + return retval; + } + else + { + assert(fmt.fmt == table_format::implicit); + + string_type retval; + for(const auto& kv : t) + { + const auto& k = kv.first; + const auto& v = kv.second; + + if( ! v.is_table() && ! v.is_array_of_tables()) + { + throw serialization_error(format_error("toml::serializer: " + "an implicit table cannot have non-table value.", + v.location(), "here"), v.location()); + } + if(v.is_table()) + { + if(v.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) + { + throw serialization_error(format_error("toml::serializer: " + "an implicit table cannot have non-multiline table", + v.location(), "here"), v.location()); + } + } + else + { + assert(v.is_array()); + for(const auto& e : v.as_array()) + { + if(e.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) + { + throw serialization_error(format_error("toml::serializer: " + "an implicit table cannot have non-multiline table", + e.location(), "here"), e.location()); + } + } + } + + keys_.push_back(k); + retval += (*this)(v); + keys_.pop_back(); + } + return retval; + } + } + } // }}} + + private: + + string_type escape_basic_string(const string_type& s) const // {{{ + { + string_type retval; + for(const char_type c : s) + { + switch(c) + { + case char_type('\\'): {retval += string_conv("\\\\"); break;} + case char_type('\"'): {retval += string_conv("\\\""); break;} + case char_type('\b'): {retval += string_conv("\\b" ); break;} + case char_type('\t'): {retval += string_conv("\\t" ); break;} + case char_type('\f'): {retval += string_conv("\\f" ); break;} + case char_type('\n'): {retval += string_conv("\\n" ); break;} + case char_type('\r'): {retval += string_conv("\\r" ); break;} + default : + { + if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) + { + retval += string_conv("\\e"); + } + else if((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) + { + if(spec_.v1_1_0_add_escape_sequence_x) + { + retval += string_conv("\\x"); + } + else + { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if(c2 < 10) + { + retval += static_cast('0' + c2); + } + else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } + else + { + retval += c; + } + } + } + } + return retval; + } // }}} + + string_type escape_ml_basic_string(const string_type& s) // {{{ + { + string_type retval; + for(const char_type c : s) + { + switch(c) + { + case char_type('\\'): {retval += string_conv("\\\\"); break;} + case char_type('\b'): {retval += string_conv("\\b" ); break;} + case char_type('\t'): {retval += string_conv("\\t" ); break;} + case char_type('\f'): {retval += string_conv("\\f" ); break;} + case char_type('\n'): {retval += string_conv("\n" ); break;} + case char_type('\r'): {retval += string_conv("\\r" ); break;} + default : + { + if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) + { + retval += string_conv("\\e"); + } + else if((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) + { + if(spec_.v1_1_0_add_escape_sequence_x) + { + retval += string_conv("\\x"); + } + else + { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if(c2 < 10) + { + retval += static_cast('0' + c2); + } + else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } + else + { + retval += c; + } + } + } + } + // Only 1 or 2 consecutive `"`s are allowed in multiline basic string. + // 3 consecutive `"`s are considered as a closing delimiter. + // We need to check if there are 3 or more consecutive `"`s and insert + // backslash to break them down into several short `"`s like the `str6` + // in the following example. + // ```toml + // str4 = """Here are two quotation marks: "". Simple enough.""" + // # str5 = """Here are three quotation marks: """.""" # INVALID + // str5 = """Here are three quotation marks: ""\".""" + // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" + // ``` + auto found_3_quotes = retval.find(string_conv("\"\"\"")); + while(found_3_quotes != string_type::npos) + { + retval.replace(found_3_quotes, 3, string_conv("\"\"\\\"")); + found_3_quotes = retval.find(string_conv("\"\"\"")); + } + return retval; + } // }}} + + string_type format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{ + { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(2) << static_cast(t.hour); + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.minute); + if(has_seconds) + { + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.second); + if(subsec_prec != 0) + { + std::ostringstream subsec; + subsec << std::setfill('0') << std::setw(3) << static_cast(t.millisecond); + subsec << std::setfill('0') << std::setw(3) << static_cast(t.microsecond); + subsec << std::setfill('0') << std::setw(3) << static_cast(t.nanosecond); + std::string subsec_str = subsec.str(); + oss << '.' << subsec_str.substr(0, subsec_prec); + } + } + return string_conv(oss.str()); + } // }}} + + string_type format_ml_table(const table_type& t, const table_format_info& fmt) // {{{ + { + const auto format_later = [](const value_type& v) -> bool { + + const bool is_ml_table = v.is_table() && + v.as_table_fmt().fmt != table_format::oneline && + v.as_table_fmt().fmt != table_format::multiline_oneline && + v.as_table_fmt().fmt != table_format::dotted ; + + const bool is_ml_array_table = v.is_array_of_tables() && + v.as_array_fmt().fmt != array_format::oneline && + v.as_array_fmt().fmt != array_format::multiline; + + return is_ml_table || is_ml_array_table; + }; + + string_type retval; + this->current_indent_ += fmt.body_indent; + for(const auto& kv : t) + { + const auto& key = kv.first; + const auto& val = kv.second; + if(format_later(val)) + { + continue; + } + this->keys_.push_back(key); + + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + if(val.is_table() && val.as_table_fmt().fmt == table_format::dotted) + { + retval += (*this)(val); + } + else + { + retval += format_key(key); + retval += string_conv(" = "); + retval += (*this)(val); + retval += char_type('\n'); + } + this->keys_.pop_back(); + } + this->current_indent_ -= fmt.body_indent; + + if( ! retval.empty()) + { + retval += char_type('\n'); // for readability, add empty line between tables + } + for(const auto& kv : t) + { + if( ! format_later(kv.second)) + { + continue; + } + // must be a [multiline.table] or [[multiline.array.of.tables]]. + // comments will be generated inside it. + this->keys_.push_back(kv.first); + retval += (*this)(kv.second); + this->keys_.pop_back(); + } + return retval; + } // }}} + + string_type format_inline_table(const table_type& t, const table_format_info&) // {{{ + { + // comments are ignored because we cannot write without newline + string_type retval; + retval += char_type('{'); + for(const auto& kv : t) + { + this->force_inline_ = true; + retval += this->format_key(kv.first); + retval += string_conv(" = "); + retval += (*this)(kv.second); + retval += string_conv(", "); + } + if( ! t.empty()) + { + retval.pop_back(); // ' ' + retval.pop_back(); // ',' + } + retval += char_type('}'); + this->force_inline_ = false; + return retval; + } // }}} + + string_type format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{ + { + string_type retval; + retval += string_conv("{\n"); + this->current_indent_ += fmt.body_indent; + for(const auto& kv : t) + { + this->force_inline_ = true; + retval += format_comments(kv.second.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += kv.first; + retval += string_conv(" = "); + + this->force_inline_ = true; + retval += (*this)(kv.second); + + retval += string_conv(",\n"); + } + if( ! t.empty()) + { + retval.pop_back(); // '\n' + retval.pop_back(); // ',' + } + this->current_indent_ -= fmt.body_indent; + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type('}'); + return retval; + } // }}} + + string_type format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{ + const source_location&, std::vector& keys) + { + // lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }` + // and `a` and `b` are `dotted`. + // + // - in case if `c` is `oneline`: + // ```toml + // a.b.c = {d = "foo", e = "bar"} + // ``` + // + // - in case if and `c` is `dotted`: + // ```toml + // a.b.c.d = "foo" + // a.b.c.e = "bar" + // ``` + + string_type retval; + + for(const auto& kv : t) + { + const auto& key = kv.first; + const auto& val = kv.second; + + keys.push_back(key); + + // format recursive dotted table? + if (val.is_table() && + val.as_table_fmt().fmt != table_format::oneline && + val.as_table_fmt().fmt != table_format::multiline_oneline) + { + retval += this->format_dotted_table(val.as_table(), val.as_table_fmt(), val.location(), keys); + } + else // non-table or inline tables. format normally + { + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += format_keys(keys).value(); + retval += string_conv(" = "); + this->force_inline_ = true; // sub-table must be inlined + retval += (*this)(val); + retval += char_type('\n'); + this->force_inline_ = false; + } + keys.pop_back(); + } + return retval; + } // }}} + + string_type format_key(const key_type& key) // {{{ + { + if(key.empty()) + { + return string_conv("\"\""); + } + + // check the key can be a bare (unquoted) key + auto loc = detail::make_temporary_location(string_conv(key)); + auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc); + if(reg.is_ok() && loc.eof()) + { + return key; + } + + //if it includes special characters, then format it in a "quoted" key. + string_type formatted = string_conv("\""); + for(const char_type c : key) + { + switch(c) + { + case char_type('\\'): {formatted += string_conv("\\\\"); break;} + case char_type('\"'): {formatted += string_conv("\\\""); break;} + case char_type('\b'): {formatted += string_conv("\\b" ); break;} + case char_type('\t'): {formatted += string_conv("\\t" ); break;} + case char_type('\f'): {formatted += string_conv("\\f" ); break;} + case char_type('\n'): {formatted += string_conv("\\n" ); break;} + case char_type('\r'): {formatted += string_conv("\\r" ); break;} + default : + { + // ASCII ctrl char + if( (char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) + { + if(spec_.v1_1_0_add_escape_sequence_x) + { + formatted += string_conv("\\x"); + } + else + { + formatted += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + formatted += static_cast('0' + c1); + if(c2 < 10) + { + formatted += static_cast('0' + c2); + } + else // 10 <= c2 + { + formatted += static_cast('A' + (c2 - 10)); + } + } + else + { + formatted += c; + } + break; + } + } + } + formatted += string_conv("\""); + return formatted; + } // }}} + cxx::optional format_keys(const std::vector& keys) // {{{ + { + if(keys.empty()) + { + return cxx::make_nullopt(); + } + + string_type formatted; + for(const auto& ky : keys) + { + formatted += format_key(ky); + formatted += char_type('.'); + } + formatted.pop_back(); // remove the last dot '.' + return formatted; + } // }}} + + string_type format_comments(const discard_comments&, const indent_char) const // {{{ + { + return string_conv(""); + } // }}} + string_type format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{ + { + string_type retval; + for(const auto& c : comments) + { + if(c.empty()) {continue;} + retval += format_indent(indent_type); + if(c.front() != '#') {retval += char_type('#');} + retval += string_conv(c); + if(c.back() != '\n') {retval += char_type('\n');} + } + return retval; + } // }}} + + string_type format_indent(const indent_char indent_type) const // {{{ + { + const auto indent = static_cast((std::max)(0, this->current_indent_)); + if(indent_type == indent_char::space) + { + return string_conv(make_string(indent, ' ')); + } + else if(indent_type == indent_char::tab) + { + return string_conv(make_string(indent, '\t')); + } + else + { + return string_type{}; + } + } // }}} + + std::locale set_locale(std::ostream& os) const + { + return os.imbue(std::locale::classic()); + } + + private: + + spec spec_; + bool force_inline_; // table inside an array without fmt specification + std::int32_t current_indent_; + std::vector keys_; +}; +} // detail + +template +typename basic_value::string_type +format(const basic_value& v, const spec s = spec::default_version()) +{ + detail::serializer ser(s); + return ser(v); +} +template +typename basic_value::string_type +format(const typename basic_value::key_type& k, + const basic_value& v, + const spec s = spec::default_version()) +{ + detail::serializer ser(s); + return ser(k, v); +} +template +typename basic_value::string_type +format(const std::vector::key_type>& ks, + const basic_value& v, + const spec s = spec::default_version()) +{ + detail::serializer ser(s); + return ser(ks, v); +} + +template +std::ostream& operator<<(std::ostream& os, const basic_value& v) +{ + os << format(v); + return os; +} + +} // toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml +{ +struct type_config; +struct ordered_type_config; + +extern template typename basic_value::string_type +format(const basic_value&, const spec); + +extern template typename basic_value::string_type +format(const typename basic_value::key_type& k, + const basic_value& v, const spec); + +extern template typename basic_value::string_type +format(const std::vector::key_type>& ks, + const basic_value& v, const spec s); + +extern template typename basic_value::string_type +format(const basic_value&, const spec); + +extern template typename basic_value::string_type +format(const typename basic_value::key_type& k, + const basic_value& v, const spec); + +extern template typename basic_value::string_type +format(const std::vector::key_type>& ks, + const basic_value& v, const spec s); + +namespace detail +{ +extern template class serializer<::toml::type_config>; +extern template class serializer<::toml::ordered_type_config>; +} // detail +} // toml +#endif // TOML11_COMPILE_SOURCES + + +#endif // TOML11_SERIALIZER_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/skip.hpp b/src/frontend/qt_sdl/toml/toml11/skip.hpp new file mode 100644 index 00000000..5a3b1b79 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/skip.hpp @@ -0,0 +1,392 @@ +#ifndef TOML11_SKIP_HPP +#define TOML11_SKIP_HPP + +#include "context.hpp" +#include "region.hpp" +#include "scanner.hpp" +#include "syntax.hpp" +#include "types.hpp" + +#include + +namespace toml +{ +namespace detail +{ + +template +bool skip_whitespace(location& loc, const context& ctx) +{ + return syntax::ws(ctx.toml_spec()).scan(loc).is_ok(); +} + +template +bool skip_empty_lines(location& loc, const context& ctx) +{ + return repeat_at_least(1, sequence( + syntax::ws(ctx.toml_spec()), + syntax::newline(ctx.toml_spec()) + )).scan(loc).is_ok(); +} + +// For error recovery. +// +// In case if a comment line contains an invalid character, we need to skip it +// to advance parsing. +template +void skip_comment_block(location& loc, const context& ctx) +{ + while( ! loc.eof()) + { + skip_whitespace(loc, ctx); + if(loc.current() == '#') + { + while( ! loc.eof()) + { + // both CRLF and LF ends with LF. + if(loc.current() == '\n') + { + loc.advance(); + break; + } + } + } + else if(syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) + { + ; // an empty line. skip this also + } + else + { + // the next token is neither a comment nor empty line. + return ; + } + } + return ; +} + +template +void skip_empty_or_comment_lines(location& loc, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + repeat_at_least(0, sequence( + syntax::ws(spec), + maybe(syntax::comment(spec)), + syntax::newline(spec)) + ).scan(loc); + return ; +} + +// For error recovery. +// +// Sometimes we need to skip a value and find a delimiter, like `,`, `]`, or `}`. +// To find delimiter, we need to skip delimiters in a string. +// Since we are skipping invalid value while error recovery, we don't need +// to check the syntax. Here we just skip string-like region until closing quote +// is found. +template +void skip_string_like(location& loc, const context&) +{ + // if """ is found, skip until the closing """ is found. + if(literal("\"\"\"").scan(loc).is_ok()) + { + while( ! loc.eof()) + { + if(literal("\"\"\"").scan(loc).is_ok()) + { + return; + } + loc.advance(); + } + } + else if(literal("'''").scan(loc).is_ok()) + { + while( ! loc.eof()) + { + if(literal("'''").scan(loc).is_ok()) + { + return; + } + loc.advance(); + } + } + // if " is found, skip until the closing " or newline is found. + else if(loc.current() == '"') + { + while( ! loc.eof()) + { + loc.advance(); + if(loc.current() == '"' || loc.current() == '\n') + { + loc.advance(); + return; + } + } + } + else if(loc.current() == '\'') + { + while( ! loc.eof()) + { + loc.advance(); + if(loc.current() == '\'' || loc.current() == '\n') + { + loc.advance(); + return ; + } + } + } + return; +} + +template +void skip_value(location& loc, const context& ctx); +template +void skip_array_like(location& loc, const context& ctx); +template +void skip_inline_table_like(location& loc, const context& ctx); +template +void skip_key_value_pair(location& loc, const context& ctx); + +template +result +guess_value_type(const location& loc, const context& ctx); + +template +void skip_array_like(location& loc, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + assert(loc.current() == '['); + loc.advance(); + + while( ! loc.eof()) + { + if(loc.current() == '\"' || loc.current() == '\'') + { + skip_string_like(loc, ctx); + } + else if(loc.current() == '#') + { + skip_comment_block(loc, ctx); + } + else if(loc.current() == '{') + { + skip_inline_table_like(loc, ctx); + } + else if(loc.current() == '[') + { + const auto checkpoint = loc; + if(syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) + { + loc = checkpoint; + break; + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } + else if(loc.current() == '=') + { + // key-value pair cannot be inside the array. + // guessing the error is "missing closing bracket `]`". + // find the previous key just before `=`. + while(loc.get_location() != 0) + { + loc.retrace(); + if(loc.current() == '\n') + { + loc.advance(); + break; + } + } + break; + } + else if(loc.current() == ']') + { + break; // found closing bracket + } + else + { + loc.advance(); + } + } + return ; +} + +template +void skip_inline_table_like(location& loc, const context& ctx) +{ + assert(loc.current() == '{'); + loc.advance(); + + const auto& spec = ctx.toml_spec(); + + while( ! loc.eof()) + { + if(loc.current() == '\n' && ! spec.v1_1_0_allow_newlines_in_inline_tables) + { + break; // missing closing `}`. + } + else if(loc.current() == '\"' || loc.current() == '\'') + { + skip_string_like(loc, ctx); + } + else if(loc.current() == '#') + { + skip_comment_block(loc, ctx); + if( ! spec.v1_1_0_allow_newlines_in_inline_tables) + { + // comment must end with newline. + break; // missing closing `}`. + } + } + else if(loc.current() == '[') + { + const auto checkpoint = loc; + if(syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) + { + loc = checkpoint; + break; // missing closing `}`. + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } + else if(loc.current() == '{') + { + skip_inline_table_like(loc, ctx); + } + else if(loc.current() == '}') + { + // closing brace found. guessing the error is inside the table. + break; + } + else + { + // skip otherwise. + loc.advance(); + } + } + return ; +} + +template +void skip_value(location& loc, const context& ctx) +{ + value_t ty = guess_value_type(loc, ctx).unwrap_or(value_t::empty); + if(ty == value_t::string) + { + skip_string_like(loc, ctx); + } + else if(ty == value_t::array) + { + skip_array_like(loc, ctx); + } + else if(ty == value_t::table) + { + // In case of multiline tables, it may skip key-value pair but not the + // whole table. + skip_inline_table_like(loc, ctx); + } + else // others are an "in-line" values. skip until the next line + { + while( ! loc.eof()) + { + if(loc.current() == '\n') + { + break; + } + else if(loc.current() == ',' || loc.current() == ']' || loc.current() == '}') + { + break; + } + loc.advance(); + } + } + return; +} + +template +void skip_key_value_pair(location& loc, const context& ctx) +{ + while( ! loc.eof()) + { + if(loc.current() == '=') + { + skip_whitespace(loc, ctx); + skip_value(loc, ctx); + return; + } + else if(loc.current() == '\n') + { + // newline is found before finding `=`. assuming "missing `=`". + return; + } + loc.advance(); + } + return ; +} + +template +void skip_until_next_table(location& loc, const context& ctx) +{ + const auto& spec = ctx.toml_spec(); + while( ! loc.eof()) + { + if(loc.current() == '\n') + { + loc.advance(); + const auto line_begin = loc; + + skip_whitespace(loc, ctx); + if(syntax::std_table(spec).scan(loc).is_ok()) + { + loc = line_begin; + return ; + } + if(syntax::array_table(spec).scan(loc).is_ok()) + { + loc = line_begin; + return ; + } + } + loc.advance(); + } +} + +} // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml +{ +struct type_config; +struct ordered_type_config; + +namespace detail +{ +extern template bool skip_whitespace (location& loc, const context&); +extern template bool skip_empty_lines (location& loc, const context&); +extern template void skip_comment_block (location& loc, const context&); +extern template void skip_empty_or_comment_lines(location& loc, const context&); +extern template void skip_string_like (location& loc, const context&); +extern template void skip_array_like (location& loc, const context&); +extern template void skip_inline_table_like (location& loc, const context&); +extern template void skip_value (location& loc, const context&); +extern template void skip_key_value_pair (location& loc, const context&); +extern template void skip_until_next_table (location& loc, const context&); + +extern template bool skip_whitespace (location& loc, const context&); +extern template bool skip_empty_lines (location& loc, const context&); +extern template void skip_comment_block (location& loc, const context&); +extern template void skip_empty_or_comment_lines(location& loc, const context&); +extern template void skip_string_like (location& loc, const context&); +extern template void skip_array_like (location& loc, const context&); +extern template void skip_inline_table_like (location& loc, const context&); +extern template void skip_value (location& loc, const context&); +extern template void skip_key_value_pair (location& loc, const context&); +extern template void skip_until_next_table (location& loc, const context&); + +} // detail +} // toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_SKIP_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/source_location.hpp b/src/frontend/qt_sdl/toml/toml11/source_location.hpp new file mode 100644 index 00000000..02e62851 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/source_location.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_SOURCE_LOCATION_HPP +#define TOML11_SOURCE_LOCATION_HPP + +#include "fwd/source_location_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/source_location_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_SOURCE_LOCATION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/spec.hpp b/src/frontend/qt_sdl/toml/toml11/spec.hpp new file mode 100644 index 00000000..ca0a9962 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/spec.hpp @@ -0,0 +1,121 @@ +#ifndef TOML11_SPEC_HPP +#define TOML11_SPEC_HPP + +#include +#include + +#include + +namespace toml +{ + +struct semantic_version +{ + constexpr semantic_version(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept + : major{mjr}, minor{mnr}, patch{p} + {} + + std::uint32_t major; + std::uint32_t minor; + std::uint32_t patch; +}; + +constexpr inline semantic_version +make_semver(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept +{ + return semantic_version(mjr, mnr, p); +} + +constexpr inline bool +operator==(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return lhs.major == rhs.major && + lhs.minor == rhs.minor && + lhs.patch == rhs.patch; +} +constexpr inline bool +operator!=(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return !(lhs == rhs); +} +constexpr inline bool +operator<(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return lhs.major < rhs.major || + (lhs.major == rhs.major && lhs.minor < rhs.minor) || + (lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch < rhs.patch); +} +constexpr inline bool +operator>(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return rhs < lhs; +} +constexpr inline bool +operator<=(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return !(lhs > rhs); +} +constexpr inline bool +operator>=(const semantic_version& lhs, const semantic_version& rhs) noexcept +{ + return !(lhs < rhs); +} + +inline std::ostream& operator<<(std::ostream& os, const semantic_version& v) +{ + os << v.major << '.' << v.minor << '.' << v.patch; + return os; +} + +inline std::string to_string(const semantic_version& v) +{ + std::ostringstream oss; + oss << v; + return oss.str(); +} + +struct spec +{ + constexpr static spec default_version() noexcept + { + return spec::v(1, 0, 0); + } + + constexpr static spec v(std::uint32_t mjr, std::uint32_t mnr, std::uint32_t p) noexcept + { + return spec(make_semver(mjr, mnr, p)); + } + + constexpr explicit spec(const semantic_version& semver) noexcept + : version{semver}, + v1_1_0_allow_control_characters_in_comments {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_newlines_in_inline_tables {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_trailing_comma_in_inline_tables{semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_non_english_in_bare_keys {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_e {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_x {semantic_version{1, 1, 0} <= semver}, + v1_1_0_make_seconds_optional {semantic_version{1, 1, 0} <= semver}, + ext_hex_float {false}, + ext_num_suffix{false}, + ext_null_value{false} + {} + + semantic_version version; // toml version + + // diff from v1.0.0 -> v1.1.0 + bool v1_1_0_allow_control_characters_in_comments; + bool v1_1_0_allow_newlines_in_inline_tables; + bool v1_1_0_allow_trailing_comma_in_inline_tables; + bool v1_1_0_allow_non_english_in_bare_keys; + bool v1_1_0_add_escape_sequence_e; + bool v1_1_0_add_escape_sequence_x; + bool v1_1_0_make_seconds_optional; + + // library extensions + bool ext_hex_float; // allow hex float (in C++ style) + bool ext_num_suffix; // allow number suffix (in C++ style) + bool ext_null_value; // allow `null` as a value +}; + +} // namespace toml +#endif // TOML11_SPEC_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/storage.hpp b/src/frontend/qt_sdl/toml/toml11/storage.hpp new file mode 100644 index 00000000..b63e24f6 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/storage.hpp @@ -0,0 +1,49 @@ +#ifndef TOML11_STORAGE_HPP +#define TOML11_STORAGE_HPP + +#include "compat.hpp" + +namespace toml +{ +namespace detail +{ + +// It owns a pointer to T. It does deep-copy when copied. +// This struct is introduced to implement a recursive type. +// +// `toml::value` contains `std::vector` to represent a toml array. +// But, in the definition of `toml::value`, `toml::value` is still incomplete. +// `std::vector` of an incomplete type is not allowed in C++11 (it is allowed +// after C++17). To avoid this, we need to use a pointer to `toml::value`, like +// `std::vector>`. Although `std::unique_ptr` is +// noncopyable, we want to make `toml::value` copyable. `storage` is introduced +// to resolve those problems. +template +struct storage +{ + using value_type = T; + + explicit storage(value_type v): ptr_(cxx::make_unique(std::move(v))) {} + ~storage() = default; + + storage(const storage& rhs): ptr_(cxx::make_unique(*rhs.ptr_)) {} + storage& operator=(const storage& rhs) + { + this->ptr_ = cxx::make_unique(*rhs.ptr_); + return *this; + } + + storage(storage&&) = default; + storage& operator=(storage&&) = default; + + bool is_ok() const noexcept {return static_cast(ptr_);} + + value_type& get() const noexcept {return *ptr_;} + + private: + std::unique_ptr ptr_; +}; + +} // detail +} // toml +#endif // TOML11_STORAGE_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/syntax.hpp b/src/frontend/qt_sdl/toml/toml11/syntax.hpp new file mode 100644 index 00000000..912535de --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/syntax.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_SYNTAX_HPP +#define TOML11_SYNTAX_HPP + +#include "fwd/syntax_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/syntax_impl.hpp" // IWYU pragma: export +#endif + +#endif// TOML11_SYNTAX_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/traits.hpp b/src/frontend/qt_sdl/toml/toml11/traits.hpp new file mode 100644 index 00000000..7a8832f2 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/traits.hpp @@ -0,0 +1,240 @@ +#ifndef TOML11_TRAITS_HPP +#define TOML11_TRAITS_HPP + +#include "from.hpp" +#include "into.hpp" +#include "compat.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(TOML11_HAS_STRING_VIEW) +#include +#endif + +namespace toml +{ +template +class basic_value; + +namespace detail +{ +// --------------------------------------------------------------------------- +// check whether type T is a kind of container/map class + +struct has_iterator_impl +{ + template static std::true_type check(typename T::iterator*); + template static std::false_type check(...); +}; +struct has_value_type_impl +{ + template static std::true_type check(typename T::value_type*); + template static std::false_type check(...); +}; +struct has_key_type_impl +{ + template static std::true_type check(typename T::key_type*); + template static std::false_type check(...); +}; +struct has_mapped_type_impl +{ + template static std::true_type check(typename T::mapped_type*); + template static std::false_type check(...); +}; +struct has_reserve_method_impl +{ + template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval().reserve(std::declval()))*); +}; +struct has_push_back_method_impl +{ + template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval().push_back(std::declval()))*); +}; +struct is_comparable_impl +{ + template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval() < std::declval())*); +}; + +struct has_from_toml_method_impl +{ + template + static std::true_type check( + decltype(std::declval().from_toml(std::declval<::toml::basic_value>()))*); + + template + static std::false_type check(...); +}; +struct has_into_toml_method_impl +{ + template + static std::true_type check(decltype(std::declval().into_toml())*); + template + static std::false_type check(...); +}; + +struct has_template_into_toml_method_impl +{ + template + static std::true_type check(decltype(std::declval().template into_toml())*); + template + static std::false_type check(...); +}; + +struct has_specialized_from_impl +{ + template + static std::false_type check(...); + template)> + static std::true_type check(::toml::from*); +}; +struct has_specialized_into_impl +{ + template + static std::false_type check(...); + template)> + static std::true_type check(::toml::into*); +}; + + +/// Intel C++ compiler can not use decltype in parent class declaration, here +/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076 +#ifdef __INTEL_COMPILER +#define decltype(...) std::enable_if::type +#endif + +template +struct has_iterator: decltype(has_iterator_impl::check(nullptr)){}; +template +struct has_value_type: decltype(has_value_type_impl::check(nullptr)){}; +template +struct has_key_type: decltype(has_key_type_impl::check(nullptr)){}; +template +struct has_mapped_type: decltype(has_mapped_type_impl::check(nullptr)){}; +template +struct has_reserve_method: decltype(has_reserve_method_impl::check(nullptr)){}; +template +struct has_push_back_method: decltype(has_push_back_method_impl::check(nullptr)){}; +template +struct is_comparable: decltype(is_comparable_impl::check(nullptr)){}; + +template +struct has_from_toml_method: decltype(has_from_toml_method_impl::check(nullptr)){}; + +template +struct has_into_toml_method: decltype(has_into_toml_method_impl::check(nullptr)){}; + +template +struct has_template_into_toml_method: decltype(has_template_into_toml_method_impl::check(nullptr)){}; + +template +struct has_specialized_from: decltype(has_specialized_from_impl::check(nullptr)){}; +template +struct has_specialized_into: decltype(has_specialized_into_impl::check(nullptr)){}; + +#ifdef __INTEL_COMPILER +#undef decltype +#endif + +// --------------------------------------------------------------------------- +// type checkers + +template struct is_std_pair_impl : std::false_type{}; +template +struct is_std_pair_impl> : std::true_type{}; +template +using is_std_pair = is_std_pair_impl>; + +template struct is_std_tuple_impl : std::false_type{}; +template +struct is_std_tuple_impl> : std::true_type{}; +template +using is_std_tuple = is_std_tuple_impl>; + +template struct is_std_array_impl : std::false_type{}; +template +struct is_std_array_impl> : std::true_type{}; +template +using is_std_array = is_std_array_impl>; + +template struct is_std_forward_list_impl : std::false_type{}; +template +struct is_std_forward_list_impl> : std::true_type{}; +template +using is_std_forward_list = is_std_forward_list_impl>; + +template struct is_std_basic_string_impl : std::false_type{}; +template +struct is_std_basic_string_impl> : std::true_type{}; +template +using is_std_basic_string = is_std_basic_string_impl>; + +template struct is_1byte_std_basic_string_impl : std::false_type{}; +template +struct is_1byte_std_basic_string_impl> + : std::integral_constant {}; +template +using is_1byte_std_basic_string = is_std_basic_string_impl>; + +#if defined(TOML11_HAS_STRING_VIEW) +template struct is_std_basic_string_view_impl : std::false_type{}; +template +struct is_std_basic_string_view_impl> : std::true_type{}; +template +using is_std_basic_string_view = is_std_basic_string_view_impl>; + +template +struct is_string_view_of : std::false_type {}; +template +struct is_string_view_of, std::basic_string> : std::true_type {}; +#endif + +template struct is_chrono_duration_impl: std::false_type{}; +template +struct is_chrono_duration_impl>: std::true_type{}; +template +using is_chrono_duration = is_chrono_duration_impl>; + +template +struct is_map_impl : cxx::conjunction< // map satisfies all the following conditions + has_iterator, // has T::iterator + has_value_type, // has T::value_type + has_key_type, // has T::key_type + has_mapped_type // has T::mapped_type + >{}; +template +using is_map = is_map_impl>; + +template +struct is_container_impl : cxx::conjunction< + cxx::negation>, // not a map + cxx::negation>, // not a std::string +#ifdef TOML11_HAS_STRING_VIEW + cxx::negation>, // not a std::string_view +#endif + has_iterator, // has T::iterator + has_value_type // has T::value_type + >{}; +template +using is_container = is_container_impl>; + +template +struct is_basic_value_impl: std::false_type{}; +template +struct is_basic_value_impl<::toml::basic_value>: std::true_type{}; +template +using is_basic_value = is_basic_value_impl>; + +}// detail +}//toml +#endif // TOML11_TRAITS_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/types.hpp b/src/frontend/qt_sdl/toml/toml11/types.hpp new file mode 100644 index 00000000..75f55b2f --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/types.hpp @@ -0,0 +1,397 @@ +#ifndef TOML11_TYPES_HPP +#define TOML11_TYPES_HPP + +#include "comments.hpp" +#include "error_info.hpp" +#include "format.hpp" +#include "ordered_map.hpp" +#include "value.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace toml +{ + +// forward decl +template +class basic_value; + +// when you use a special integer type as toml::value::integer_type, parse must +// be able to read it. So, type_config has static member functions that read the +// integer_type as {dec, hex, oct, bin}-integer. But, in most cases, operator<< +// is enough. To make config easy, we provide the default read functions. +// +// Before this functions is called, syntax is checked and prefix(`0x` etc) and +// spacer(`_`) are removed. + +template +result +read_dec_int(const std::string& str, const source_location src) +{ + constexpr auto max_digits = std::numeric_limits::digits; + assert( ! str.empty()); + + T val{0}; + std::istringstream iss(str); + iss >> val; + if(iss.fail()) + { + return err(make_error_info("toml::parse_dec_integer: " + "too large integer: current max digits = 2^" + std::to_string(max_digits), + std::move(src), "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); +} + +template +result +read_hex_int(const std::string& str, const source_location src) +{ + constexpr auto max_digits = std::numeric_limits::digits; + assert( ! str.empty()); + + T val{0}; + std::istringstream iss(str); + iss >> std::hex >> val; + if(iss.fail()) + { + return err(make_error_info("toml::parse_hex_integer: " + "too large integer: current max value = 2^" + std::to_string(max_digits), + std::move(src), "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); +} + +template +result +read_oct_int(const std::string& str, const source_location src) +{ + constexpr auto max_digits = std::numeric_limits::digits; + assert( ! str.empty()); + + T val{0}; + std::istringstream iss(str); + iss >> std::oct >> val; + if(iss.fail()) + { + return err(make_error_info("toml::parse_oct_integer: " + "too large integer: current max value = 2^" + std::to_string(max_digits), + std::move(src), "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); +} + +template +result +read_bin_int(const std::string& str, const source_location src) +{ + constexpr auto is_bounded = std::numeric_limits::is_bounded; + constexpr auto max_digits = std::numeric_limits::digits; + const auto max_value = (std::numeric_limits::max)(); + + T val{0}; + T base{1}; + for(auto i = str.rbegin(); i != str.rend(); ++i) + { + const auto c = *i; + if(c == '1') + { + val += base; + // prevent `base` from overflow + if(is_bounded && max_value / 2 < base && std::next(i) != str.rend()) + { + base = 0; + } + else + { + base *= 2; + } + } + else + { + assert(c == '0'); + + if(is_bounded && max_value / 2 < base && std::next(i) != str.rend()) + { + base = 0; + } + else + { + base *= 2; + } + } + } + if(base == 0) + { + return err(make_error_info("toml::parse_bin_integer: " + "too large integer: current max value = 2^" + std::to_string(max_digits), + std::move(src), "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); +} + +template +result +read_int(const std::string& str, const source_location src, const std::uint8_t base) +{ + assert(base == 10 || base == 16 || base == 8 || base == 2); + switch(base) + { + case 2: { return read_bin_int(str, src); } + case 8: { return read_oct_int(str, src); } + case 16: { return read_hex_int(str, src); } + default: + { + assert(base == 10); + return read_dec_int(str, src); + } + } +} + +inline result +read_hex_float(const std::string& str, const source_location src, float val) +{ +#if defined(_MSC_VER) && ! defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%a", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%a", std::addressof(val)); +#endif + if(res != 1) + { + return err(make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), "here")); + } + return ok(val); +} +inline result +read_hex_float(const std::string& str, const source_location src, double val) +{ +#if defined(_MSC_VER) && ! defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%la", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%la", std::addressof(val)); +#endif + if(res != 1) + { + return err(make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), "here")); + } + return ok(val); +} +template +cxx::enable_if_t, double>>, + cxx::negation, float>> + >::value, result> +read_hex_float(const std::string&, const source_location src, T) +{ + return err(make_error_info("toml::parse_floating: failed to read " + "floating point value because of unknown type in type_config", + std::move(src), "here")); +} + +template +result +read_dec_float(const std::string& str, const source_location src) +{ + T val; + std::istringstream iss(str); + iss >> val; + if(iss.fail()) + { + return err(make_error_info("toml::parse_floating: " + "failed to read floating point value from stream", + std::move(src), "here")); + } + return ok(val); +} + +template +result +read_float(const std::string& str, const source_location src, const bool is_hex) +{ + if(is_hex) + { + return read_hex_float(str, src, T{}); + } + else + { + return read_dec_float(str, src); + } +} + +struct type_config +{ + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = std::unordered_map; + + static result + parse_int(const std::string& str, const source_location src, const std::uint8_t base) + { + return read_int(str, src, base); + } + static result + parse_float(const std::string& str, const source_location src, const bool is_hex) + { + return read_float(str, src, is_hex); + } +}; + +using value = basic_value; +using table = typename value::table_type; +using array = typename value::array_type; + +struct ordered_type_config +{ + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = ordered_map; + + static result + parse_int(const std::string& str, const source_location src, const std::uint8_t base) + { + return read_int(str, src, base); + } + static result + parse_float(const std::string& str, const source_location src, const bool is_hex) + { + return read_float(str, src, is_hex); + } +}; + +using ordered_value = basic_value; +using ordered_table = typename ordered_value::table_type; +using ordered_array = typename ordered_value::array_type; + +// ---------------------------------------------------------------------------- +// meta functions for internal use + +namespace detail +{ + +// ---------------------------------------------------------------------------- +// check if type T has all the needed member types + +struct has_comment_type_impl +{ + template static std::true_type check(typename T::comment_type*); + template static std::false_type check(...); +}; +template +using has_comment_type = decltype(has_comment_type_impl::check(nullptr)); + +struct has_integer_type_impl +{ + template static std::true_type check(typename T::integer_type*); + template static std::false_type check(...); +}; +template +using has_integer_type = decltype(has_integer_type_impl::check(nullptr)); + +struct has_floating_type_impl +{ + template static std::true_type check(typename T::floating_type*); + template static std::false_type check(...); +}; +template +using has_floating_type = decltype(has_floating_type_impl::check(nullptr)); + +struct has_string_type_impl +{ + template static std::true_type check(typename T::string_type*); + template static std::false_type check(...); +}; +template +using has_string_type = decltype(has_string_type_impl::check(nullptr)); + +struct has_array_type_impl +{ + template static std::true_type check(typename T::template array_type*); + template static std::false_type check(...); +}; +template +using has_array_type = decltype(has_array_type_impl::check(nullptr)); + +struct has_table_type_impl +{ + template static std::true_type check(typename T::template table_type*); + template static std::false_type check(...); +}; +template +using has_table_type = decltype(has_table_type_impl::check(nullptr)); + +struct has_parse_int_impl +{ + template static std::true_type check(decltype(std::declval().parse_int( + std::declval(), + std::declval(), + std::declval() + ))*); + template static std::false_type check(...); +}; +template +using has_parse_int = decltype(has_parse_int_impl::check(nullptr)); + +struct has_parse_float_impl +{ + template static std::true_type check(decltype(std::declval().parse_float( + std::declval(), + std::declval(), + std::declval() + ))*); + template static std::false_type check(...); +}; +template +using has_parse_float = decltype(has_parse_float_impl::check(nullptr)); + +template +using is_type_config = cxx::conjunction< + has_comment_type, + has_integer_type, + has_floating_type, + has_string_type, + has_array_type, + has_table_type, + has_parse_int, + has_parse_float + >; + +} // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml +{ +extern template class basic_value; +extern template class basic_value; +} // toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_TYPES_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/utility.hpp b/src/frontend/qt_sdl/toml/toml11/utility.hpp new file mode 100644 index 00000000..9e30ccb7 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/utility.hpp @@ -0,0 +1,170 @@ +#ifndef TOML11_UTILITY_HPP +#define TOML11_UTILITY_HPP + +#include "result.hpp" +#include "traits.hpp" + +#include +#include + +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +// to output character in an error message. +inline std::string show_char(const int c) +{ + using char_type = unsigned char; + if(std::isgraph(c)) + { + return std::string(1, static_cast(c)); + } + else + { + std::array buf; + buf.fill('\0'); + const auto r = std::snprintf(buf.data(), buf.size(), "0x%02x", c & 0xFF); + assert(r == static_cast(buf.size()) - 1); + (void) r; // Unused variable warning + auto in_hex = std::string(buf.data()); + switch(c) + { + case char_type('\0'): {in_hex += "(NUL)"; break;} + case char_type(' ') : {in_hex += "(SPACE)"; break;} + case char_type('\n'): {in_hex += "(LINE FEED)"; break;} + case char_type('\r'): {in_hex += "(CARRIAGE RETURN)"; break;} + case char_type('\t'): {in_hex += "(TAB)"; break;} + case char_type('\v'): {in_hex += "(VERTICAL TAB)"; break;} + case char_type('\f'): {in_hex += "(FORM FEED)"; break;} + case char_type('\x1B'): {in_hex += "(ESCAPE)"; break;} + default: break; + } + return in_hex; + } +} + +// --------------------------------------------------------------------------- + +template +void try_reserve_impl(Container& container, std::size_t N, std::true_type) +{ + container.reserve(N); + return; +} +template +void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept +{ + return; +} + +template +void try_reserve(Container& container, std::size_t N) +{ + try_reserve_impl(container, N, has_reserve_method{}); + return; +} + +// --------------------------------------------------------------------------- + +template +result from_string(const std::string& str) +{ + T v; + std::istringstream iss(str); + iss >> v; + if(iss.fail()) + { + return err(); + } + return ok(v); +} + +// --------------------------------------------------------------------------- + +// helper function to avoid std::string(0, 'c') or std::string(iter, iter) +template +std::string make_string(Iterator first, Iterator last) +{ + if(first == last) {return "";} + return std::string(first, last); +} +inline std::string make_string(std::size_t len, char c) +{ + if(len == 0) {return "";} + return std::string(len, c); +} + +// --------------------------------------------------------------------------- + +template +struct string_conv_impl +{ + static_assert(sizeof(Char) == sizeof(char), ""); + static_assert(sizeof(Char2) == sizeof(char), ""); + + static std::basic_string invoke(std::basic_string s) + { + std::basic_string retval; + std::transform(s.begin(), s.end(), std::back_inserter(retval), + [](const Char2 c) {return static_cast(c);}); + return retval; + } + template + static std::basic_string invoke(const Char2 (&s)[N]) + { + std::basic_string retval; + // "string literal" has null-char at the end. to skip it, we use prev. + std::transform(std::begin(s), std::prev(std::end(s)), std::back_inserter(retval), + [](const Char2 c) {return static_cast(c);}); + return retval; + } +}; + +template +struct string_conv_impl +{ + static_assert(sizeof(Char) == sizeof(char), ""); + + static std::basic_string invoke(std::basic_string s) + { + return s; + } + template + static std::basic_string invoke(const Char (&s)[N]) + { + return std::basic_string(s); + } +}; + +template +cxx::enable_if_t::value, S> +string_conv(std::basic_string s) +{ + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + return string_conv_impl::invoke(std::move(s)); +} +template +cxx::enable_if_t::value, S> +string_conv(const char (&s)[N]) +{ + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + using C2 = char; + using T2 = std::char_traits; + using A2 = std::allocator; + + return string_conv_impl::template invoke(s); +} + +} // namespace detail +} // namespace toml +#endif // TOML11_UTILITY_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/value.hpp b/src/frontend/qt_sdl/toml/toml11/value.hpp new file mode 100644 index 00000000..d945fa01 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/value.hpp @@ -0,0 +1,2257 @@ +#ifndef TOML11_VALUE_HPP +#define TOML11_VALUE_HPP + +#include "color.hpp" +#include "datetime.hpp" +#include "exception.hpp" +#include "error_info.hpp" +#include "format.hpp" +#include "region.hpp" +#include "source_location.hpp" +#include "storage.hpp" +#include "traits.hpp" +#include "value_t.hpp" +#include "version.hpp" // IWYU pragma: keep < TOML11_HAS_STRING_VIEW + +#ifdef TOML11_HAS_STRING_VIEW +#include +#endif + +#include + +namespace toml +{ +template +class basic_value; + +struct type_error final : public ::toml::exception +{ + public: + type_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)), loc_(std::move(loc)) + {} + ~type_error() noexcept override = default; + + const char* what() const noexcept override {return what_.c_str();} + + source_location const& location() const noexcept {return loc_;} + + private: + std::string what_; + source_location loc_; +}; + +// only for internal use +namespace detail +{ +template +error_info make_type_error(const basic_value&, const std::string&, const value_t); + +template +error_info make_not_found_error(const basic_value&, const std::string&, const typename basic_value::key_type&); + +template +void change_region_of_value(basic_value&, const basic_value&); + +template +struct getter; +} // detail + +template +class basic_value +{ + public: + + using config_type = TypeConfig; + using key_type = typename config_type::string_type; + using value_type = basic_value; + using boolean_type = typename config_type::boolean_type; + using integer_type = typename config_type::integer_type; + using floating_type = typename config_type::floating_type; + using string_type = typename config_type::string_type; + using local_time_type = ::toml::local_time; + using local_date_type = ::toml::local_date; + using local_datetime_type = ::toml::local_datetime; + using offset_datetime_type = ::toml::offset_datetime; + using array_type = typename config_type::template array_type; + using table_type = typename config_type::template table_type; + using comment_type = typename config_type::comment_type; + using char_type = typename string_type::value_type; + + private: + + using region_type = detail::region; + + public: + + basic_value() noexcept + : type_(value_t::empty), empty_('\0'), region_{}, comments_{} + {} + ~basic_value() noexcept {this->cleanup();} + + // copy/move constructor/assigner ===================================== {{{ + + basic_value(const basic_value& v) + : type_(v.type_), region_(v.region_), comments_(v.comments_) + { + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : assigner(array_ , v.array_ ); break; + case value_t::table : assigner(table_ , v.table_ ); break; + default : assigner(empty_ , '\0' ); break; + } + } + basic_value(basic_value&& v) + : type_(v.type()), region_(std::move(v.region_)), + comments_(std::move(v.comments_)) + { + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default : assigner(empty_ , '\0' ); break; + } + } + + basic_value& operator=(const basic_value& v) + { + if(this == std::addressof(v)) {return *this;} + + this->cleanup(); + this->type_ = v.type_; + this->region_ = v.region_; + this->comments_ = v.comments_; + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : assigner(array_ , v.array_ ); break; + case value_t::table : assigner(table_ , v.table_ ); break; + default : assigner(empty_ , '\0' ); break; + } + return *this; + } + basic_value& operator=(basic_value&& v) + { + if(this == std::addressof(v)) {return *this;} + + this->cleanup(); + this->type_ = v.type_; + this->region_ = std::move(v.region_); + this->comments_ = std::move(v.comments_); + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default : assigner(empty_ , '\0' ); break; + } + return *this; + } + // }}} + + // constructor to overwrite commnets ================================== {{{ + + basic_value(basic_value v, std::vector com) + : type_(v.type()), region_(std::move(v.region_)), + comments_(std::move(com)) + { + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default : assigner(empty_ , '\0' ); break; + } + } + // }}} + + // conversion between different basic_values ========================== {{{ + + template + basic_value(basic_value other) + : type_(other.type_), + region_(std::move(other.region_)), + comments_(std::move(other.comments_)) + { + switch(other.type_) + { + // use auto-convert in constructor + case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; + case value_t::string : assigner(string_ , std::move(other.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; + + // may have different container type + case value_t::array : + { + array_type tmp( + std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, array_storage( + detail::storage(std::move(tmp)), + other.array_.format + )); + break; + } + case value_t::table : + { + table_type tmp( + std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, table_storage( + detail::storage(std::move(tmp)), + other.table_.format + )); + break; + } + default: break; + } + } + + template + basic_value(basic_value other, std::vector com) + : type_(other.type_), + region_(std::move(other.region_)), + comments_(std::move(com)) + { + switch(other.type_) + { + // use auto-convert in constructor + case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; + case value_t::string : assigner(string_ , std::move(other.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; + + // may have different container type + case value_t::array : + { + array_type tmp( + std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, array_storage( + detail::storage(std::move(tmp)), + other.array_.format + )); + break; + } + case value_t::table : + { + table_type tmp( + std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, table_storage( + detail::storage(std::move(tmp)), + other.table_.format + )); + break; + } + default: break; + } + } + template + basic_value& operator=(basic_value other) + { + this->cleanup(); + this->region_ = other.region_; + this->comments_ = comment_type(other.comments_); + this->type_ = other.type_; + switch(other.type_) + { + // use auto-convert in constructor + case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; + case value_t::string : assigner(string_ , std::move(other.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; + + // may have different container type + case value_t::array : + { + array_type tmp( + std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, array_storage( + detail::storage(std::move(tmp)), + other.array_.format + )); + break; + } + case value_t::table : + { + table_type tmp( + std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, table_storage( + detail::storage(std::move(tmp)), + other.table_.format + )); + break; + } + default: break; + } + return *this; + } + // }}} + + // constructor (boolean) ============================================== {{{ + + basic_value(boolean_type x) + : basic_value(x, boolean_format_info{}, std::vector{}, region_type{}) + {} + basic_value(boolean_type x, boolean_format_info fmt) + : basic_value(x, fmt, std::vector{}, region_type{}) + {} + basic_value(boolean_type x, std::vector com) + : basic_value(x, boolean_format_info{}, std::move(com), region_type{}) + {} + basic_value(boolean_type x, boolean_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type{}) + {} + basic_value(boolean_type x, boolean_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::boolean), boolean_(boolean_storage(x, fmt)), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(boolean_type x) + { + boolean_format_info fmt; + if(this->is_boolean()) + { + fmt = this->as_boolean_fmt(); + } + this->cleanup(); + this->type_ = value_t::boolean; + this->region_ = region_type{}; + assigner(this->boolean_, boolean_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (integer) ============================================== {{{ + + basic_value(integer_type x) + : basic_value(std::move(x), integer_format_info{}, std::vector{}, region_type{}) + {} + basic_value(integer_type x, integer_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(integer_type x, std::vector com) + : basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{}) + {} + basic_value(integer_type x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) + {} + basic_value(integer_type x, integer_format_info fmt, std::vector com, region_type reg) + : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(integer_type x) + { + integer_format_info fmt; + if(this->is_integer()) + { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type{}; + assigner(this->integer_, integer_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + + template + using enable_if_integer_like_t = cxx::enable_if_t, boolean_type>>, + cxx::negation, integer_type>>, + std::is_integral> + >::value, std::nullptr_t>; + + public: + + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), integer_format_info{}, std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, integer_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, integer_format_info fmt, std::vector com, region_type reg) + : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + template = nullptr> + basic_value& operator=(T x) + { + integer_format_info fmt; + if(this->is_integer()) + { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type{}; + assigner(this->integer_, integer_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (floating) ============================================= {{{ + + basic_value(floating_type x) + : basic_value(std::move(x), floating_format_info{}, std::vector{}, region_type{}) + {} + basic_value(floating_type x, floating_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(floating_type x, std::vector com) + : basic_value(std::move(x), floating_format_info{}, std::move(com), region_type{}) + {} + basic_value(floating_type x, floating_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) + {} + basic_value(floating_type x, floating_format_info fmt, std::vector com, region_type reg) + : type_(value_t::floating), floating_(floating_storage(std::move(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(floating_type x) + { + floating_format_info fmt; + if(this->is_floating()) + { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type{}; + assigner(this->floating_, floating_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + + template + using enable_if_floating_like_t = cxx::enable_if_t, floating_type>>, + std::is_floating_point> + >::value, std::nullptr_t>; + + public: + + template = nullptr> + basic_value(T x) + : basic_value(x, floating_format_info{}, std::vector{}, region_type{}) + {} + + template = nullptr> + basic_value(T x, floating_format_info fmt) + : basic_value(x, std::move(fmt), std::vector{}, region_type{}) + {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(x, floating_format_info{}, std::move(com), region_type{}) + {} + + template = nullptr> + basic_value(T x, floating_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type{}) + {} + + template = nullptr> + basic_value(T x, floating_format_info fmt, std::vector com, region_type reg) + : type_(value_t::floating), floating_(floating_storage(x, std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + + template = nullptr> + basic_value& operator=(T x) + { + floating_format_info fmt; + if(this->is_floating()) + { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type{}; + assigner(this->floating_, floating_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (string) =============================================== {{{ + + basic_value(string_type x) + : basic_value(std::move(x), string_format_info{}, std::vector{}, region_type{}) + {} + basic_value(string_type x, string_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(string_type x, std::vector com) + : basic_value(std::move(x), string_format_info{}, std::move(com), region_type{}) + {} + basic_value(string_type x, string_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) + {} + basic_value(string_type x, string_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::string), string_(string_storage(std::move(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(string_type x) + { + string_format_info fmt; + if(this->is_string()) + { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type{}; + assigner(this->string_, string_storage(x, std::move(fmt))); + return *this; + } + + // "string literal" + + basic_value(const typename string_type::value_type* x) + : basic_value(x, string_format_info{}, std::vector{}, region_type{}) + {} + basic_value(const typename string_type::value_type* x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(const typename string_type::value_type* x, std::vector com) + : basic_value(x, string_format_info{}, std::move(com), region_type{}) + {} + basic_value(const typename string_type::value_type* x, string_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type{}) + {} + basic_value(const typename string_type::value_type* x, string_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(const typename string_type::value_type* x) + { + string_format_info fmt; + if(this->is_string()) + { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type{}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#if defined(TOML11_HAS_STRING_VIEW) + using string_view_type = std::basic_string_view< + typename string_type::value_type, typename string_type::traits_type>; + + basic_value(string_view_type x) + : basic_value(x, string_format_info{}, std::vector{}, region_type{}) + {} + basic_value(string_view_type x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(string_view_type x, std::vector com) + : basic_value(x, string_format_info{}, std::move(com), region_type{}) + {} + basic_value(string_view_type x, string_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type{}) + {} + basic_value(string_view_type x, string_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(string_view_type x) + { + string_format_info fmt; + if(this->is_string()) + { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type{}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#endif // TOML11_HAS_STRING_VIEW + + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value(const T& x) + : basic_value(x, string_format_info{}, std::vector{}, region_type{}) + {} + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector{}, region_type{}) + {} + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value(const T& x, std::vector com) + : basic_value(x, string_format_info{}, std::move(com), region_type{}) + {} + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type{}) + {} + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::string), + string_(string_storage(detail::string_conv(x), std::move(fmt))), + region_(std::move(reg)), comments_(std::move(com)) + {} + template, string_type>>, + detail::is_1byte_std_basic_string + >::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& x) + { + string_format_info fmt; + if(this->is_string()) + { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type{}; + assigner(this->string_, string_storage(detail::string_conv(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_date) =========================================== {{{ + + basic_value(local_date_type x) + : basic_value(x, local_date_format_info{}, std::vector{}, region_type{}) + {} + basic_value(local_date_type x, local_date_format_info fmt) + : basic_value(x, fmt, std::vector{}, region_type{}) + {} + basic_value(local_date_type x, std::vector com) + : basic_value(x, local_date_format_info{}, std::move(com), region_type{}) + {} + basic_value(local_date_type x, local_date_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type{}) + {} + basic_value(local_date_type x, local_date_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::local_date), local_date_(local_date_storage(x, fmt)), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(local_date_type x) + { + local_date_format_info fmt; + if(this->is_local_date()) + { + fmt = this->as_local_date_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_date; + this->region_ = region_type{}; + assigner(this->local_date_, local_date_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (local_time) =========================================== {{{ + + basic_value(local_time_type x) + : basic_value(x, local_time_format_info{}, std::vector{}, region_type{}) + {} + basic_value(local_time_type x, local_time_format_info fmt) + : basic_value(x, fmt, std::vector{}, region_type{}) + {} + basic_value(local_time_type x, std::vector com) + : basic_value(x, local_time_format_info{}, std::move(com), region_type{}) + {} + basic_value(local_time_type x, local_time_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type{}) + {} + basic_value(local_time_type x, local_time_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::local_time), local_time_(local_time_storage(x, fmt)), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(local_time_type x) + { + local_time_format_info fmt; + if(this->is_local_time()) + { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type{}; + assigner(this->local_time_, local_time_storage(x, fmt)); + return *this; + } + + template + basic_value(const std::chrono::duration& x) + : basic_value(local_time_type(x), local_time_format_info{}, std::vector{}, region_type{}) + {} + template + basic_value(const std::chrono::duration& x, local_time_format_info fmt) + : basic_value(local_time_type(x), std::move(fmt), std::vector{}, region_type{}) + {} + template + basic_value(const std::chrono::duration& x, std::vector com) + : basic_value(local_time_type(x), local_time_format_info{}, std::move(com), region_type{}) + {} + template + basic_value(const std::chrono::duration& x, local_time_format_info fmt, std::vector com) + : basic_value(local_time_type(x), std::move(fmt), std::move(com), region_type{}) + {} + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt, + std::vector com, region_type reg) + : basic_value(local_time_type(x), std::move(fmt), std::move(com), std::move(reg)) + {} + template + basic_value& operator=(const std::chrono::duration& x) + { + local_time_format_info fmt; + if(this->is_local_time()) + { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type{}; + assigner(this->local_time_, local_time_storage(local_time_type(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_datetime) =========================================== {{{ + + basic_value(local_datetime_type x) + : basic_value(x, local_datetime_format_info{}, std::vector{}, region_type{}) + {} + basic_value(local_datetime_type x, local_datetime_format_info fmt) + : basic_value(x, fmt, std::vector{}, region_type{}) + {} + basic_value(local_datetime_type x, std::vector com) + : basic_value(x, local_datetime_format_info{}, std::move(com), region_type{}) + {} + basic_value(local_datetime_type x, local_datetime_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type{}) + {} + basic_value(local_datetime_type x, local_datetime_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::local_datetime), local_datetime_(local_datetime_storage(x, fmt)), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(local_datetime_type x) + { + local_datetime_format_info fmt; + if(this->is_local_datetime()) + { + fmt = this->as_local_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_datetime; + this->region_ = region_type{}; + assigner(this->local_datetime_, local_datetime_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (offset_datetime) =========================================== {{{ + + basic_value(offset_datetime_type x) + : basic_value(x, offset_datetime_format_info{}, std::vector{}, region_type{}) + {} + basic_value(offset_datetime_type x, offset_datetime_format_info fmt) + : basic_value(x, fmt, std::vector{}, region_type{}) + {} + basic_value(offset_datetime_type x, std::vector com) + : basic_value(x, offset_datetime_format_info{}, std::move(com), region_type{}) + {} + basic_value(offset_datetime_type x, offset_datetime_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type{}) + {} + basic_value(offset_datetime_type x, offset_datetime_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::offset_datetime), offset_datetime_(offset_datetime_storage(x, fmt)), + region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(offset_datetime_type x) + { + offset_datetime_format_info fmt; + if(this->is_offset_datetime()) + { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type{}; + assigner(this->offset_datetime_, offset_datetime_storage(x, fmt)); + return *this; + } + + // system_clock::time_point + + basic_value(std::chrono::system_clock::time_point x) + : basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::vector{}, region_type{}) + {} + basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt) + : basic_value(offset_datetime_type(x), fmt, std::vector{}, region_type{}) + {} + basic_value(std::chrono::system_clock::time_point x, std::vector com) + : basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::move(com), region_type{}) + {} + basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt, std::vector com) + : basic_value(offset_datetime_type(x), fmt, std::move(com), region_type{}) + {} + basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt, + std::vector com, region_type reg) + : basic_value(offset_datetime_type(x), std::move(fmt), std::move(com), std::move(reg)) + {} + basic_value& operator=(std::chrono::system_clock::time_point x) + { + offset_datetime_format_info fmt; + if(this->is_offset_datetime()) + { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type{}; + assigner(this->offset_datetime_, offset_datetime_storage(offset_datetime_type(x), fmt)); + return *this; + } + + // }}} + + // constructor (array) ================================================ {{{ + + basic_value(array_type x) + : basic_value(std::move(x), array_format_info{}, std::vector{}, region_type{}) + {} + basic_value(array_type x, array_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(array_type x, std::vector com) + : basic_value(std::move(x), array_format_info{}, std::move(com), region_type{}) + {} + basic_value(array_type x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type{}) + {} + basic_value(array_type x, array_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::array), array_(array_storage( + detail::storage(std::move(x)), std::move(fmt) + )), region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(array_type x) + { + array_format_info fmt; + if(this->is_array()) + { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type{}; + assigner(this->array_, array_storage( + detail::storage(std::move(x)), std::move(fmt))); + return *this; + } + + private: + + template + using enable_if_array_like_t = cxx::enable_if_t, + cxx::negation>, + cxx::negation>, +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, +#endif + cxx::negation>, + cxx::negation> + >::value, std::nullptr_t>; + + public: + + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), array_format_info{}, std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, array_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), array_format_info{}, std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, array_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::array), array_(array_storage( + detail::storage(array_type( + std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())) + ), std::move(fmt) + )), region_(std::move(reg)), comments_(std::move(com)) + {} + template = nullptr> + basic_value& operator=(T x) + { + array_format_info fmt; + if(this->is_array()) + { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type{}; + + array_type a(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->array_, array_storage( + detail::storage(std::move(a)), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (table) ================================================ {{{ + + basic_value(table_type x) + : basic_value(std::move(x), table_format_info{}, std::vector{}, region_type{}) + {} + basic_value(table_type x, table_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + basic_value(table_type x, std::vector com) + : basic_value(std::move(x), table_format_info{}, std::move(com), region_type{}) + {} + basic_value(table_type x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type{}) + {} + basic_value(table_type x, table_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::table), table_(table_storage( + detail::storage(std::move(x)), std::move(fmt) + )), region_(std::move(reg)), comments_(std::move(com)) + {} + basic_value& operator=(table_type x) + { + table_format_info fmt; + if(this->is_table()) + { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type{}; + assigner(this->table_, table_storage( + detail::storage(std::move(x)), std::move(fmt))); + return *this; + } + + // table-like + + private: + + template + using enable_if_table_like_t = cxx::enable_if_t>, + detail::is_map, + cxx::negation>, + cxx::negation> + >::value, std::nullptr_t>; + + public: + + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), table_format_info{}, std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, table_format_info fmt) + : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) + {} + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), table_format_info{}, std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type{}) + {} + template = nullptr> + basic_value(T x, table_format_info fmt, + std::vector com, region_type reg) + : type_(value_t::table), table_(table_storage( + detail::storage(table_type( + std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end()) + )), std::move(fmt) + )), region_(std::move(reg)), comments_(std::move(com)) + {} + template = nullptr> + basic_value& operator=(T x) + { + table_format_info fmt; + if(this->is_table()) + { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type{}; + + table_type t(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->table_, table_storage( + detail::storage(std::move(t)), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (user_defined) ========================================= {{{ + + template::value, std::nullptr_t> = nullptr> + basic_value(const T& ud) + : basic_value( + into>::template into_toml(ud)) + {} + template::value, std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value( + into>::template into_toml(ud), + std::move(com)) + {} + template::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) + { + *this = into>::template into_toml(ud); + return *this; + } + + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value(const T& ud): basic_value(ud.into_toml()) {} + + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.into_toml(), std::move(com)) + {} + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) + { + *this = ud.into_toml(); + return *this; + } + + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value(const T& ud): basic_value(ud.template into_toml()) {} + + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.template into_toml(), std::move(com)) + {} + template, + cxx::negation> + >::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) + { + *this = ud.template into_toml(); + return *this; + } + // }}} + + // empty value with region info ======================================= {{{ + + // mainly for `null` extension + basic_value(detail::none_t, region_type reg) noexcept + : type_(value_t::empty), empty_('\0'), region_(std::move(reg)), comments_{} + {} + + // }}} + + // type checking ====================================================== {{{ + + template, value_type>::value, + std::nullptr_t> = nullptr> + bool is() const noexcept + { + return detail::type_to_enum::value == this->type_; + } + bool is(value_t t) const noexcept {return t == this->type_;} + + bool is_empty() const noexcept {return this->is(value_t::empty );} + bool is_boolean() const noexcept {return this->is(value_t::boolean );} + bool is_integer() const noexcept {return this->is(value_t::integer );} + bool is_floating() const noexcept {return this->is(value_t::floating );} + bool is_string() const noexcept {return this->is(value_t::string );} + bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);} + bool is_local_datetime() const noexcept {return this->is(value_t::local_datetime );} + bool is_local_date() const noexcept {return this->is(value_t::local_date );} + bool is_local_time() const noexcept {return this->is(value_t::local_time );} + bool is_array() const noexcept {return this->is(value_t::array );} + bool is_table() const noexcept {return this->is(value_t::table );} + + bool is_array_of_tables() const noexcept + { + if( ! this->is_array()) {return false;} + const auto& a = this->as_array(std::nothrow); // already checked. + + // when you define [[array.of.tables]], at least one empty table will be + // assigned. In case of array of inline tables, `array_of_tables = []`, + // there is no reason to consider this as an array of *tables*. + // So empty array is not an array-of-tables. + if(a.empty()) {return false;} + + // since toml v1.0.0 allows array of heterogeneous types, we need to + // check all the elements. if any of the elements is not a table, it + // is a heterogeneous array and cannot be expressed by `[[aot]]` form. + for(const auto& e : a) + { + if( ! e.is_table()) {return false;} + } + return true; + } + + value_t type() const noexcept {return type_;} + + // }}} + + // as_xxx (noexcept) version ========================================== {{{ + + template + detail::enum_to_type_t> const& + as(const std::nothrow_t&) const noexcept + { + return detail::getter::get_nothrow(*this); + } + template + detail::enum_to_type_t>& + as(const std::nothrow_t&) noexcept + { + return detail::getter::get_nothrow(*this); + } + + boolean_type const& as_boolean (const std::nothrow_t&) const noexcept {return this->boolean_.value;} + integer_type const& as_integer (const std::nothrow_t&) const noexcept {return this->integer_.value;} + floating_type const& as_floating (const std::nothrow_t&) const noexcept {return this->floating_.value;} + string_type const& as_string (const std::nothrow_t&) const noexcept {return this->string_.value;} + offset_datetime_type const& as_offset_datetime(const std::nothrow_t&) const noexcept {return this->offset_datetime_.value;} + local_datetime_type const& as_local_datetime (const std::nothrow_t&) const noexcept {return this->local_datetime_.value;} + local_date_type const& as_local_date (const std::nothrow_t&) const noexcept {return this->local_date_.value;} + local_time_type const& as_local_time (const std::nothrow_t&) const noexcept {return this->local_time_.value;} + array_type const& as_array (const std::nothrow_t&) const noexcept {return this->array_.value.get();} + table_type const& as_table (const std::nothrow_t&) const noexcept {return this->table_.value.get();} + + boolean_type & as_boolean (const std::nothrow_t&) noexcept {return this->boolean_.value;} + integer_type & as_integer (const std::nothrow_t&) noexcept {return this->integer_.value;} + floating_type & as_floating (const std::nothrow_t&) noexcept {return this->floating_.value;} + string_type & as_string (const std::nothrow_t&) noexcept {return this->string_.value;} + offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept {return this->offset_datetime_.value;} + local_datetime_type & as_local_datetime (const std::nothrow_t&) noexcept {return this->local_datetime_.value;} + local_date_type & as_local_date (const std::nothrow_t&) noexcept {return this->local_date_.value;} + local_time_type & as_local_time (const std::nothrow_t&) noexcept {return this->local_time_.value;} + array_type & as_array (const std::nothrow_t&) noexcept {return this->array_.value.get();} + table_type & as_table (const std::nothrow_t&) noexcept {return this->table_.value.get();} + + // }}} + + // as_xxx (throw) ===================================================== {{{ + + template + detail::enum_to_type_t> const& as() const + { + return detail::getter::get(*this); + } + template + detail::enum_to_type_t>& as() + { + return detail::getter::get(*this); + } + + boolean_type const& as_boolean() const + { + if(this->type_ != value_t::boolean) + { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + integer_type const& as_integer() const + { + if(this->type_ != value_t::integer) + { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + floating_type const& as_floating() const + { + if(this->type_ != value_t::floating) + { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + string_type const& as_string() const + { + if(this->type_ != value_t::string) + { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + offset_datetime_type const& as_offset_datetime() const + { + if(this->type_ != value_t::offset_datetime) + { + this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + local_datetime_type const& as_local_datetime() const + { + if(this->type_ != value_t::local_datetime) + { + this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); + } + return this->local_datetime_.value; + } + local_date_type const& as_local_date() const + { + if(this->type_ != value_t::local_date) + { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + local_time_type const& as_local_time() const + { + if(this->type_ != value_t::local_time) + { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + array_type const& as_array() const + { + if(this->type_ != value_t::array) + { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + table_type const& as_table() const + { + if(this->type_ != value_t::table) + { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_type& as_boolean() + { + if(this->type_ != value_t::boolean) + { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + integer_type& as_integer() + { + if(this->type_ != value_t::integer) + { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + floating_type& as_floating() + { + if(this->type_ != value_t::floating) + { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + string_type& as_string() + { + if(this->type_ != value_t::string) + { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + offset_datetime_type& as_offset_datetime() + { + if(this->type_ != value_t::offset_datetime) + { + this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + local_datetime_type& as_local_datetime() + { + if(this->type_ != value_t::local_datetime) + { + this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); + } + return this->local_datetime_.value; + } + local_date_type& as_local_date() + { + if(this->type_ != value_t::local_date) + { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + local_time_type& as_local_time() + { + if(this->type_ != value_t::local_time) + { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + array_type& as_array() + { + if(this->type_ != value_t::array) + { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + table_type& as_table() + { + if(this->type_ != value_t::table) + { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // }}} + + // format accessors (noexcept) ======================================== {{{ + + template + detail::enum_to_fmt_type_t const& + as_fmt(const std::nothrow_t&) const noexcept + { + return detail::getter::get_fmt_nothrow(*this); + } + template + detail::enum_to_fmt_type_t& + as_fmt(const std::nothrow_t&) noexcept + { + return detail::getter::get_fmt_nothrow(*this); + } + + boolean_format_info & as_boolean_fmt (const std::nothrow_t&) noexcept {return this->boolean_.format;} + integer_format_info & as_integer_fmt (const std::nothrow_t&) noexcept {return this->integer_.format;} + floating_format_info & as_floating_fmt (const std::nothrow_t&) noexcept {return this->floating_.format;} + string_format_info & as_string_fmt (const std::nothrow_t&) noexcept {return this->string_.format;} + offset_datetime_format_info& as_offset_datetime_fmt(const std::nothrow_t&) noexcept {return this->offset_datetime_.format;} + local_datetime_format_info & as_local_datetime_fmt (const std::nothrow_t&) noexcept {return this->local_datetime_.format;} + local_date_format_info & as_local_date_fmt (const std::nothrow_t&) noexcept {return this->local_date_.format;} + local_time_format_info & as_local_time_fmt (const std::nothrow_t&) noexcept {return this->local_time_.format;} + array_format_info & as_array_fmt (const std::nothrow_t&) noexcept {return this->array_.format;} + table_format_info & as_table_fmt (const std::nothrow_t&) noexcept {return this->table_.format;} + + boolean_format_info const& as_boolean_fmt (const std::nothrow_t&) const noexcept {return this->boolean_.format;} + integer_format_info const& as_integer_fmt (const std::nothrow_t&) const noexcept {return this->integer_.format;} + floating_format_info const& as_floating_fmt (const std::nothrow_t&) const noexcept {return this->floating_.format;} + string_format_info const& as_string_fmt (const std::nothrow_t&) const noexcept {return this->string_.format;} + offset_datetime_format_info const& as_offset_datetime_fmt(const std::nothrow_t&) const noexcept {return this->offset_datetime_.format;} + local_datetime_format_info const& as_local_datetime_fmt (const std::nothrow_t&) const noexcept {return this->local_datetime_.format;} + local_date_format_info const& as_local_date_fmt (const std::nothrow_t&) const noexcept {return this->local_date_.format;} + local_time_format_info const& as_local_time_fmt (const std::nothrow_t&) const noexcept {return this->local_time_.format;} + array_format_info const& as_array_fmt (const std::nothrow_t&) const noexcept {return this->array_.format;} + table_format_info const& as_table_fmt (const std::nothrow_t&) const noexcept {return this->table_.format;} + + // }}} + + // format accessors (throw) =========================================== {{{ + + template + detail::enum_to_fmt_type_t const& as_fmt() const + { + return detail::getter::get_fmt(*this); + } + template + detail::enum_to_fmt_type_t& as_fmt() + { + return detail::getter::get_fmt(*this); + } + + boolean_format_info const& as_boolean_fmt() const + { + if(this->type_ != value_t::boolean) + { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + integer_format_info const& as_integer_fmt() const + { + if(this->type_ != value_t::integer) + { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + floating_format_info const& as_floating_fmt() const + { + if(this->type_ != value_t::floating) + { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + string_format_info const& as_string_fmt() const + { + if(this->type_ != value_t::string) + { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + offset_datetime_format_info const& as_offset_datetime_fmt() const + { + if(this->type_ != value_t::offset_datetime) + { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + local_datetime_format_info const& as_local_datetime_fmt() const + { + if(this->type_ != value_t::local_datetime) + { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime); + } + return this->local_datetime_.format; + } + local_date_format_info const& as_local_date_fmt() const + { + if(this->type_ != value_t::local_date) + { + this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date); + } + return this->local_date_.format; + } + local_time_format_info const& as_local_time_fmt() const + { + if(this->type_ != value_t::local_time) + { + this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time); + } + return this->local_time_.format; + } + array_format_info const& as_array_fmt() const + { + if(this->type_ != value_t::array) + { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + table_format_info const& as_table_fmt() const + { + if(this->type_ != value_t::table) + { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_format_info& as_boolean_fmt() + { + if(this->type_ != value_t::boolean) + { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + integer_format_info& as_integer_fmt() + { + if(this->type_ != value_t::integer) + { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + floating_format_info& as_floating_fmt() + { + if(this->type_ != value_t::floating) + { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + string_format_info& as_string_fmt() + { + if(this->type_ != value_t::string) + { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + offset_datetime_format_info& as_offset_datetime_fmt() + { + if(this->type_ != value_t::offset_datetime) + { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + local_datetime_format_info& as_local_datetime_fmt() + { + if(this->type_ != value_t::local_datetime) + { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime); + } + return this->local_datetime_.format; + } + local_date_format_info& as_local_date_fmt() + { + if(this->type_ != value_t::local_date) + { + this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date); + } + return this->local_date_.format; + } + local_time_format_info& as_local_time_fmt() + { + if(this->type_ != value_t::local_time) + { + this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time); + } + return this->local_time_.format; + } + array_format_info& as_array_fmt() + { + if(this->type_ != value_t::array) + { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + table_format_info& as_table_fmt() + { + if(this->type_ != value_t::table) + { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + // }}} + + // table accessors ==================================================== {{{ + + value_type& at(const key_type& k) + { + if(!this->is_table()) + { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if(found == table.end()) + { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + value_type const& at(const key_type& k) const + { + if(!this->is_table()) + { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if(found == table.end()) + { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + value_type& operator[](const key_type& k) + { + if(this->is_empty()) + { + (*this) = table_type{}; + } + else if( ! this->is_table()) // initialized, but not a table + { + this->throw_bad_cast("toml::value::operator[](key_type)", value_t::table); + } + return (this->as_table(std::nothrow))[k]; + } + std::size_t count(const key_type& k) const + { + if(!this->is_table()) + { + this->throw_bad_cast("toml::value::count(key_type)", value_t::table); + } + return this->as_table(std::nothrow).count(k); + } + bool contains(const key_type& k) const + { + if(!this->is_table()) + { + this->throw_bad_cast("toml::value::contains(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + return table.find(k) != table.end(); + } + // }}} + + // array accessors ==================================================== {{{ + + value_type& at(const std::size_t idx) + { + if(!this->is_array()) + { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + + if(ar.size() <= idx) + { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), oss.str() + )); + } + return ar.at(idx); + } + value_type const& at(const std::size_t idx) const + { + if(!this->is_array()) + { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + const auto& ar = this->as_array(std::nothrow); + + if(ar.size() <= idx) + { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), oss.str() + )); + } + return ar.at(idx); + } + + value_type& operator[](const std::size_t idx) noexcept + { + // no check... + return this->as_array(std::nothrow)[idx]; + } + value_type const& operator[](const std::size_t idx) const noexcept + { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + void push_back(const value_type& x) + { + if(!this->is_array()) + { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(x); + return; + } + void push_back(value_type&& x) + { + if(!this->is_array()) + { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(std::move(x)); + return; + } + + template + value_type& emplace_back(Ts&& ... args) + { + if(!this->is_array()) + { + this->throw_bad_cast("toml::value::emplace_back(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + ar.emplace_back(std::forward(args) ...); + return ar.back(); + } + + std::size_t size() const + { + switch(this->type_) + { + case value_t::array: + { + return this->as_array(std::nothrow).size(); + } + case value_t::table: + { + return this->as_table(std::nothrow).size(); + } + case value_t::string: + { + return this->as_string(std::nothrow).size(); + } + default: + { + throw type_error(format_error( + "toml::value::size(): bad_cast to container types", + this->location(), + "the actual type is " + to_string(this->type_) + ), this->location()); + } + } + } + + // }}} + + source_location location() const + { + return source_location(this->region_); + } + + comment_type const& comments() const noexcept {return this->comments_;} + comment_type& comments() noexcept {return this->comments_;} + + private: + + // private helper functions =========================================== {{{ + + void cleanup() noexcept + { + switch(this->type_) + { + case value_t::boolean : { boolean_ .~boolean_storage (); break; } + case value_t::integer : { integer_ .~integer_storage (); break; } + case value_t::floating : { floating_ .~floating_storage (); break; } + case value_t::string : { string_ .~string_storage (); break; } + case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); break; } + case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); break; } + case value_t::local_date : { local_date_ .~local_date_storage (); break; } + case value_t::local_time : { local_time_ .~local_time_storage (); break; } + case value_t::array : { array_ .~array_storage (); break; } + case value_t::table : { table_ .~table_storage (); break; } + default : { break; } + } + this->type_ = value_t::empty; + return; + } + + template + static void assigner(T& dst, U&& v) + { + const auto tmp = ::new(std::addressof(dst)) T(std::forward(v)); + assert(tmp == std::addressof(dst)); + (void)tmp; + } + + [[noreturn]] + void throw_bad_cast(const std::string& funcname, const value_t ty) const + { + throw type_error(format_error(detail::make_type_error(*this, funcname, ty)), + this->location()); + } + + [[noreturn]] + void throw_key_not_found_error(const std::string& funcname, const key_type& key) const + { + throw std::out_of_range(format_error( + detail::make_not_found_error(*this, funcname, key))); + } + + template + friend void detail::change_region_of_value(basic_value&, const basic_value&); + + template + friend class basic_value; + + // }}} + + private: + + using boolean_storage = detail::value_with_format; + using integer_storage = detail::value_with_format; + using floating_storage = detail::value_with_format; + using string_storage = detail::value_with_format; + using offset_datetime_storage = detail::value_with_format; + using local_datetime_storage = detail::value_with_format; + using local_date_storage = detail::value_with_format; + using local_time_storage = detail::value_with_format; + using array_storage = detail::value_with_format, array_format_info >; + using table_storage = detail::value_with_format, table_format_info >; + + private: + + value_t type_; + union + { + char empty_; // the smallest type + boolean_storage boolean_; + integer_storage integer_; + floating_storage floating_; + string_storage string_; + offset_datetime_storage offset_datetime_; + local_datetime_storage local_datetime_; + local_date_storage local_date_; + local_time_storage local_time_; + array_storage array_; + table_storage table_; + }; + region_type region_; + comment_type comments_; +}; + +template +bool operator==(const basic_value& lhs, const basic_value& rhs) +{ + if(lhs.type() != rhs.type()) {return false;} + if(lhs.comments() != rhs.comments()) {return false;} + + switch(lhs.type()) + { + case value_t::boolean : + { + return lhs.as_boolean() == rhs.as_boolean(); + } + case value_t::integer : + { + return lhs.as_integer() == rhs.as_integer(); + } + case value_t::floating : + { + return lhs.as_floating() == rhs.as_floating(); + } + case value_t::string : + { + return lhs.as_string() == rhs.as_string(); + } + case value_t::offset_datetime: + { + return lhs.as_offset_datetime() == rhs.as_offset_datetime(); + } + case value_t::local_datetime: + { + return lhs.as_local_datetime() == rhs.as_local_datetime(); + } + case value_t::local_date: + { + return lhs.as_local_date() == rhs.as_local_date(); + } + case value_t::local_time: + { + return lhs.as_local_time() == rhs.as_local_time(); + } + case value_t::array : + { + return lhs.as_array() == rhs.as_array(); + } + case value_t::table : + { + return lhs.as_table() == rhs.as_table(); + } + case value_t::empty : {return true; } + default: {return false;} + } +} + +template +bool operator!=(const basic_value& lhs, const basic_value& rhs) +{ + return !(lhs == rhs); +} + +template +cxx::enable_if_t::array_type>, + detail::is_comparable::table_type> + >::value, bool> +operator<(const basic_value& lhs, const basic_value& rhs) +{ + if(lhs.type() != rhs.type()) + { + return (lhs.type() < rhs.type()); + } + switch(lhs.type()) + { + case value_t::boolean : + { + return lhs.as_boolean() < rhs.as_boolean() || + (lhs.as_boolean() == rhs.as_boolean() && + lhs.comments() < rhs.comments()); + } + case value_t::integer : + { + return lhs.as_integer() < rhs.as_integer() || + (lhs.as_integer() == rhs.as_integer() && + lhs.comments() < rhs.comments()); + } + case value_t::floating : + { + return lhs.as_floating() < rhs.as_floating() || + (lhs.as_floating() == rhs.as_floating() && + lhs.comments() < rhs.comments()); + } + case value_t::string : + { + return lhs.as_string() < rhs.as_string() || + (lhs.as_string() == rhs.as_string() && + lhs.comments() < rhs.comments()); + } + case value_t::offset_datetime: + { + return lhs.as_offset_datetime() < rhs.as_offset_datetime() || + (lhs.as_offset_datetime() == rhs.as_offset_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_datetime: + { + return lhs.as_local_datetime() < rhs.as_local_datetime() || + (lhs.as_local_datetime() == rhs.as_local_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_date: + { + return lhs.as_local_date() < rhs.as_local_date() || + (lhs.as_local_date() == rhs.as_local_date() && + lhs.comments() < rhs.comments()); + } + case value_t::local_time: + { + return lhs.as_local_time() < rhs.as_local_time() || + (lhs.as_local_time() == rhs.as_local_time() && + lhs.comments() < rhs.comments()); + } + case value_t::array : + { + return lhs.as_array() < rhs.as_array() || + (lhs.as_array() == rhs.as_array() && + lhs.comments() < rhs.comments()); + } + case value_t::table : + { + return lhs.as_table() < rhs.as_table() || + (lhs.as_table() == rhs.as_table() && + lhs.comments() < rhs.comments()); + } + case value_t::empty : + { + return lhs.comments() < rhs.comments(); + } + default: + { + return lhs.comments() < rhs.comments(); + } + } +} + +template +cxx::enable_if_t::array_type>, + detail::is_comparable::table_type> + >::value, bool> +operator<=(const basic_value& lhs, const basic_value& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +template +cxx::enable_if_t::array_type>, + detail::is_comparable::table_type> + >::value, bool> +operator>(const basic_value& lhs, const basic_value& rhs) +{ + return !(lhs <= rhs); +} +template +cxx::enable_if_t::array_type>, + detail::is_comparable::table_type> + >::value, bool> +operator>=(const basic_value& lhs, const basic_value& rhs) +{ + return !(lhs < rhs); +} + +// error_info helper +namespace detail +{ +template +error_info make_error_info_rec(error_info e, + const basic_value& v, std::string msg, Ts&& ... tail) +{ + return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward(tail)...); +} +} // detail + +template +error_info make_error_info( + std::string title, const basic_value& v, std::string msg, Ts&& ... tail) +{ + return make_error_info(std::move(title), + v.location(), std::move(msg), std::forward(tail)...); +} +template +std::string format_error(std::string title, + const basic_value& v, std::string msg, Ts&& ... tail) +{ + return format_error(std::move(title), + v.location(), std::move(msg), std::forward(tail)...); +} + +namespace detail +{ + +template +error_info make_type_error(const basic_value& v, const std::string& fname, const value_t ty) +{ + return make_error_info(fname + ": bad_cast to " + to_string(ty), + v.location(), "the actual type is " + to_string(v.type())); +} +template +error_info make_not_found_error(const basic_value& v, const std::string& fname, const typename basic_value::key_type& key) +{ + const auto loc = v.location(); + const std::string title = fname + ": key \"" + string_conv(key) + "\" not found"; + + std::vector> locs; + if( ! loc.is_ok()) + { + return error_info(title, locs); + } + + if(loc.first_line_number() == 1 && loc.first_column_number() == 1 && loc.length() == 1) + { + // The top-level table has its region at the 0th character of the file. + // That means that, in the case when a key is not found in the top-level + // table, the error message points to the first character. If the file has + // the first table at the first line, the error message would be like this. + // ```console + // [error] key "a" not found + // --> example.toml + // | + // 1 | [table] + // | ^------ in this table + // ``` + // It actually points to the top-level table at the first character, not + // `[table]`. But it is too confusing. To avoid the confusion, the error + // message should explicitly say "key not found in the top-level table". + locs.emplace_back(v.location(), "at the top-level table"); + } + else + { + locs.emplace_back(v.location(), "in this table"); + } + return error_info(title, locs); +} + +#define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \ + template \ + struct getter \ + { \ + using value_type = basic_value; \ + using result_type = enum_to_type_t; \ + using format_type = enum_to_fmt_type_t; \ + \ + static result_type& get(value_type& v) \ + { \ + return v.as_ ## ty(); \ + } \ + static result_type const& get(const value_type& v) \ + { \ + return v.as_ ## ty(); \ + } \ + \ + static result_type& get_nothrow(value_type& v) noexcept \ + { \ + return v.as_ ## ty(std::nothrow); \ + } \ + static result_type const& get_nothrow(const value_type& v) noexcept \ + { \ + return v.as_ ## ty(std::nothrow); \ + } \ + \ + static format_type& get_fmt(value_type& v) \ + { \ + return v.as_ ## ty ## _fmt(); \ + } \ + static format_type const& get_fmt(const value_type& v) \ + { \ + return v.as_ ## ty ## _fmt(); \ + } \ + \ + static format_type& get_fmt_nothrow(value_type& v) noexcept \ + { \ + return v.as_ ## ty ## _fmt(std::nothrow); \ + } \ + static format_type const& get_fmt_nothrow(const value_type& v) noexcept \ + { \ + return v.as_ ## ty ## _fmt(std::nothrow); \ + } \ + }; + +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(boolean ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(integer ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(floating ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(string ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(offset_datetime) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_datetime ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_date ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_time ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(array ) +TOML11_DETAIL_GENERATE_COMPTIME_GETTER(table ) + +#undef TOML11_DETAIL_GENERATE_COMPTIME_GETTER + +template +void change_region_of_value(basic_value& dst, const basic_value& src) +{ + dst.region_ = std::move(src.region_); + return; +} + +} // namespace detail +} // namespace toml +#endif // TOML11_VALUE_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/value_t.hpp b/src/frontend/qt_sdl/toml/toml11/value_t.hpp new file mode 100644 index 00000000..ed0fbe93 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/value_t.hpp @@ -0,0 +1,10 @@ +#ifndef TOML11_VALUE_T_HPP +#define TOML11_VALUE_T_HPP + +#include "fwd/value_t_fwd.hpp" // IWYU pragma: export + +#if ! defined(TOML11_COMPILE_SOURCES) +#include "impl/value_t_impl.hpp" // IWYU pragma: export +#endif + +#endif // TOML11_VALUE_T_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/version.hpp b/src/frontend/qt_sdl/toml/toml11/version.hpp new file mode 100644 index 00000000..f95b3cf5 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/version.hpp @@ -0,0 +1,121 @@ +#ifndef TOML11_VERSION_HPP +#define TOML11_VERSION_HPP + +#define TOML11_VERSION_MAJOR 4 +#define TOML11_VERSION_MINOR 2 +#define TOML11_VERSION_PATCH 0 + +#ifndef __cplusplus +# error "__cplusplus is not defined" +#endif + +// Since MSVC does not define `__cplusplus` correctly unless you pass +// `/Zc:__cplusplus` when compiling, the workaround macros are added. +// +// The value of `__cplusplus` macro is defined in the C++ standard spec, but +// MSVC ignores the value, maybe because of backward compatibility. Instead, +// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in +// the C++ standard. So we check if _MSVC_LANG is defined before using `__cplusplus`. +// +// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170 +// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 +// + +#if defined(_MSVC_LANG) && defined(_MSC_VER) && 190024210 <= _MSC_FULL_VER +# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG +#else +# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L +# error "toml11 requires C++11 or later." +#endif + +#if ! defined(__has_include) +# define __has_include(x) 0 +#endif + +#if ! defined(__has_cpp_attribute) +# define __has_cpp_attribute(x) 0 +#endif + +#if ! defined(__has_builtin) +# define __has_builtin(x) 0 +#endif + +// hard to remember + +#ifndef TOML11_CXX14_VALUE +#define TOML11_CXX14_VALUE 201402L +#endif//TOML11_CXX14_VALUE + +#ifndef TOML11_CXX17_VALUE +#define TOML11_CXX17_VALUE 201703L +#endif//TOML11_CXX17_VALUE + +#ifndef TOML11_CXX20_VALUE +#define TOML11_CXX20_VALUE 202002L +#endif//TOML11_CXX20_VALUE + +#if defined(__cpp_char8_t) +# if __cpp_char8_t >= 201811L +# define TOML11_HAS_CHAR8_T 1 +# endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if __has_include() +# define TOML11_HAS_STRING_VIEW 1 +# endif +#endif + +#ifndef TOML11_DISABLE_STD_FILESYSTEM +# if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if __has_include() +# define TOML11_HAS_FILESYSTEM 1 +# endif +# endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE +# if __has_include() +# define TOML11_HAS_OPTIONAL 1 +# endif +#endif + +#if defined(TOML11_COMPILE_SOURCES) +# define TOML11_INLINE +#else +# define TOML11_INLINE inline +#endif + +namespace toml +{ + +inline const char* license_notice() noexcept +{ + return R"(The MIT License (MIT) + +Copyright (c) 2017-now Toru Niina + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.)"; +} + +} // toml +#endif // TOML11_VERSION_HPP diff --git a/src/frontend/qt_sdl/toml/toml11/visit.hpp b/src/frontend/qt_sdl/toml/toml11/visit.hpp new file mode 100644 index 00000000..d97344b3 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml11/visit.hpp @@ -0,0 +1,81 @@ +#ifndef TOML11_VISIT_HPP +#define TOML11_VISIT_HPP + +#include "exception.hpp" +#include "traits.hpp" +#include "value.hpp" + +namespace toml +{ + +template +cxx::return_type_of_t::boolean_type&> +visit(Visitor&& visitor, const basic_value& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(v.as_boolean ());} + case value_t::integer : {return visitor(v.as_integer ());} + case value_t::floating : {return visitor(v.as_floating ());} + case value_t::string : {return visitor(v.as_string ());} + case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} + case value_t::local_datetime : {return visitor(v.as_local_datetime ());} + case value_t::local_date : {return visitor(v.as_local_date ());} + case value_t::local_time : {return visitor(v.as_local_time ());} + case value_t::array : {return visitor(v.as_array ());} + case value_t::table : {return visitor(v.as_table ());} + case value_t::empty : break; + default: break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", v.location(), "here"), v.location()); +} + +template +cxx::return_type_of_t::boolean_type&> +visit(Visitor&& visitor, basic_value& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(v.as_boolean ());} + case value_t::integer : {return visitor(v.as_integer ());} + case value_t::floating : {return visitor(v.as_floating ());} + case value_t::string : {return visitor(v.as_string ());} + case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} + case value_t::local_datetime : {return visitor(v.as_local_datetime ());} + case value_t::local_date : {return visitor(v.as_local_date ());} + case value_t::local_time : {return visitor(v.as_local_time ());} + case value_t::array : {return visitor(v.as_array ());} + case value_t::table : {return visitor(v.as_table ());} + case value_t::empty : break; + default: break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", v.location(), "here"), v.location()); +} + +template +cxx::return_type_of_t::boolean_type&&> +visit(Visitor&& visitor, basic_value&& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(std::move(v.as_boolean ()));} + case value_t::integer : {return visitor(std::move(v.as_integer ()));} + case value_t::floating : {return visitor(std::move(v.as_floating ()));} + case value_t::string : {return visitor(std::move(v.as_string ()));} + case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));} + case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));} + case value_t::local_date : {return visitor(std::move(v.as_local_date ()));} + case value_t::local_time : {return visitor(std::move(v.as_local_time ()));} + case value_t::array : {return visitor(std::move(v.as_array ()));} + case value_t::table : {return visitor(std::move(v.as_table ()));} + case value_t::empty : break; + default: break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", v.location(), "here"), v.location()); +} + +} // toml +#endif // TOML11_VISIT_HPP diff --git a/src/frontend/qt_sdl/toml/toml_fwd.hpp b/src/frontend/qt_sdl/toml/toml_fwd.hpp new file mode 100644 index 00000000..3ba77ff4 --- /dev/null +++ b/src/frontend/qt_sdl/toml/toml_fwd.hpp @@ -0,0 +1,88 @@ +#ifndef TOML11_TOML_FWD_HPP +#define TOML11_TOML_FWD_HPP + +// IWYU pragma: begin_exports +#include "toml11/version.hpp" +#include "toml11/compat.hpp" +#include "toml11/conversion.hpp" +#include "toml11/from.hpp" +#include "toml11/into.hpp" +// IWYU pragma: end_exports + +#include + +#ifdef TOML11_COLORIZE_ERROR_MESSAGE +#define TOML11_ERROR_MESSAGE_COLORIZED true +#else +#define TOML11_ERROR_MESSAGE_COLORIZED false +#endif + +namespace toml +{ +class discard_comments; +class preserve_comments; + +enum class month_t : std::uint8_t; +struct local_date; +struct local_time; +struct time_offset; +struct local_datetime; +struct offset_datetime; + +struct error_info; + +struct exception; + +enum class indent_char : std::uint8_t; +enum class integer_format : std::uint8_t; +enum class floating_format : std::uint8_t; +enum class string_format : std::uint8_t; +enum class datetime_delimiter_kind : std::uint8_t; +enum class array_format : std::uint8_t; +enum class table_format : std::uint8_t; + +struct boolean_format_info; +struct integer_format_info; +struct floating_format_info; +struct string_format_info; +struct offset_datetime_format_info; +struct local_datetime_format_info; +struct local_date_format_info; +struct local_time_format_info; +struct array_format_info; +struct table_format_info; + +template +class ordered_map; + +struct syntax_error; +struct file_io_error; + +struct bad_result_access; +template +struct success; +template +struct failure; +template +struct result; + +struct source_location; + +struct semantic_version; +struct spec; + + +template +class basic_value; +struct type_error; + +struct type_config; +using value = basic_value; + +struct ordered_type_config; +using ordered_value = basic_value; + +enum class value_t : std::uint8_t; + +} // toml +#endif// TOML11_TOML_HPP