update toml11. fixes bug with FPS settings corrupting config file

This commit is contained in:
Arisotura 2024-11-18 22:53:55 +01:00
parent bdc8f635de
commit f1c96281a9
83 changed files with 16956 additions and 10432 deletions

View File

@ -0,0 +1,2 @@
@PACKAGE_INIT@
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")

BIN
res/icon/melon_192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
res/icon/splash.xcf Normal file

Binary file not shown.

View File

@ -816,7 +816,7 @@ Table GetLocalTable(int instance)
std::string key = "Instance" + std::to_string(instance); std::string key = "Instance" + std::to_string(instance);
toml::value& tbl = RootTable[key]; toml::value& tbl = RootTable[key];
if (tbl.is_uninitialized()) if (tbl.is_empty())
RootTable[key] = RootTable["Instance0"]; RootTable[key] = RootTable["Instance0"];
return Table(tbl, key); return Table(tbl, key);

View File

@ -25,7 +25,7 @@
#include <unordered_map> #include <unordered_map>
#include <tuple> #include <tuple>
#include "toml/toml/value.hpp" #include "toml/toml11/types.hpp"
namespace Config namespace Config
{ {

View File

@ -1,38 +1,62 @@
/* #ifndef TOML11_TOML_HPP
* The MIT License (MIT) #define TOML11_TOML_HPP
*
* 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 TOML_FOR_MODERN_CPP // The MIT License (MIT)
#define TOML_FOR_MODERN_CPP //
// 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 // IWYU pragma: begin_exports
#define TOML11_VERSION_MINOR 7 #include "toml11/color.hpp"
#define TOML11_VERSION_PATCH 1 #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" #endif// TOML11_TOML_HPP
#include "toml/literal.hpp"
#include "toml/serializer.hpp"
#include "toml/get.hpp"
#include "toml/macros.hpp"
#endif// TOML_FOR_MODERN_CPP

View File

@ -1,64 +0,0 @@
#ifndef TOML11_COLOR_HPP
#define TOML11_COLOR_HPP
#include <cstdint>
#include <ostream>
#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

View File

@ -1,306 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_COMBINATOR_HPP
#define TOML11_COMBINATOR_HPP
#include <cassert>
#include <cctype>
#include <cstdio>
#include <array>
#include <iomanip>
#include <iterator>
#include <limits>
#include <type_traits>
#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<unsigned char const*>(std::addressof(c))))
{
return std::string(1, c);
}
else
{
std::array<char, 5> buf;
buf.fill('\0');
const auto r = std::snprintf(
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
(void) r; // Unused variable warning
assert(r == static_cast<int>(buf.size()) - 1);
return std::string(buf.data());
}
}
template<char C>
struct character
{
static constexpr char target = C;
static result<region, none_t>
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<char C>
constexpr char character<C>::target;
// closed interval [Low, Up]. both Low and Up are included.
template<char Low, char Up>
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<region, none_t>
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<char L, char U> constexpr char in_range<L, U>::upper;
template<char L, char U> constexpr char in_range<L, U>::lower;
// keep iterator if `Combinator` matches. otherwise, increment `iter` by 1 char.
// for detecting invalid characters, like control sequences in toml string.
template<typename Combinator>
struct exclude
{
static result<region, none_t>
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<typename Combinator>
struct maybe
{
static result<region, none_t>
invoke(location& loc)
{
const auto rslt = Combinator::invoke(loc);
if(rslt.is_ok())
{
return rslt;
}
return ok(region(loc));
}
};
template<typename ... Ts>
struct sequence;
template<typename Head, typename ... Tail>
struct sequence<Head, Tail...>
{
static result<region, none_t>
invoke(location& loc)
{
const auto first = loc.iter();
auto rslt = Head::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
return none();
}
return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
}
// called from the above function only, recursively.
template<typename Iterator>
static result<region, none_t>
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<Tail...>::invoke(loc, std::move(reg), first);
}
};
template<typename Head>
struct sequence<Head>
{
// would be called from sequence<T ...>::invoke only.
template<typename Iterator>
static result<region, none_t>
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<typename ... Ts>
struct either;
template<typename Head, typename ... Tail>
struct either<Head, Tail...>
{
static result<region, none_t>
invoke(location& loc)
{
const auto rslt = Head::invoke(loc);
if(rslt.is_ok()) {return rslt;}
return either<Tail...>::invoke(loc);
}
};
template<typename Head>
struct either<Head>
{
static result<region, none_t>
invoke(location& loc)
{
return Head::invoke(loc);
}
};
template<typename T, typename N>
struct repeat;
template<std::size_t N> struct exactly{};
template<std::size_t N> struct at_least{};
struct unlimited{};
template<typename T, std::size_t N>
struct repeat<T, exactly<N>>
{
static result<region, none_t>
invoke(location& loc)
{
region retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
{
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
return ok(std::move(retval));
}
};
template<typename T, std::size_t N>
struct repeat<T, at_least<N>>
{
static result<region, none_t>
invoke(location& loc)
{
region retval(loc);
const auto first = loc.iter();
for(std::size_t i=0; i<N; ++i)
{
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
loc.reset(first);
return none();
}
retval += rslt.unwrap();
}
while(true)
{
auto rslt = T::invoke(loc);
if(rslt.is_err())
{
return ok(std::move(retval));
}
retval += rslt.unwrap();
}
}
};
template<typename T>
struct repeat<T, unlimited>
{
static result<region, none_t>
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

View File

@ -1,631 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_DATETIME_HPP
#define TOML11_DATETIME_HPP
#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <array>
#include <chrono>
#include <iomanip>
#include <ostream>
#include <tuple>
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<std::int16_t>(y)),
month(static_cast<std::uint8_t>(m)),
day (static_cast<std::uint8_t>(d))
{}
explicit local_date(const std::tm& t)
: year (static_cast<std::int16_t>(t.tm_year + 1900)),
month(static_cast<std::uint8_t>(t.tm_mon)),
day (static_cast<std::uint8_t>(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<int>(this->day);
t.tm_mon = static_cast<int>(this->month);
t.tm_year = static_cast<int>(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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
{
os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(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<std::uint8_t>(h)),
minute(static_cast<std::uint8_t>(m)),
second(static_cast<std::uint8_t>(s)),
millisecond(static_cast<std::uint16_t>(ms)),
microsecond(static_cast<std::uint16_t>(us)),
nanosecond (static_cast<std::uint16_t>(ns))
{}
explicit local_time(const std::tm& t)
: hour (static_cast<std::uint8_t>(t.tm_hour)),
minute(static_cast<std::uint8_t>(t.tm_min)),
second(static_cast<std::uint8_t>(t.tm_sec)),
millisecond(0), microsecond(0), nanosecond(0)
{}
template<typename Rep, typename Period>
explicit local_time(const std::chrono::duration<Rep, Period>& t)
{
const auto h = std::chrono::duration_cast<std::chrono::hours>(t);
this->hour = static_cast<std::uint8_t>(h.count());
const auto t2 = t - h;
const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);
this->minute = static_cast<std::uint8_t>(m.count());
const auto t3 = t2 - m;
const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);
this->second = static_cast<std::uint8_t>(s.count());
const auto t4 = t3 - s;
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);
this->millisecond = static_cast<std::uint16_t>(ms.count());
const auto t5 = t4 - ms;
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);
this->microsecond = static_cast<std::uint16_t>(us.count());
const auto t6 = t5 - us;
const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);
this->nanosecond = static_cast<std::uint16_t>(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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
{
os << std::setfill('0') << std::setw(2) << static_cast<int>(time.hour ) << ':';
os << std::setfill('0') << std::setw(2) << static_cast<int>(time.minute) << ':';
os << std::setfill('0') << std::setw(2) << static_cast<int>(time.second);
if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0)
{
os << '.';
os << std::setfill('0') << std::setw(3) << static_cast<int>(time.millisecond);
if(time.microsecond != 0 || time.nanosecond != 0)
{
os << std::setfill('0') << std::setw(3) << static_cast<int>(time.microsecond);
if(time.nanosecond != 0)
{
os << std::setfill('0') << std::setw(3) << static_cast<int>(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<std::int8_t>(h)),
minute(static_cast<std::int8_t>(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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
{
if(offset.hour == 0 && offset.minute == 0)
{
os << 'Z';
return os;
}
int minute = static_cast<int>(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(&ltime));
this->time.millisecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
this->time.microsecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
this->time.nanosecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::nanoseconds >(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<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(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<internal_duration>(
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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& 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<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(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<internal_duration>(
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<char, 6> 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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const offset_datetime& dt)
{
os << dt.date << 'T' << dt.time << dt.offset;
return os;
}
}//toml
#endif// TOML11_DATETIME

View File

@ -1,65 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_EXCEPTION_HPP
#define TOML11_EXCEPTION_HPP
#include <stdexcept>
#include <string>
#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

File diff suppressed because it is too large Load Diff

View File

@ -1,293 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_LEXER_HPP
#define TOML11_LEXER_HPP
#include <istream>
#include <sstream>
#include <stdexcept>
#include <fstream>
#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<' '>, character<'\t'>>;
using lex_ws = repeat<lex_wschar, at_least<1>>;
using lex_newline = either<character<'\n'>,
sequence<character<'\r'>, character<'\n'>>>;
using lex_lower = in_range<'a', 'z'>;
using lex_upper = in_range<'A', 'Z'>;
using lex_alpha = either<lex_lower, lex_upper>;
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<lex_digit, in_range<'A', 'F'>, in_range<'a', 'f'>>;
using lex_hex_prefix = sequence<character<'0'>, character<'x'>>;
using lex_oct_prefix = sequence<character<'0'>, character<'o'>>;
using lex_bin_prefix = sequence<character<'0'>, character<'b'>>;
using lex_underscore = character<'_'>;
using lex_plus = character<'+'>;
using lex_minus = character<'-'>;
using lex_sign = either<lex_plus, lex_minus>;
// digit | nonzero 1*(digit | _ digit)
using lex_unsigned_dec_int = either<sequence<lex_nonzero, repeat<
either<lex_digit, sequence<lex_underscore, lex_digit>>, at_least<1>>>,
lex_digit>;
// (+|-)? unsigned_dec_int
using lex_dec_int = sequence<maybe<lex_sign>, lex_unsigned_dec_int>;
// hex_prefix hex_dig *(hex_dig | _ hex_dig)
using lex_hex_int = sequence<lex_hex_prefix, sequence<lex_hex_dig, repeat<
either<lex_hex_dig, sequence<lex_underscore, lex_hex_dig>>, unlimited>>>;
// oct_prefix oct_dig *(oct_dig | _ oct_dig)
using lex_oct_int = sequence<lex_oct_prefix, sequence<lex_oct_dig, repeat<
either<lex_oct_dig, sequence<lex_underscore, lex_oct_dig>>, unlimited>>>;
// bin_prefix bin_dig *(bin_dig | _ bin_dig)
using lex_bin_int = sequence<lex_bin_prefix, sequence<lex_bin_dig, repeat<
either<lex_bin_dig, sequence<lex_underscore, lex_bin_dig>>, unlimited>>>;
// (dec_int | hex_int | oct_int | bin_int)
using lex_integer = either<lex_bin_int, lex_oct_int, lex_hex_int, lex_dec_int>;
// ===========================================================================
using lex_inf = sequence<character<'i'>, character<'n'>, character<'f'>>;
using lex_nan = sequence<character<'n'>, character<'a'>, character<'n'>>;
using lex_special_float = sequence<maybe<lex_sign>, either<lex_inf, lex_nan>>;
using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
sequence<lex_underscore, lex_digit>>, unlimited>>;
using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
using lex_exponent_part = sequence<either<character<'e'>, character<'E'>>,
maybe<lex_sign>, lex_zero_prefixable_int>;
using lex_float = either<lex_special_float,
sequence<lex_dec_int, either<lex_exponent_part,
sequence<lex_fractional_part, maybe<lex_exponent_part>>>>>;
// ===========================================================================
using lex_true = sequence<character<'t'>, character<'r'>,
character<'u'>, character<'e'>>;
using lex_false = sequence<character<'f'>, character<'a'>, character<'l'>,
character<'s'>, character<'e'>>;
using lex_boolean = either<lex_true, lex_false>;
// ===========================================================================
using lex_date_fullyear = repeat<lex_digit, exactly<4>>;
using lex_date_month = repeat<lex_digit, exactly<2>>;
using lex_date_mday = repeat<lex_digit, exactly<2>>;
using lex_time_delim = either<character<'T'>, character<'t'>, character<' '>>;
using lex_time_hour = repeat<lex_digit, exactly<2>>;
using lex_time_minute = repeat<lex_digit, exactly<2>>;
using lex_time_second = repeat<lex_digit, exactly<2>>;
using lex_time_secfrac = sequence<character<'.'>,
repeat<lex_digit, at_least<1>>>;
using lex_time_numoffset = sequence<either<character<'+'>, character<'-'>>,
sequence<lex_time_hour, character<':'>,
lex_time_minute>>;
using lex_time_offset = either<character<'Z'>, character<'z'>,
lex_time_numoffset>;
using lex_partial_time = sequence<lex_time_hour, character<':'>,
lex_time_minute, character<':'>,
lex_time_second, maybe<lex_time_secfrac>>;
using lex_full_date = sequence<lex_date_fullyear, character<'-'>,
lex_date_month, character<'-'>,
lex_date_mday>;
using lex_full_time = sequence<lex_partial_time, lex_time_offset>;
using lex_offset_date_time = sequence<lex_full_date, lex_time_delim, lex_full_time>;
using lex_local_date_time = sequence<lex_full_date, lex_time_delim, lex_partial_time>;
using lex_local_date = lex_full_date;
using lex_local_time = lex_partial_time;
// ===========================================================================
using lex_quotation_mark = character<'"'>;
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
in_range<0x0A, 0x1F>,
character<0x22>, character<0x5C>,
character<0x7F>>>;
using lex_escape = character<'\\'>;
using lex_escape_unicode_short = sequence<character<'u'>,
repeat<lex_hex_dig, exactly<4>>>;
using lex_escape_unicode_long = sequence<character<'U'>,
repeat<lex_hex_dig, exactly<8>>>;
using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
character<'b'>, character<'f'>,
character<'n'>, character<'r'>,
character<'t'>,
lex_escape_unicode_short,
lex_escape_unicode_long
>;
using lex_escaped = sequence<lex_escape, lex_escape_seq_char>;
using lex_basic_char = either<lex_basic_unescaped, lex_escaped>;
using lex_basic_string = sequence<lex_quotation_mark,
repeat<lex_basic_char, unlimited>,
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<lex_quotation_mark, exactly<3>>;
using lex_ml_basic_string_open = lex_ml_basic_string_delim;
using lex_ml_basic_string_close = sequence<
repeat<lex_quotation_mark, exactly<3>>,
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
>;
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 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_ws>, lex_newline,
repeat<either<lex_ws, lex_newline>, unlimited>>;
using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
lex_ml_basic_escaped_newline>,
unlimited>;
using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
lex_ml_basic_body,
lex_ml_basic_string_close>;
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
character<0x7F>, character<0x27>>>;
using lex_apostrophe = character<'\''>;
using lex_literal_string = sequence<lex_apostrophe,
repeat<lex_literal_char, unlimited>,
lex_apostrophe>;
// the same reason as above.
using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
using lex_ml_literal_string_open = lex_ml_literal_string_delim;
using lex_ml_literal_string_close = sequence<
repeat<lex_apostrophe, exactly<3>>,
maybe<lex_apostrophe>, maybe<lex_apostrophe>
>;
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
in_range<0x0A, 0x1F>,
character<0x7F>,
lex_ml_literal_string_delim>>;
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
unlimited>;
using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
lex_ml_literal_body,
lex_ml_literal_string_close>;
using lex_string = either<lex_ml_basic_string, lex_basic_string,
lex_ml_literal_string, lex_literal_string>;
// ===========================================================================
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
character<'-'>, character<'_'>>,
at_least<1>>;
using lex_quoted_key = either<lex_basic_string, lex_literal_string>;
using lex_simple_key = either<lex_unquoted_key, lex_quoted_key>;
using lex_dotted_key = sequence<lex_simple_key,
repeat<sequence<lex_dot_sep, lex_simple_key>,
at_least<1>
>
>;
using lex_key = either<lex_dotted_key, lex_simple_key>;
using lex_keyval_sep = sequence<maybe<lex_ws>,
character<'='>,
maybe<lex_ws>>;
using lex_std_table_open = character<'['>;
using lex_std_table_close = character<']'>;
using lex_std_table = sequence<lex_std_table_open,
maybe<lex_ws>,
lex_key,
maybe<lex_ws>,
lex_std_table_close>;
using lex_array_table_open = sequence<lex_std_table_open, lex_std_table_open>;
using lex_array_table_close = sequence<lex_std_table_close, lex_std_table_close>;
using lex_array_table = sequence<lex_array_table_open,
maybe<lex_ws>,
lex_key,
maybe<lex_ws>,
lex_array_table_close>;
using lex_utf8_1byte = in_range<0x00, 0x7F>;
using lex_utf8_2byte = sequence<
in_range<static_cast<char>(0xC2), static_cast<char>(0xDF)>,
in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>
>;
using lex_utf8_3byte = sequence<either<
sequence<character<static_cast<char>(0xE0)>, in_range<static_cast<char>(0xA0), static_cast<char>(0xBF)>>,
sequence<in_range <static_cast<char>(0xE1), static_cast<char>(0xEC)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>,
sequence<character<static_cast<char>(0xED)>, in_range<static_cast<char>(0x80), static_cast<char>(0x9F)>>,
sequence<in_range <static_cast<char>(0xEE), static_cast<char>(0xEF)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>
>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>;
using lex_utf8_4byte = sequence<either<
sequence<character<static_cast<char>(0xF0)>, in_range<static_cast<char>(0x90), static_cast<char>(0xBF)>>,
sequence<in_range <static_cast<char>(0xF1), static_cast<char>(0xF3)>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>>,
sequence<character<static_cast<char>(0xF4)>, in_range<static_cast<char>(0x80), static_cast<char>(0x8F)>>
>, in_range<static_cast<char>(0x80), static_cast<char>(0xBF)>,
in_range<static_cast<char>(0x80), static_cast<char>(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<character<0x09>, in_range<0x20, 0x7E>>;
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
} // detail
} // toml
#endif // TOML_LEXER_HPP

View File

@ -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<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
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::sequence<
::toml::detail::maybe<::toml::detail::lex_ws>,
::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<value_type>(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<value_type>(loc))
{
return data.unwrap();
}
else // none of them.
{
throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
}
}
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
operator"" _toml(const char* str, std::size_t len)
{
::toml::detail::location loc(
std::string("TOML literal encoded in a C++ code"),
std::vector<char>(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<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
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<char>(reinterpret_cast<const char*>(str),
reinterpret_cast<const char*>(str) + len));
return literal_internal_impl(std::move(loc));
}
#endif
} // toml_literals
} // literals
} // toml
#endif//TOML11_LITERAL_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,417 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_REGION_HPP
#define TOML11_REGION_HPP
#include <memory>
#include <vector>
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <iomanip>
#include <cassert>
#include "color.hpp"
namespace toml
{
namespace detail
{
// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
template<typename Iterator>
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<std::string> 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<char>::const_iterator;
using difference_type = typename const_iterator::difference_type;
using source_ptr = std::shared_ptr<const std::vector<char>>;
location(std::string source_name, std::vector<char> cont)
: source_(std::make_shared<std::vector<char>>(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<std::vector<char>>(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<bool>(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::size_t>(
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::size_t>(
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::size_t>(
std::count(rollback, this->iter_, '\n'));
}
else // iter < rollback [[unlikely]]
{
this->line_number_ += static_cast<std::size_t>(
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<const_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<std::size_t>(sz);
}
std::size_t after() const noexcept override
{
const auto sz = std::distance(this->iter(), this->line_end());
assert(sz >= 0);
return static_cast<std::size_t>(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<char>::const_iterator;
using source_ptr = std::shared_ptr<const std::vector<char>>;
// 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<bool>(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<std::size_t>(sz);
}
std::size_t before() const noexcept override
{
const auto sz = std::distance(this->line_begin(), this->first());
assert(sz >= 0);
return static_cast<std::size_t>(sz);
}
std::size_t after() const noexcept override
{
const auto sz = std::distance(this->last(), this->line_end());
assert(sz >= 0);
return static_cast<std::size_t>(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<const_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<std::string> comments() const override
{
// assuming the current region (`*this`) points a value.
// ```toml
// a = "value"
// ^^^^^^^- this region
// ```
using rev_iter = std::reverse_iterator<const_iterator>;
std::vector<std::string> 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

View File

@ -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 <type_traits>
#include <stdexcept>
#include <utility>
#include <new>
#include <string>
#include <sstream>
#include <cassert>
namespace toml
{
template<typename T>
struct success
{
using value_type = T;
value_type value;
explicit success(const value_type& v)
noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: value(v)
{}
explicit success(value_type&& v)
noexcept(std::is_nothrow_move_constructible<value_type>::value)
: value(std::move(v))
{}
template<typename U>
explicit success(U&& v): value(std::forward<U>(v)) {}
template<typename U>
explicit success(const success<U>& v): value(v.value) {}
template<typename U>
explicit success(success<U>&& 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<typename T>
struct failure
{
using value_type = T;
value_type value;
explicit failure(const value_type& v)
noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: value(v)
{}
explicit failure(value_type&& v)
noexcept(std::is_nothrow_move_constructible<value_type>::value)
: value(std::move(v))
{}
template<typename U>
explicit failure(U&& v): value(std::forward<U>(v)) {}
template<typename U>
explicit failure(const failure<U>& v): value(v.value) {}
template<typename U>
explicit failure(failure<U>&& 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<typename T>
success<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
ok(T&& v)
{
return success<
typename std::remove_cv<typename std::remove_reference<T>::type>::type
>(std::forward<T>(v));
}
template<typename T>
failure<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
err(T&& v)
{
return failure<
typename std::remove_cv<typename std::remove_reference<T>::type>::type
>(std::forward<T>(v));
}
inline success<std::string> ok(const char* literal)
{
return success<std::string>(std::string(literal));
}
inline failure<std::string> err(const char* literal)
{
return failure<std::string>(std::string(literal));
}
template<typename T, typename E>
struct result
{
using value_type = T;
using error_type = E;
using success_type = success<value_type>;
using failure_type = failure<error_type>;
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<typename U>
result(const success<U>& s): is_ok_(true)
{
auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
assert(tmp == std::addressof(this->succ));
(void)tmp;
}
template<typename U>
result(const failure<U>& f): is_ok_(false)
{
auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
assert(tmp == std::addressof(this->fail));
(void)tmp;
}
template<typename U>
result(success<U>&& 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<typename U>
result(failure<U>&& 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<typename U>
result& operator=(const success<U>& 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<typename U>
result& operator=(const failure<U>& 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<typename U>
result& operator=(success<U>&& 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<typename U>
result& operator=(failure<U>&& 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<typename U, typename F>
result(const result<U, F>& 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<typename U, typename F>
result(result<U, F>&& 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<typename U, typename F>
result& operator=(const result<U, F>& 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<typename U, typename F>
result& operator=(result<U, F>&& 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<U, E>
template<typename F>
result<detail::return_type_of_t<F, value_type&>, error_type>
map(F&& f) &
{
if(this->is_ok()){return ok(f(this->as_ok()));}
return err(this->as_err());
}
template<typename F>
result<detail::return_type_of_t<F, value_type const&>, error_type>
map(F&& f) const&
{
if(this->is_ok()){return ok(f(this->as_ok()));}
return err(this->as_err());
}
template<typename F>
result<detail::return_type_of_t<F, value_type &&>, 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<T, F>
template<typename F>
result<value_type, detail::return_type_of_t<F, error_type&>>
map_err(F&& f) &
{
if(this->is_err()){return err(f(this->as_err()));}
return ok(this->as_ok());
}
template<typename F>
result<value_type, detail::return_type_of_t<F, error_type const&>>
map_err(F&& f) const&
{
if(this->is_err()){return err(f(this->as_err()));}
return ok(this->as_ok());
}
template<typename F>
result<value_type, detail::return_type_of_t<F, error_type&&>>
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<typename F, typename U>
detail::return_type_of_t<F, value_type&>
map_or_else(F&& f, U&& opt) &
{
if(this->is_err()){return std::forward<U>(opt);}
return f(this->as_ok());
}
template<typename F, typename U>
detail::return_type_of_t<F, value_type const&>
map_or_else(F&& f, U&& opt) const&
{
if(this->is_err()){return std::forward<U>(opt);}
return f(this->as_ok());
}
template<typename F, typename U>
detail::return_type_of_t<F, value_type&&>
map_or_else(F&& f, U&& opt) &&
{
if(this->is_err()){return std::forward<U>(opt);}
return f(std::move(this->as_ok()));
}
// prerequisities
// F: E -> U
// retval: U
template<typename F, typename U>
detail::return_type_of_t<F, error_type&>
map_err_or_else(F&& f, U&& opt) &
{
if(this->is_ok()){return std::forward<U>(opt);}
return f(this->as_err());
}
template<typename F, typename U>
detail::return_type_of_t<F, error_type const&>
map_err_or_else(F&& f, U&& opt) const&
{
if(this->is_ok()){return std::forward<U>(opt);}
return f(this->as_err());
}
template<typename F, typename U>
detail::return_type_of_t<F, error_type&&>
map_err_or_else(F&& f, U&& opt) &&
{
if(this->is_ok()){return std::forward<U>(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<S, F> and E is convertible to F
template<typename F>
detail::return_type_of_t<F, value_type&>
and_then(F&& f) &
{
if(this->is_ok()){return f(this->as_ok());}
return err(this->as_err());
}
template<typename F>
detail::return_type_of_t<F, value_type const&>
and_then(F&& f) const&
{
if(this->is_ok()){return f(this->as_ok());}
return err(this->as_err());
}
template<typename F>
detail::return_type_of_t<F, value_type&&>
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<S, F> and T is convertible to S
template<typename F>
detail::return_type_of_t<F, error_type&>
or_else(F&& f) &
{
if(this->is_err()){return f(this->as_err());}
return ok(this->as_ok());
}
template<typename F>
detail::return_type_of_t<F, error_type const&>
or_else(F&& f) const&
{
if(this->is_err()){return f(this->as_err());}
return ok(this->as_ok());
}
template<typename F>
detail::return_type_of_t<F, error_type&&>
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<T, E>& other)
{
result<T, E> 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<typename U, typename std::enable_if<!std::is_base_of<
std::exception, U>::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<typename T, typename E>
void swap(result<T, E>& lhs, result<T, E>& rhs)
{
lhs.swap(rhs);
return;
}
// this might be confusing because it eagerly evaluated, while in the other
// cases operator && and || are short-circuited.
//
// template<typename T, typename E>
// inline result<T, E>
// operator&&(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
// {
// return lhs.is_ok() ? rhs : lhs;
// }
//
// template<typename T, typename E>
// inline result<T, E>
// operator||(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
// {
// return lhs.is_ok() ? lhs : rhs;
// }
// ----------------------------------------------------------------------------
// re-use result<T, E> as a optional<T> 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<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
{
os << "none";
return os;
}
inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
} // detail
} // toml11
#endif// TOML11_RESULT_H

View File

@ -1,922 +0,0 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_SERIALIZER_HPP
#define TOML11_SERIALIZER_HPP
#include <cmath>
#include <cstdio>
#include <limits>
#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<typename charT, typename traits, typename Alloc>
std::basic_string<charT, traits, Alloc>
format_key(const std::basic_string<charT, traits, Alloc>& k)
{
if(k.empty())
{
return std::string("\"\"");
}
// check the key can be a bare (unquoted) key
detail::location loc(k, std::vector<char>(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<charT, traits, Alloc> 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<typename charT, typename traits, typename Alloc>
std::basic_string<charT, traits, Alloc>
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
{
if(keys.empty())
{
return std::string("\"\"");
}
std::basic_string<charT, traits, Alloc> serialized;
for(const auto& ky : keys)
{
serialized += format_key(ky);
serialized += charT('.');
}
serialized.pop_back(); // remove the last dot '.'
return serialized;
}
template<typename Value>
struct serializer
{
static_assert(detail::is_basic_value<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<toml::floating>::max_digits10,
const bool can_be_inlined = false,
const bool no_comment = false,
std::vector<toml::key> 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<char> buf(static_cast<std::size_t>(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<std::size_t>::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<std::size_t>::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<std::size_t>::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<std::size_t>::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<toml::key> 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<toml::key> keys_;
};
template<typename C,
template<typename ...> class M, template<typename ...> class V>
std::string
format(const basic_value<C, M, V>& v, std::size_t w = 80u,
int fprec = std::numeric_limits<toml::floating>::max_digits10,
bool no_comment = false, bool force_inline = false)
{
using value_type = basic_value<C, M, V>;
// 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<value_type>(w, fprec, false, no_comment), v);
oss << serialized;
return oss.str();
}
return visit(serializer<value_type>(w, fprec, force_inline), v);
}
namespace detail
{
template<typename charT, typename traits>
int comment_index(std::basic_ostream<charT, traits>&)
{
static const int index = std::ios_base::xalloc();
return index;
}
} // detail
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
nocomment(std::basic_ostream<charT, traits>& os)
{
// by default, it is zero. and by default, it shows comments.
os.iword(detail::comment_index(os)) = 1;
return os;
}
template<typename charT, typename traits>
std::basic_ostream<charT, traits>&
showcomment(std::basic_ostream<charT, traits>& os)
{
// by default, it is zero. and by default, it shows comments.
os.iword(detail::comment_index(os)) = 0;
return os;
}
template<typename charT, typename traits, typename C,
template<typename ...> class M, template<typename ...> class V>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
{
using value_type = basic_value<C, M, V>;
// get status of std::setw().
const auto w = static_cast<std::size_t>(os.width());
const int fprec = static_cast<int>(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<value_type>(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

View File

@ -1,233 +0,0 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_SOURCE_LOCATION_HPP
#define TOML11_SOURCE_LOCATION_HPP
#include <cstdint>
#include <sstream>
#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::uint_least32_t>(
std::stoul(reg->line_num()));
}
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
region_size_ = static_cast<std::uint_least32_t>(reg->size());
file_name_ = reg->name();
line_str_ = reg->line();
}
}
explicit source_location(const detail::region& reg)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(reg.size())),
file_name_(reg.name()),
line_str_ (reg.line())
{}
explicit source_location(const detail::location& loc)
: line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
region_size_(static_cast<std::uint_least32_t>(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<std::pair<source_location, std::string>>& loc_com,
const std::vector<std::string>& 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<std::size_t>(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<int>(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<std::size_t>(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<loc_com.size(); ++i)
{
const auto& prev = loc_com.at(i-1);
const auto& curr = loc_com.at(i);
retval << '\n';
// if the filenames are the same, print "..."
if(prev.first.file_name() == curr.first.file_name())
{
retval << color::bold << color::blue << " ...\n" << color::reset;
}
else // if filename differs, print " --> 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

View File

@ -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<typename T>
struct storage
{
using value_type = T;
explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
explicit storage(value_type&& v): ptr(toml::make_unique<T>(std::move(v))) {}
~storage() = default;
storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
storage& operator=(const storage& rhs)
{
this->ptr = toml::make_unique<T>(*rhs.ptr);
return *this;
}
storage(storage&&) = default;
storage& operator=(storage&&) = default;
bool is_ok() const noexcept {return static_cast<bool>(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<value_type> ptr;
};
} // detail
} // toml
#endif// TOML11_STORAGE_HPP

View File

@ -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 <cstdint>
#include <algorithm>
#include <string>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
#define TOML11_USING_STRING_VIEW 1
#include <string_view>
#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<typename charT, typename traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& 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

View File

@ -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 <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus >= C++17
namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;
namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class
struct has_iterator_impl
{
template<typename T> static std::true_type check(typename T::iterator*);
template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
template<typename T> static std::true_type check(typename T::value_type*);
template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
template<typename T> static std::true_type check(typename T::key_type*);
template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
template<typename T> static std::true_type check(typename T::mapped_type*);
template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>() < std::declval<T>())*);
};
struct has_from_toml_method_impl
{
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
static std::true_type check(
decltype(std::declval<T>().from_toml(
std::declval<::toml::basic_value<C, Tb, A>>()))*);
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
static std::false_type check(...);
};
struct has_into_toml_method_impl
{
template<typename T>
static std::true_type check(decltype(std::declval<T>().into_toml())*);
template<typename T>
static std::false_type check(...);
};
struct has_specialized_from_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
static std::true_type check(::toml::from<T>*);
};
/// 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<true, decltype(__VA_ARGS__)>::type
#endif
template<typename T>
struct has_iterator : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
template<typename T, typename C,
template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};
template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(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<typename ...> struct conjunction : std::true_type{};
template<typename T> struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};
template<typename ...> struct disjunction : std::false_type{};
template<typename T> struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};
template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
#endif
// ---------------------------------------------------------------------------
// type checkers
template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};
template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
template<typename T> struct is_std_forward_list : std::false_type{};
template<typename T>
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
has_iterator<T>, // has T::iterator
has_value_type<T>, // has T::value_type
has_key_type<T>, // has T::key_type
has_mapped_type<T> // has T::mapped_type
>{};
template<typename T> struct is_map<T&> : is_map<T>{};
template<typename T> struct is_map<T const&> : is_map<T>{};
template<typename T> struct is_map<T volatile&> : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>, // not a map
negation<std::is_same<T, std::string>>, // not a std::string
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if __has_include(<string_view>)
negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif // has_include(<string_view>)
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
>{};
template<typename T> struct is_container<T&> : is_container<T>{};
template<typename T> struct is_container<T const&> : is_container<T>{};
template<typename T> struct is_container<T volatile&> : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};
template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&> : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
// ---------------------------------------------------------------------------
// C++14 index_sequence
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::index_sequence;
using std::make_index_sequence;
#else
template<std::size_t ... Ns> struct index_sequence{};
template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
typedef index_sequence<Ns..., N> type;
};
template<std::size_t N>
struct index_sequence_maker
{
typedef typename push_back_index_sequence<
typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;
#endif // cplusplus >= 2014
// ---------------------------------------------------------------------------
// C++14 enable_if_t
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
using std::enable_if_t;
#else
template<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::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<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;
#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;
#endif
// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.
template<typename T>
struct is_string_literal:
disjunction<
std::is_same<const char*, T>,
conjunction<
std::is_array<T>,
std::is_same<const char, typename std::remove_extent<T>::type>
>
>{};
// ---------------------------------------------------------------------------
// C++20 remove_cvref_t
template<typename T>
struct remove_cvref
{
using type = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
};
template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
}// detail
}//toml
#endif // TOML_TRAITS

View File

@ -1,173 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TYPES_HPP
#define TOML11_TYPES_HPP
#include <unordered_map>
#include <vector>
#include "comments.hpp"
#include "datetime.hpp"
#include "string.hpp"
#include "traits.hpp"
namespace toml
{
template<typename Comment, // discard/preserve_comment
template<typename ...> class Table, // map-like class
template<typename ...> 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<discard_comments, std::unordered_map, std::vector>;
// 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<typename charT, typename traits>
inline std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& 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 charT = char,
typename traits = std::char_traits<charT>,
typename alloc = std::allocator<charT>>
inline std::basic_string<charT, traits, alloc> stringize(value_t t)
{
std::basic_ostringstream<charT, traits, alloc> oss;
oss << t;
return oss.str();
}
namespace detail
{
// helper to define a type that represents a value_t value.
template<value_t V>
using value_t_constant = std::integral_constant<value_t, V>;
// 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<value_t t, typename Value> struct enum_to_type {using type = void ;};
template<typename Value> struct enum_to_type<value_t::empty , Value>{using type = void ;};
template<typename Value> struct enum_to_type<value_t::boolean , Value>{using type = boolean ;};
template<typename Value> struct enum_to_type<value_t::integer , Value>{using type = integer ;};
template<typename Value> struct enum_to_type<value_t::floating , Value>{using type = floating ;};
template<typename Value> struct enum_to_type<value_t::string , Value>{using type = string ;};
template<typename Value> struct enum_to_type<value_t::offset_datetime, Value>{using type = offset_datetime ;};
template<typename Value> struct enum_to_type<value_t::local_datetime , Value>{using type = local_datetime ;};
template<typename Value> struct enum_to_type<value_t::local_date , Value>{using type = local_date ;};
template<typename Value> struct enum_to_type<value_t::local_time , Value>{using type = local_time ;};
template<typename Value> struct enum_to_type<value_t::array , Value>{using type = typename Value::array_type;};
template<typename Value> struct enum_to_type<value_t::table , Value>{using type = typename Value::table_type;};
// meta-function that converts from an exact toml type to the enum that corresponds to.
template<typename T, typename Value>
struct type_to_enum : std::conditional<
std::is_same<T, typename Value::array_type>::value, // if T == array_type,
value_t_constant<value_t::array>, // then value_t::array
typename std::conditional< // else...
std::is_same<T, typename Value::table_type>::value, // if T == table_type
value_t_constant<value_t::table>, // then value_t::table
value_t_constant<value_t::empty> // else value_t::empty
>::type
>::type {};
template<typename Value> struct type_to_enum<boolean , Value>: value_t_constant<value_t::boolean > {};
template<typename Value> struct type_to_enum<integer , Value>: value_t_constant<value_t::integer > {};
template<typename Value> struct type_to_enum<floating , Value>: value_t_constant<value_t::floating > {};
template<typename Value> struct type_to_enum<string , Value>: value_t_constant<value_t::string > {};
template<typename Value> struct type_to_enum<offset_datetime, Value>: value_t_constant<value_t::offset_datetime> {};
template<typename Value> struct type_to_enum<local_datetime , Value>: value_t_constant<value_t::local_datetime > {};
template<typename Value> struct type_to_enum<local_date , Value>: value_t_constant<value_t::local_date > {};
template<typename Value> struct type_to_enum<local_time , Value>: value_t_constant<value_t::local_time > {};
// meta-function that checks the type T is the same as one of the toml::* types.
template<typename T, typename Value>
struct is_exact_toml_type : disjunction<
std::is_same<T, boolean >,
std::is_same<T, integer >,
std::is_same<T, floating >,
std::is_same<T, string >,
std::is_same<T, offset_datetime>,
std::is_same<T, local_datetime >,
std::is_same<T, local_date >,
std::is_same<T, local_time >,
std::is_same<T, typename Value::array_type>,
std::is_same<T, typename Value::table_type>
>{};
template<typename T, typename V> struct is_exact_toml_type<T&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T const&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T volatile&, V> : is_exact_toml_type<T, V>{};
template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>: is_exact_toml_type<T, V>{};
} // detail
} // toml
#endif// TOML11_TYPES_H

View File

@ -1,150 +0,0 @@
// Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_UTILITY_HPP
#define TOML11_UTILITY_HPP
#include <memory>
#include <sstream>
#include <utility>
#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<typename T, typename ... Ts>
inline std::unique_ptr<T> make_unique(Ts&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
}
#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
namespace detail
{
template<typename Container>
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
{
container.reserve(N);
return;
}
template<typename Container>
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
{
return;
}
} // detail
template<typename Container>
void try_reserve(Container& container, std::size_t N)
{
if(N <= container.size()) {return;}
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
return;
}
namespace detail
{
inline std::string concat_to_string_impl(std::ostringstream& oss)
{
return oss.str();
}
template<typename T, typename ... Ts>
std::string concat_to_string_impl(std::ostringstream& oss, T&& head, Ts&& ... tail)
{
oss << std::forward<T>(head);
return concat_to_string_impl(oss, std::forward<Ts>(tail) ... );
}
} // detail
template<typename ... Ts>
std::string concat_to_string(Ts&& ... args)
{
std::ostringstream oss;
oss << std::boolalpha << std::fixed;
return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
}
template<typename T>
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<typename T>
decltype(auto) last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
{
return last_one(std::forward<Ts>(tail)...);
}
#else // C++11
// The following code
// ```cpp
// 1 | template<typename T, typename ... Ts>
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
// 4 | {
// 5 | return last_one(std::forward<Ts>(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<typename T, typename ... Ts>
struct last_one_in_pack
{
using type = typename last_one_in_pack<Ts...>::type;
};
template<typename T>
struct last_one_in_pack<T>
{
using type = T;
};
template<typename ... Ts>
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
template<typename T>
T&& last_one(T&& tail) noexcept
{
return std::forward<T>(tail);
}
template<typename T, typename ... Ts>
enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
last_one(T&& /*head*/, Ts&& ... tail)
{
return last_one(std::forward<Ts>(tail)...);
}
#endif
} // detail
}// toml
#endif // TOML11_UTILITY

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -0,0 +1,751 @@
#ifndef TOML11_COMPAT_HPP
#define TOML11_COMPAT_HPP
#include "version.hpp"
#include <algorithm>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
#include <cassert>
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE
# if __has_include(<bit>)
# include <bit>
# endif
#endif
#include <cstring>
// ----------------------------------------------------------------------------
#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<typename T, typename ... Ts>
std::unique_ptr<T> make_unique(Ts&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Ts>(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<typename Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator iter)
{
return std::reverse_iterator<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<typename T>
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<typename U, typename T>
U bit_cast(const T& x) noexcept
{
static_assert(sizeof(T) == sizeof(U), "");
static_assert(std::is_default_constructible<T>::value, "");
U z;
std::memcpy(reinterpret_cast<char*>(std::addressof(z)),
reinterpret_cast<const char*>(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<typename T>
struct remove_cvref
{
using type = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
};
template<typename T>
using remove_cvref_t = typename remove_cvref<T>::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<typename ...> struct conjunction : std::true_type{};
template<typename T> struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};
template<typename ...> struct disjunction : std::false_type{};
template<typename T> struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};
template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(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<std::size_t ... Ns> struct index_sequence{};
template<bool B, std::size_t N, typename T>
struct double_index_sequence;
template<std::size_t N, std::size_t ... Is>
struct double_index_sequence<true, N, index_sequence<Is...>>
{
using type = index_sequence<Is..., (Is+N)..., N*2>;
};
template<std::size_t N, std::size_t ... Is>
struct double_index_sequence<false, N, index_sequence<Is...>>
{
using type = index_sequence<Is..., (Is+N)...>;
};
template<std::size_t N>
struct index_sequence_maker
{
using type = typename double_index_sequence<
N % 2 == 1, N/2, typename index_sequence_maker<N/2>::type
>::type;
};
template<>
struct index_sequence_maker<0>
{
using type = index_sequence<>;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N>::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<bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::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<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;
#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;
#endif // TOML11_HAS_STD_INVOKE_RESULT
} // cxx
} // toml
// ----------------------------------------------------------------------------
// (subset of) source_location
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L
# if __has_include(<source_location>)
# 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(<experimental/source_location>)
# 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 <source_location>
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 <experimental/source_location>
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(<optional>)
# include <optional>
# 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<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& 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<typename charT, typename traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& os, const nullopt_t&)
{
os << "nullopt";
return os;
}
template<typename T>
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<typename U, enable_if_t<std::is_constructible<T, U>::value, std::nullptr_t> = nullptr>
explicit optional(U&& x): has_value_(true), value_(std::forward<U>(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<typename U, enable_if_t<conjunction<
negation<std::is_same<T, U>>, std::is_constructible<T, U>
>::value, std::nullptr_t> = nullptr>
explicit optional(const optional<U>& rhs): has_value_(rhs.has_value_), null_('\0')
{
if(rhs.has_value_)
{
this->assigner(rhs.value_);
}
}
template<typename U, enable_if_t<conjunction<
negation<std::is_same<T, U>>, std::is_constructible<T, U>
>::value, std::nullptr_t> = nullptr>
explicit optional(optional<U>&& rhs): has_value_(rhs.has_value_), null_('\0')
{
if(this->has_value_)
{
this->assigner(std::move(rhs.value_));
}
}
template<typename U, enable_if_t<conjunction<
negation<std::is_same<T, U>>, std::is_constructible<T, U>
>::value, std::nullptr_t> = nullptr>
optional& operator=(const optional<U>& 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<typename U, enable_if_t<conjunction<
negation<std::is_same<T, U>>, std::is_constructible<T, U>
>::value, std::nullptr_t> = nullptr>
optional& operator=(optional<U>&& 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<typename U>
void assigner(U&& x)
{
const auto tmp = ::new(std::addressof(this->value_)) value_type(std::forward<U>(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

View File

@ -0,0 +1,68 @@
#ifndef TOML11_CONTEXT_HPP
#define TOML11_CONTEXT_HPP
#include "error_info.hpp"
#include "spec.hpp"
#include <vector>
namespace toml
{
namespace detail
{
template<typename TypeConfig>
class context
{
public:
explicit context(const spec& toml_spec)
: toml_spec_(toml_spec), errors_{}
{}
bool has_error() const noexcept {return !errors_.empty();}
std::vector<error_info> 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<error_info> 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

View File

@ -1,5 +1,105 @@
#ifndef TOML11_MACROS_HPP #ifndef TOML11_CONVERSION_HPP
#define TOML11_MACROS_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 <optional>
namespace toml
{
namespace detail
{
template<typename T>
inline constexpr bool is_optional_v = false;
template<typename T>
inline constexpr bool is_optional_v<std::optional<T>> = true;
template<typename T, typename TC>
void find_member_variable_from_value(T& obj, const basic_value<TC>& v, const char* var_name)
{
if constexpr(is_optional_v<T>)
{
if(v.contains(var_name))
{
obj = toml::find<typename T::value_type>(v, var_name);
}
else
{
obj = std::nullopt;
}
}
else
{
obj = toml::find<T>(v, var_name);
}
}
template<typename T, typename TC>
void assign_member_variable_to_value(const T& obj, basic_value<TC>& v, const char* var_name)
{
if constexpr(is_optional_v<T>)
{
if(obj.has_value())
{
v[var_name] = obj.value();
}
}
else
{
v[var_name] = obj;
}
}
} // detail
} // toml
#else
namespace toml
{
namespace detail
{
template<typename T, typename TC>
void find_member_variable_from_value(T& obj, const basic_value<TC>& v, const char* var_name)
{
obj = toml::find<T>(v, var_name);
}
template<typename T, typename TC>
void assign_member_variable_to_value(const T& obj, basic_value<TC>& 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<foo::Foo>(v)` and `toml::find<foo::Foo>(file, "foo");`
//
#define TOML11_STRINGIZE_AUX(x) #x #define TOML11_STRINGIZE_AUX(x) #x
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x) #define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
@ -65,39 +165,20 @@
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\ #define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__) 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<foo::Foo>(file, "foo");`
//
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\ #define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(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)\ #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, ...)\ #define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
namespace toml { \ namespace toml { \
template<> \ template<> \
struct from<NAME> \ struct from<NAME> \
{ \ { \
template<typename C, template<typename ...> class T, \ template<typename TC> \
template<typename ...> class A> \ static NAME from_toml(const basic_value<TC>& v) \
static NAME from_toml(const basic_value<C, T, A>& v) \
{ \ { \
NAME obj; \ NAME obj; \
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \ TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
@ -107,9 +188,10 @@
template<> \ template<> \
struct into<NAME> \ struct into<NAME> \
{ \ { \
static value into_toml(const NAME& obj) \ template<typename TC> \
static basic_value<TC> into_toml(const NAME& obj) \
{ \ { \
::toml::value v = ::toml::table{}; \ ::toml::basic_value<TC> v = typename ::toml::basic_value<TC>::table_type{}; \
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \ TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
return v; \ return v; \
} \ } \
@ -118,4 +200,4 @@
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE #endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
#endif// TOML11_MACROS_HPP #endif // TOML11_CONVERSION_HPP

View File

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

View File

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

View File

@ -0,0 +1,17 @@
#ifndef TOML11_EXCEPTION_HPP
#define TOML11_EXCEPTION_HPP
#include <exception>
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

377
src/frontend/qt_sdl/toml/toml11/find.hpp vendored Normal file
View File

@ -0,0 +1,377 @@
#ifndef TOML11_FIND_HPP
#define TOML11_FIND_HPP
#include <algorithm>
#include "get.hpp"
#include "value.hpp"
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif
namespace toml
{
// ----------------------------------------------------------------------------
// find<T>(value, key);
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC> const&>()))
find(const basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)
{
return ::toml::get<T>(v.at(ky));
}
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))
find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)
{
return ::toml::get<T>(v.at(ky));
}
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))
find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky)
{
return ::toml::get<T>(std::move(v.at(ky)));
}
// ----------------------------------------------------------------------------
// find<T>(value, idx)
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC> const&>()))
find(const basic_value<TC>& v, const std::size_t idx)
{
return ::toml::get<T>(v.at(idx));
}
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))
find(basic_value<TC>& v, const std::size_t idx)
{
return ::toml::get<T>(v.at(idx));
}
template<typename T, typename TC>
decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))
find(basic_value<TC>&& v, const std::size_t idx)
{
return ::toml::get<T>(std::move(v.at(idx)));
}
// ----------------------------------------------------------------------------
// find(value, key/idx), w/o conversion
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&
find(basic_value<TC>& v, const typename basic_value<TC>::key_type& ky)
{
return v.at(ky);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&
find(basic_value<TC> const& v, const typename basic_value<TC>::key_type& ky)
{
return v.at(ky);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>
find(basic_value<TC>&& v, const typename basic_value<TC>::key_type& ky)
{
return basic_value<TC>(std::move(v.at(ky)));
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&
find(basic_value<TC>& v, const std::size_t idx)
{
return v.at(idx);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&
find(basic_value<TC> const& v, const std::size_t idx)
{
return v.at(idx);
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>
find(basic_value<TC>&& v, const std::size_t idx)
{
return basic_value<TC>(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<typename TC>
std::size_t key_cast(const std::size_t& v) noexcept
{
return v;
}
template<typename TC, typename T>
cxx::enable_if_t<std::is_integral<cxx::remove_cvref_t<T>>::value, std::size_t>
key_cast(const T& v) noexcept
{
return static_cast<std::size_t>(v);
}
// for string-like (string, string literal, string_view)
template<typename TC>
typename basic_value<TC>::key_type const&
key_cast(const typename basic_value<TC>::key_type& v) noexcept
{
return v;
}
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const typename basic_value<TC>::key_type::value_type* v)
{
return typename basic_value<TC>::key_type(v);
}
#if defined(TOML11_HAS_STRING_VIEW)
template<typename TC>
typename basic_value<TC>::key_type
key_cast(const std::string_view v)
{
return typename basic_value<TC>::key_type(v);
}
#endif // string_view
} // detail
// ----------------------------------------------------------------------------
// find(v, keys...)
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&
find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);
}
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&
find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);
}
template<typename TC, typename K1, typename K2, typename ... Ks>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>
find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find(std::move(v.at(detail::key_cast<TC>(k1))), detail::key_cast<TC>(k2), ks...);
}
// ----------------------------------------------------------------------------
// find<T>(v, keys...)
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::get<T>(std::declval<const basic_value<TC>&>()))
find(const basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find<T>(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);
}
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::get<T>(std::declval<basic_value<TC>&>()))
find(basic_value<TC>& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find<T>(v.at(detail::key_cast<TC>(k1)), detail::key_cast<TC>(k2), ks...);
}
template<typename T, typename TC, typename K1, typename K2, typename ... Ks>
decltype(::toml::get<T>(std::declval<basic_value<TC>&&>()))
find(basic_value<TC>&& v, const K1& k1, const K2& k2, const Ks& ... ks)
{
return find<T>(std::move(v.at(detail::key_cast<TC>(k1))), detail::key_cast<TC>(k2), ks...);
}
// ===========================================================================
// find_or<T>(value, key, fallback)
// ---------------------------------------------------------------------------
// find_or(v, key, other_v)
template<typename TC, typename K>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&
find_or(basic_value<TC>& v, const K& k, basic_value<TC>& opt) noexcept
{
try
{
return ::toml::find(v, detail::key_cast<TC>(k));
}
catch(...)
{
return opt;
}
}
template<typename TC, typename K>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&
find_or(const basic_value<TC>& v, const K& k, const basic_value<TC>& opt) noexcept
{
try
{
return ::toml::find(v, detail::key_cast<TC>(k));
}
catch(...)
{
return opt;
}
}
template<typename TC, typename K>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>
find_or(basic_value<TC>&& v, const K& k, basic_value<TC>&& opt) noexcept
{
try
{
return ::toml::find(v, detail::key_cast<TC>(k));
}
catch(...)
{
return opt;
}
}
// ---------------------------------------------------------------------------
// toml types (return type can be a reference)
template<typename T, typename TC, typename K>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,
cxx::remove_cvref_t<T> const&>
find_or(const basic_value<TC>& v, const K& k, const T& opt)
{
try
{
return ::toml::get<T>(v.at(detail::key_cast<TC>(k)));
}
catch(...)
{
return opt;
}
}
template<typename T, typename TC, typename K>
cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_const<T>>,
detail::is_exact_toml_type<T, basic_value<TC>>
>::value, cxx::remove_cvref_t<T>&>
find_or(basic_value<TC>& v, const K& k, T& opt)
{
try
{
return ::toml::get<T>(v.at(detail::key_cast<TC>(k)));
}
catch(...)
{
return opt;
}
}
template<typename T, typename TC, typename K>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value,
cxx::remove_cvref_t<T>>
find_or(basic_value<TC>&& v, const K& k, T opt)
{
try
{
return ::toml::get<T>(std::move(v.at(detail::key_cast<TC>(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<T>(),
// we restrict the string type as std::string.
template<typename TC, typename K>
cxx::enable_if_t<detail::is_type_config<TC>::value, std::string>
find_or(const basic_value<TC>& v, const K& k, const char* opt)
{
try
{
return ::toml::get<std::string>(v.at(detail::key_cast<TC>(k)));
}
catch(...)
{
return std::string(opt);
}
}
// ---------------------------------------------------------------------------
// other types (requires type conversion and return type cannot be a reference)
template<typename T, typename TC, typename K>
cxx::enable_if_t<cxx::conjunction<
cxx::negation<detail::is_basic_value<cxx::remove_cvref_t<T>>>,
detail::is_not_toml_type<cxx::remove_cvref_t<T>, basic_value<TC>>,
cxx::negation<std::is_same<cxx::remove_cvref_t<T>,
const typename basic_value<TC>::string_type::value_type*>>
>::value, cxx::remove_cvref_t<T>>
find_or(const basic_value<TC>& v, const K& ky, T opt)
{
try
{
return ::toml::get<cxx::remove_cvref_t<T>>(v.at(detail::key_cast<TC>(ky)));
}
catch(...)
{
return cxx::remove_cvref_t<T>(std::move(opt));
}
}
// ----------------------------------------------------------------------------
// recursive
namespace detail
{
template<typename ...Ts>
auto last_one(Ts&&... args)
-> decltype(std::get<sizeof...(Ts)-1>(std::forward_as_tuple(std::forward<Ts>(args)...)))
{
return std::get<sizeof...(Ts)-1>(std::forward_as_tuple(std::forward<Ts>(args)...));
}
} // detail
template<typename Value, typename K1, typename K2, typename K3, typename ... Ks>
auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&& ... keys) noexcept
-> cxx::enable_if_t<
detail::is_basic_value<cxx::remove_cvref_t<Value>>::value,
decltype(find_or(v, k2, std::forward<K3>(k3), std::forward<Ks>(keys)...))
>
{
try
{
return find_or(v.at(k1), k2, std::forward<K3>(k3), std::forward<Ks>(keys)...);
}
catch(...)
{
return detail::last_one(k3, keys...);
}
}
template<typename T, typename TC, typename K1, typename K2, typename K3, typename ... Ks>
T find_or(const basic_value<TC>& v, const K1& k1, const K2& k2, const K3& k3, const Ks& ... keys) noexcept
{
try
{
return find_or<T>(v.at(k1), k2, k3, keys...);
}
catch(...)
{
return static_cast<T>(detail::last_one(k3, keys...));
}
}
} // toml
#endif // TOML11_FIND_HPP

View File

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

View File

@ -1,5 +1,3 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_FROM_HPP #ifndef TOML11_FROM_HPP
#define TOML11_FROM_HPP #define TOML11_FROM_HPP

View File

@ -0,0 +1,88 @@
#ifndef TOML11_COLOR_FWD_HPP
#define TOML11_COLOR_FWD_HPP
#include <iosfwd>
#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

View File

@ -1,7 +1,10 @@
// Copyright Toru Niina 2019. #ifndef TOML11_COMMENTS_FWD_HPP
// Distributed under the MIT License. #define TOML11_COMMENTS_FWD_HPP
#ifndef TOML11_COMMENTS_HPP
#define TOML11_COMMENTS_HPP // to use __has_builtin
#include "../version.hpp" // IWYU pragma: keep
#include <exception>
#include <initializer_list> #include <initializer_list>
#include <iterator> #include <iterator>
#include <stdexcept> #include <stdexcept>
@ -9,12 +12,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <ostream>
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
#else
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
#endif
// This file provides mainly two classes, `preserve_comments` and `discard_comments`. // This file provides mainly two classes, `preserve_comments` and `discard_comments`.
// Those two are a container that have the same interface as `std::vector<std::string>` // Those two are a container that have the same interface as `std::vector<std::string>`
@ -25,16 +23,11 @@
// error whenever you access to the element. // error whenever you access to the element.
namespace toml namespace toml
{ {
struct discard_comments; // forward decl class discard_comments; // forward decl
// use it in the following way class preserve_comments
//
// const toml::basic_value<toml::preserve_comments> data =
// toml::parse<toml::preserve_comments>("example.toml");
//
// the interface is almost the same as std::vector<std::string>.
struct preserve_comments
{ {
public:
// `container_type` is not provided in discard_comments. // `container_type` is not provided in discard_comments.
// do not use this inner-type in a generic code. // do not use this inner-type in a generic code.
using container_type = std::vector<std::string>; using container_type = std::vector<std::string>;
@ -51,6 +44,8 @@ struct preserve_comments
using reverse_iterator = container_type::reverse_iterator; using reverse_iterator = container_type::reverse_iterator;
using const_reverse_iterator = container_type::const_reverse_iterator; using const_reverse_iterator = container_type::const_reverse_iterator;
public:
preserve_comments() = default; preserve_comments() = default;
~preserve_comments() = default; ~preserve_comments() = default;
preserve_comments(preserve_comments const&) = default; preserve_comments(preserve_comments const&) = default;
@ -90,11 +85,9 @@ struct preserve_comments
// Related to the issue #97. // Related to the issue #97.
// //
// It is known that `std::vector::insert` and `std::vector::erase` in // `std::vector::insert` and `std::vector::erase` in the STL implementation
// the standard library implementation included in GCC 4.8.5 takes // included in GCC 4.8.5 takes `std::vector::iterator` instead of
// `std::vector::iterator` instead of `std::vector::const_iterator`. // `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5.
// Because of the const-correctness, we cannot convert a `const_iterator` to
// an `iterator`. It causes compilation error in GCC 4.8.5.
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__) #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805 # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION # define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
@ -233,39 +226,18 @@ struct preserve_comments
container_type comments; container_type 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);
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);
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);
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);
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);
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);
inline void swap(preserve_comments& lhs, preserve_comments& rhs) void swap(preserve_comments& lhs, preserve_comments& rhs);
{ void swap(preserve_comments& lhs, std::vector<std::string>& rhs);
lhs.swap(rhs); void swap(std::vector<std::string>& lhs, preserve_comments& rhs);
return;
}
inline void swap(preserve_comments& lhs, std::vector<std::string>& rhs)
{
lhs.comments.swap(rhs);
return;
}
inline void swap(std::vector<std::string>& lhs, preserve_comments& rhs)
{
lhs.swap(rhs.comments);
return;
}
template<typename charT, typename traits> std::ostream& operator<<(std::ostream& os, const preserve_comments& com);
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const preserve_comments& com)
{
for(const auto& c : com)
{
os << '#' << c << '\n';
}
return os;
}
namespace detail namespace detail
{ {
@ -349,8 +321,9 @@ operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::differ
// efficiency, this is chosen as a default. // efficiency, this is chosen as a default.
// //
// To reduce the memory footprint, later we can try empty base optimization (EBO). // 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 size_type = std::size_t;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = std::string; using value_type = std::string;
@ -363,6 +336,7 @@ struct discard_comments
using reverse_iterator = detail::empty_iterator<std::string, false>; using reverse_iterator = detail::empty_iterator<std::string, false>;
using const_reverse_iterator = detail::empty_iterator<std::string, true>; using const_reverse_iterator = detail::empty_iterator<std::string, true>;
public:
discard_comments() = default; discard_comments() = default;
~discard_comments() = default; ~discard_comments() = default;
discard_comments(discard_comments const&) = default; discard_comments(discard_comments const&) = default;
@ -425,14 +399,14 @@ struct discard_comments
// empty, so accessing through operator[], front/back, data causes address // empty, so accessing through operator[], front/back, data causes address
// error. // error.
reference operator[](const size_type) noexcept {return *data();} reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
const_reference operator[](const size_type) const noexcept {return *data();} 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.");} 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.");} const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
reference front() noexcept {return *data();} reference front() noexcept {never_call("toml::discard_comment::front");}
const_reference front() const noexcept {return *data();} const_reference front() const noexcept {never_call("toml::discard_comment::front");}
reference back() noexcept {return *data();} reference back() noexcept {never_call("toml::discard_comment::back");}
const_reference back() const noexcept {return *data();} const_reference back() const noexcept {never_call("toml::discard_comment::back");}
pointer data() noexcept {return nullptr;} pointer data() noexcept {return nullptr;}
const_pointer data() const 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 rend() const noexcept {return const_iterator{};}
const_reverse_iterator crbegin() const noexcept {return const_iterator{};} const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
const_reverse_iterator crend() 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;} 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;} inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}
template<typename charT, typename traits> inline std::ostream& operator<<(std::ostream& os, const discard_comments&) {return os;}
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const discard_comments&)
{
return os;
}
} // toml11 } // toml11
#endif// TOML11_COMMENTS_HPP #endif // TOML11_COMMENTS_FWD_HPP

View File

@ -0,0 +1,261 @@
#ifndef TOML11_DATETIME_FWD_HPP
#define TOML11_DATETIME_FWD_HPP
#include <chrono>
#include <iosfwd>
#include <string>
#include <cstdint>
#include <cstdlib>
#include <ctime>
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<std::int16_t>(y)},
month{static_cast<std::uint8_t>(m)},
day {static_cast<std::uint8_t>(d)}
{}
explicit local_date(const std::tm& t)
: year {static_cast<std::int16_t>(t.tm_year + 1900)},
month{static_cast<std::uint8_t>(t.tm_mon)},
day {static_cast<std::uint8_t>(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<std::uint8_t>(h)},
minute{static_cast<std::uint8_t>(m)},
second{static_cast<std::uint8_t>(s)},
millisecond{static_cast<std::uint16_t>(ms)},
microsecond{static_cast<std::uint16_t>(us)},
nanosecond {static_cast<std::uint16_t>(ns)}
{}
explicit local_time(const std::tm& t)
: hour {static_cast<std::uint8_t>(t.tm_hour)},
minute{static_cast<std::uint8_t>(t.tm_min )},
second{static_cast<std::uint8_t>(t.tm_sec )},
millisecond{0}, microsecond{0}, nanosecond{0}
{}
template<typename Rep, typename Period>
explicit local_time(const std::chrono::duration<Rep, Period>& t)
{
const auto h = std::chrono::duration_cast<std::chrono::hours>(t);
this->hour = static_cast<std::uint8_t>(h.count());
const auto t2 = t - h;
const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);
this->minute = static_cast<std::uint8_t>(m.count());
const auto t3 = t2 - m;
const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);
this->second = static_cast<std::uint8_t>(s.count());
const auto t4 = t3 - s;
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);
this->millisecond = static_cast<std::uint16_t>(ms.count());
const auto t5 = t4 - ms;
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);
this->microsecond = static_cast<std::uint16_t>(us.count());
const auto t6 = t5 - us;
const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);
this->nanosecond = static_cast<std::uint16_t>(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<std::int8_t>(h)},
minute{static_cast<std::int8_t>(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

View File

@ -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<std::pair<source_location, std::string>> 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<std::pair<source_location, std::string>> 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<std::pair<source_location, std::string>> locations_;
std::string suffix_; // hint or something like that
};
// forward decl
template<typename TypeConfig>
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<typename TC, typename ... Ts>
error_info make_error_info_rec(error_info e,
const basic_value<TC>& v, std::string msg, Ts&& ... tail);
template<typename ... Ts>
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<Ts>(tail)...);
}
} // detail
template<typename ... Ts>
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<Ts>(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<typename ... Ts>
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<Ts>(tail)...));
}
std::ostream& operator<<(std::ostream& os, const error_info& e);
} // toml
#endif // TOML11_ERROR_INFO_FWD_HPP

View File

@ -0,0 +1,250 @@
#ifndef TOML11_FORMAT_FWD_HPP
#define TOML11_FORMAT_FWD_HPP
#include <iosfwd>
#include <string>
#include <utility>
#include <cstddef>
#include <cstdint>
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<typename T, typename F>
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<typename U>
value_with_format(value_with_format<U, format_type> 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

View File

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

View File

@ -0,0 +1,145 @@
#ifndef TOML11_LOCATION_FWD_HPP
#define TOML11_LOCATION_FWD_HPP
#include "../result.hpp"
#include <memory>
#include <string>
#include <vector>
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<char_type>;
using difference_type = typename container_type::difference_type; // to suppress sign-conversion warning
using source_ptr = std::shared_ptr<const container_type>;
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<bool>(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<typename F>
result<location, none_t>
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<typename F>
result<location, none_t>
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<location, none_t> find(const location& first, const location& last,
const location::char_type val);
result<location, none_t> 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

View File

@ -0,0 +1,104 @@
#ifndef TOML11_REGION_FWD_HPP
#define TOML11_REGION_FWD_HPP
#include "../location.hpp"
#include <string>
#include <vector>
#include <cassert>
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<bool>(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<std::string> 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

View File

@ -0,0 +1,391 @@
#ifndef TOML11_SCANNER_FWD_HPP
#define TOML11_SCANNER_FWD_HPP
#include "../region.hpp"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <cassert>
#include <cstdio>
#include <cctype>
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<typename Scanner, cxx::enable_if_t<
std::is_base_of<scanner_base, cxx::remove_cvref_t<Scanner>>::value,
std::nullptr_t> = nullptr>
explicit scanner_storage(Scanner&& s)
: scanner_(cxx::make_unique<cxx::remove_cvref_t<Scanner>>(std::forward<Scanner>(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<bool>(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_base> 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<char_type> cs) noexcept
: chars_(std::move(cs))
{
assert(! this->chars_.empty());
}
template<std::size_t N>
explicit character_either(const char (&cs)[N]) noexcept
: chars_(N-1, '\0')
{
static_assert(N >= 1, "");
for(std::size_t i=0; i+1<N; ++i)
{
chars_.at(i) = char_type(cs[i]);
}
}
~character_either() override = default;
region scan(location& loc) const override;
std::string expected_chars(location&) const override;
scanner_base* clone() const override;
void push_back(const char_type c);
std::string name() const override;
private:
std::vector<char_type> 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<std::size_t N>
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<typename ... Ts>
explicit sequence(Ts&& ... args)
{
push_back_all(std::forward<Ts>(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<typename Scanner>
void push_back(Scanner&& other_scanner)
{
this->others_.emplace_back(std::forward<Scanner>(other_scanner));
}
std::string name() const override;
private:
void push_back_all()
{
return;
}
template<typename T, typename ... Ts>
void push_back_all(T&& head, Ts&& ... args)
{
others_.emplace_back(std::forward<T>(head));
push_back_all(std::forward<Ts>(args)...);
return;
}
private:
std::vector<scanner_storage> others_;
};
// ----------------------------------------------------------------------------
class either final: public scanner_base
{
public:
using char_type = location::char_type;
public:
template<typename ... Ts>
explicit either(Ts&& ... args)
{
push_back_all(std::forward<Ts>(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<typename Scanner>
void push_back(Scanner&& other_scanner)
{
this->others_.emplace_back(std::forward<Scanner>(other_scanner));
}
std::string name() const override;
private:
void push_back_all()
{
return;
}
template<typename T, typename ... Ts>
void push_back_all(T&& head, Ts&& ... args)
{
others_.emplace_back(std::forward<T>(head));
push_back_all(std::forward<Ts>(args)...);
return;
}
private:
std::vector<scanner_storage> others_;
};
// ----------------------------------------------------------------------------
class repeat_exact final: public scanner_base
{
public:
using char_type = location::char_type;
public:
template<typename Scanner>
repeat_exact(const std::size_t length, Scanner&& other)
: length_(length), other_(std::forward<Scanner>(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<typename Scanner>
repeat_at_least(const std::size_t length, Scanner&& s)
: length_(length), other_(std::forward<Scanner>(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<typename Scanner>
explicit maybe(Scanner&& s)
: other_(std::forward<Scanner>(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

View File

@ -0,0 +1,115 @@
#ifndef TOML11_SOURCE_LOCATION_FWD_HPP
#define TOML11_SOURCE_LOCATION_FWD_HPP
#include "../region.hpp"
#include <sstream>
#include <string>
#include <vector>
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<std::string> 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<std::string> 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<typename ... Ts>
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<typename ... Ts>
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<typename ... Ts>
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

View File

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

View File

@ -0,0 +1,117 @@
#ifndef TOML11_VALUE_T_FWD_HPP
#define TOML11_VALUE_T_FWD_HPP
#include "../compat.hpp"
#include "../format.hpp"
#include <iosfwd>
#include <string>
#include <type_traits>
#include <cstdint>
namespace toml
{
// forward decl
template<typename TypeConfig>
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<value_t V>
using value_t_constant = std::integral_constant<value_t, V>;
template<typename T, typename Value>
struct type_to_enum : value_t_constant<value_t::empty> {};
template<typename V> struct type_to_enum<typename V::boolean_type , V> : value_t_constant<value_t::boolean > {};
template<typename V> struct type_to_enum<typename V::integer_type , V> : value_t_constant<value_t::integer > {};
template<typename V> struct type_to_enum<typename V::floating_type , V> : value_t_constant<value_t::floating > {};
template<typename V> struct type_to_enum<typename V::string_type , V> : value_t_constant<value_t::string > {};
template<typename V> struct type_to_enum<typename V::offset_datetime_type, V> : value_t_constant<value_t::offset_datetime> {};
template<typename V> struct type_to_enum<typename V::local_datetime_type , V> : value_t_constant<value_t::local_datetime > {};
template<typename V> struct type_to_enum<typename V::local_date_type , V> : value_t_constant<value_t::local_date > {};
template<typename V> struct type_to_enum<typename V::local_time_type , V> : value_t_constant<value_t::local_time > {};
template<typename V> struct type_to_enum<typename V::array_type , V> : value_t_constant<value_t::array > {};
template<typename V> struct type_to_enum<typename V::table_type , V> : value_t_constant<value_t::table > {};
template<value_t V, typename Value>
struct enum_to_type { using type = void; };
template<typename V> struct enum_to_type<value_t::boolean , V> { using type = typename V::boolean_type ; };
template<typename V> struct enum_to_type<value_t::integer , V> { using type = typename V::integer_type ; };
template<typename V> struct enum_to_type<value_t::floating , V> { using type = typename V::floating_type ; };
template<typename V> struct enum_to_type<value_t::string , V> { using type = typename V::string_type ; };
template<typename V> struct enum_to_type<value_t::offset_datetime, V> { using type = typename V::offset_datetime_type; };
template<typename V> struct enum_to_type<value_t::local_datetime , V> { using type = typename V::local_datetime_type ; };
template<typename V> struct enum_to_type<value_t::local_date , V> { using type = typename V::local_date_type ; };
template<typename V> struct enum_to_type<value_t::local_time , V> { using type = typename V::local_time_type ; };
template<typename V> struct enum_to_type<value_t::array , V> { using type = typename V::array_type ; };
template<typename V> struct enum_to_type<value_t::table , V> { using type = typename V::table_type ; };
template<value_t V, typename Value>
using enum_to_type_t = typename enum_to_type<V, Value>::type;
template<value_t V>
struct enum_to_fmt_type { using type = void; };
template<> struct enum_to_fmt_type<value_t::boolean > { using type = boolean_format_info ; };
template<> struct enum_to_fmt_type<value_t::integer > { using type = integer_format_info ; };
template<> struct enum_to_fmt_type<value_t::floating > { using type = floating_format_info ; };
template<> struct enum_to_fmt_type<value_t::string > { using type = string_format_info ; };
template<> struct enum_to_fmt_type<value_t::offset_datetime> { using type = offset_datetime_format_info; };
template<> struct enum_to_fmt_type<value_t::local_datetime > { using type = local_datetime_format_info ; };
template<> struct enum_to_fmt_type<value_t::local_date > { using type = local_date_format_info ; };
template<> struct enum_to_fmt_type<value_t::local_time > { using type = local_time_format_info ; };
template<> struct enum_to_fmt_type<value_t::array > { using type = array_format_info ; };
template<> struct enum_to_fmt_type<value_t::table > { using type = table_format_info ; };
template<value_t V>
using enum_to_fmt_type_t = typename enum_to_fmt_type<V>::type;
template<typename T, typename Value>
struct is_exact_toml_type0 : cxx::disjunction<
std::is_same<T, typename Value::boolean_type >,
std::is_same<T, typename Value::integer_type >,
std::is_same<T, typename Value::floating_type >,
std::is_same<T, typename Value::string_type >,
std::is_same<T, typename Value::offset_datetime_type>,
std::is_same<T, typename Value::local_datetime_type >,
std::is_same<T, typename Value::local_date_type >,
std::is_same<T, typename Value::local_time_type >,
std::is_same<T, typename Value::array_type >,
std::is_same<T, typename Value::table_type >
>{};
template<typename T, typename V> struct is_exact_toml_type: is_exact_toml_type0<cxx::remove_cvref_t<T>, V> {};
template<typename T, typename V> struct is_not_toml_type : cxx::negation<is_exact_toml_type<T, V>> {};
} // namespace detail
} // namespace toml
#endif // TOML11_VALUE_T_FWD_HPP

632
src/frontend/qt_sdl/toml/toml11/get.hpp vendored Normal file
View File

@ -0,0 +1,632 @@
#ifndef TOML11_GET_HPP
#define TOML11_GET_HPP
#include <algorithm>
#include "from.hpp"
#include "types.hpp"
#include "value.hpp"
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif // string_view
namespace toml
{
// ============================================================================
// T is toml::value; identity transformation.
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T>&
get(basic_value<TC>& v)
{
return v;
}
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T> const&
get(const basic_value<TC>& v)
{
return v;
}
template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, basic_value<TC>>::value, T>
get(basic_value<TC>&& v)
{
return basic_value<TC>(std::move(v));
}
// ============================================================================
// exact toml::* type
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T> &
get(basic_value<TC>& v)
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
return detail::getter<TC, ty>::get(v);
}
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T> const&
get(const basic_value<TC>& v)
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
return detail::getter<TC, ty>::get(v);
}
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<T, basic_value<TC>>::value, T>
get(basic_value<TC>&& v)
{
constexpr auto ty = detail::type_to_enum<T, basic_value<TC>>::value;
return detail::getter<TC, ty>::get(std::move(v));
}
// ============================================================================
// T is toml::basic_value<U>
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_basic_value<T>,
cxx::negation<std::is_same<T, basic_value<TC>>>
>::value, T>
get(basic_value<TC> v)
{
return T(std::move(v));
}
// ============================================================================
// integer convertible from toml::value::integer_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_integral<T>,
cxx::negation<std::is_same<T, bool>>,
detail::is_not_toml_type<T, basic_value<TC>>,
cxx::negation<detail::has_from_toml_method<T, TC>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, T>
get(const basic_value<TC>& v)
{
return static_cast<T>(v.as_integer());
}
// ============================================================================
// floating point convertible from toml::value::floating_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_floating_point<T>,
detail::is_not_toml_type<T, basic_value<TC>>,
cxx::negation<detail::has_from_toml_method<T, TC>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, T>
get(const basic_value<TC>& v)
{
return static_cast<T>(v.as_floating());
}
// ============================================================================
// std::string with different char/trait/allocator
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_not_toml_type<T, basic_value<TC>>,
detail::is_1byte_std_basic_string<T>
>::value, T>
get(const basic_value<TC>& v)
{
return detail::string_conv<cxx::remove_cvref_t<T>>(v.as_string());
}
// ============================================================================
// std::string_view
#if defined(TOML11_HAS_STRING_VIEW)
template<typename T, typename TC>
cxx::enable_if_t<detail::is_string_view_of<T, typename basic_value<TC>::string_type>::value, T>
get(const basic_value<TC>& v)
{
return T(v.as_string());
}
#endif // string_view
// ============================================================================
// std::chrono::duration from toml::local_time
template<typename T, typename TC>
cxx::enable_if_t<detail::is_chrono_duration<T>::value, T>
get(const basic_value<TC>& v)
{
return std::chrono::duration_cast<T>(
std::chrono::nanoseconds(v.as_local_time()));
}
// ============================================================================
// std::chrono::system_clock::time_point from toml::datetime variants
template<typename T, typename TC>
cxx::enable_if_t<
std::is_same<std::chrono::system_clock::time_point, T>::value, T>
get(const basic_value<TC>& 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<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>&);
// std::array
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_array<T>::value, T>
get(const basic_value<TC>&);
// std::forward_list
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_forward_list<T>::value, T>
get(const basic_value<TC>&);
// std::pair<T1, T2>
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_pair<T>::value, T>
get(const basic_value<TC>&);
// std::tuple<T1, T2, ...>
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_tuple<T>::value, T>
get(const basic_value<TC>&);
// std::map<key, value> (key is convertible from toml::value::key_type)
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>, // keys are convertible
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& v);
// std::map<key, value> (key is not convertible from toml::value::key_type, but
// is a std::basic_string)
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>>, // keys are NOT convertible
detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& v);
// toml::from<T>::from_toml(v)
template<typename T, typename TC>
cxx::enable_if_t<detail::has_specialized_from<T>::value, T>
get(const basic_value<TC>&);
// has T.from_toml(v) but no from<T>
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::has_from_toml_method<T, TC>, // has T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
std::is_default_constructible<T> // T{} works
>::value, T>
get(const basic_value<TC>&);
// T(const toml::value&) and T is not toml::basic_value,
// and it does not have `from<T>` nor `from_toml`.
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_constructible<T, const basic_value<TC>&>, // has T(const basic_value&)
cxx::negation<detail::is_basic_value<T>>, // but not basic_value itself
cxx::negation<detail::has_from_toml_method<T, TC>>, // no .from_toml()
cxx::negation<detail::has_specialized_from<T>> // no toml::from<T>
>::value, T>
get(const basic_value<TC>&);
// ============================================================================
// array-like types; most likely STL container, like std::vector, etc.
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& 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<value_type>(elem));
}
return container;
}
// ============================================================================
// std::array
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_array<T>::value, T>
get(const basic_value<TC>& 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.size(); ++i)
{
container.at(i) = ::toml::get<value_type>(a.at(i));
}
return container;
}
// ============================================================================
// std::forward_list
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_forward_list<T>::value, T>
get(const basic_value<TC>& v)
{
using value_type = typename T::value_type;
T container;
for(const auto& elem : v.as_array())
{
container.push_front(get<value_type>(elem));
}
container.reverse();
return container;
}
// ============================================================================
// std::pair
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_pair<T>::value, T>
get(const basic_value<TC>& 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<first_type >(ar.at(0)),
::toml::get<second_type>(ar.at(1)));
}
// ============================================================================
// std::tuple.
namespace detail
{
template<typename T, typename Array, std::size_t ... I>
T get_tuple_impl(const Array& a, cxx::index_sequence<I...>)
{
return std::make_tuple(
::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
}
} // detail
template<typename T, typename TC>
cxx::enable_if_t<detail::is_std_tuple<T>::value, T>
get(const basic_value<TC>& v)
{
const auto& ar = v.as_array();
if(ar.size() != std::tuple_size<T>::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<T>::value) + " elements in toml array.",
loc, "here"));
}
return detail::get_tuple_impl<T>(ar,
cxx::make_index_sequence<std::tuple_size<T>::value>{});
}
// ============================================================================
// map-like types; most likely STL map, like std::map or std::unordered_map.
// key is convertible from toml::value::key_type
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>, // keys are convertible
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& v)
{
using key_type = typename T::key_type;
using mapped_type = typename T::mapped_type;
static_assert(
std::is_convertible<typename basic_value<TC>::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<mapped_type>(kv.second));
}
return m;
}
// key is NOT convertible from toml::value::key_type but std::basic_string
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_map<T>, // T is map
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::table
cxx::negation<std::is_convertible<typename basic_value<TC>::key_type,
typename T::key_type>>, // keys are NOT convertible
detail::is_1byte_std_basic_string<typename T::key_type>, // is std::basic_string
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
>::value, T>
get(const basic_value<TC>& 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<key_type>(kv.first), get<mapped_type>(kv.second));
}
return m;
}
// ============================================================================
// user-defined, but convertible types.
// toml::from<T>
template<typename T, typename TC>
cxx::enable_if_t<detail::has_specialized_from<T>::value, T>
get(const basic_value<TC>& v)
{
return ::toml::from<T>::from_toml(v);
}
// has T.from_toml(v) but no from<T>
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::has_from_toml_method<T, TC>, // has T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
std::is_default_constructible<T> // T{} works
>::value, T>
get(const basic_value<TC>& 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<T>` nor `from_toml`.
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
std::is_constructible<T, const basic_value<TC>&>, // has T(const basic_value&)
cxx::negation<detail::is_basic_value<T>>, // but not basic_value itself
cxx::negation<detail::has_from_toml_method<T, TC>>, // no .from_toml()
cxx::negation<detail::has_specialized_from<T>> // no toml::from<T>
>::value, T>
get(const basic_value<TC>& v)
{
return T(v);
}
// ============================================================================
// get_or(value, fallback)
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>> const&
get_or(const basic_value<TC>& v, const basic_value<TC>&)
{
return v;
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>&
get_or(basic_value<TC>& v, basic_value<TC>&)
{
return v;
}
template<typename TC>
cxx::enable_if_t<detail::is_type_config<TC>::value, basic_value<TC>>
get_or(basic_value<TC>&& v, basic_value<TC>&&)
{
return v;
}
// ----------------------------------------------------------------------------
// specialization for the exact toml types (return type becomes lvalue ref)
template<typename T, typename TC>
cxx::enable_if_t<
detail::is_exact_toml_type<T, basic_value<TC>>::value, T> const&
get_or(const basic_value<TC>& v, const T& opt) noexcept
{
try
{
return get<cxx::remove_cvref_t<T>>(v);
}
catch(...)
{
return opt;
}
}
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_const<T>>,
detail::is_exact_toml_type<T, basic_value<TC>>
>::value, T>&
get_or(basic_value<TC>& v, T& opt) noexcept
{
try
{
return get<cxx::remove_cvref_t<T>>(v);
}
catch(...)
{
return opt;
}
}
template<typename T, typename TC>
cxx::enable_if_t<detail::is_exact_toml_type<cxx::remove_cvref_t<T>,
basic_value<TC>>::value, cxx::remove_cvref_t<T>>
get_or(basic_value<TC>&& v, T&& opt) noexcept
{
try
{
return get<cxx::remove_cvref_t<T>>(std::move(v));
}
catch(...)
{
return cxx::remove_cvref_t<T>(std::forward<T>(opt));
}
}
// ----------------------------------------------------------------------------
// specialization for string literal
// template<std::size_t N, typename TC>
// typename basic_value<TC>::string_type
// get_or(const basic_value<TC>& v,
// const typename basic_value<TC>::string_type::value_type (&opt)[N])
// {
// try
// {
// return v.as_string();
// }
// catch(...)
// {
// return typename basic_value<TC>::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 TC>
typename basic_value<TC>::string_type
get_or(const basic_value<TC>& v,
const typename basic_value<TC>::string_type::value_type* opt)
{
try
{
return v.as_string();
}
catch(...)
{
return typename basic_value<TC>::string_type(opt);
}
}
// ----------------------------------------------------------------------------
// others (require type conversion and return type cannot be lvalue reference)
template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
cxx::negation<detail::is_basic_value<T>>,
cxx::negation<detail::is_exact_toml_type<T, basic_value<TC>>>,
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, typename basic_value<TC>::string_type::value_type const*>>
>::value, cxx::remove_cvref_t<T>>
get_or(const basic_value<TC>& v, T&& opt)
{
try
{
return get<cxx::remove_cvref_t<T>>(v);
}
catch(...)
{
return cxx::remove_cvref_t<T>(std::forward<T>(opt));
}
}
} // toml
#endif // TOML11_GET_HPP

View File

@ -0,0 +1,76 @@
#ifndef TOML11_COLOR_IMPL_HPP
#define TOML11_COLOR_IMPL_HPP
#include "../fwd/color_fwd.hpp"
#include "../version.hpp"
#include <ostream>
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

View File

@ -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<std::string>& rhs)
{
lhs.comments.swap(rhs);
return;
}
TOML11_INLINE void swap(std::vector<std::string>& 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

View File

@ -0,0 +1,518 @@
#ifndef TOML11_DATETIME_IMPL_HPP
#define TOML11_DATETIME_IMPL_HPP
#include "../fwd/datetime_fwd.hpp"
#include "../version.hpp"
#include <array>
#include <iomanip>
#include <ostream>
#include <sstream>
#include <tuple>
#include <cstdlib>
#include <ctime>
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<int>(this->day);
t.tm_mon = static_cast<int>(this->month);
t.tm_year = static_cast<int>(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<int>(date.year ) << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
os << std::setfill('0') << std::setw(2) << static_cast<int>(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<int>(time.hour ) << ':';
os << std::setfill('0') << std::setw(2) << static_cast<int>(time.minute) << ':';
os << std::setfill('0') << std::setw(2) << static_cast<int>(time.second);
if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0)
{
os << '.';
os << std::setfill('0') << std::setw(3) << static_cast<int>(time.millisecond);
if(time.microsecond != 0 || time.nanosecond != 0)
{
os << std::setfill('0') << std::setw(3) << static_cast<int>(time.microsecond);
if(time.nanosecond != 0)
{
os << std::setfill('0') << std::setw(3) << static_cast<int>(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<int>(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(&ltime));
this->time.millisecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
this->time.microsecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
this->time.nanosecond = static_cast<std::uint16_t>(
std::chrono::duration_cast<std::chrono::nanoseconds >(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<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(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<internal_duration>(
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<int>(this->time.second);
t.tm_min = static_cast<int>(this->time.minute);
t.tm_hour = static_cast<int>(this->time.hour);
t.tm_mday = static_cast<int>(this->date.day);
t.tm_mon = static_cast<int>(this->date.month);
t.tm_year = static_cast<int>(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<internal_duration>(
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<char, 6> 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

View File

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

View File

@ -0,0 +1,297 @@
#ifndef TOML11_FORMAT_IMPL_HPP
#define TOML11_FORMAT_IMPL_HPP
#include "../fwd/format_fwd.hpp"
#include "../version.hpp"
#include <ostream>
#include <sstream>
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<std::uint8_t>(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<std::uint8_t>(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<std::uint8_t>(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<std::uint8_t>(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<std::uint8_t>(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<std::uint8_t>(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<std::uint8_t>(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

View File

@ -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<type_config> 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<sp.value().comments.size(); ++i)
{
val.comments().push_back(std::move(sp.value().comments.at(i)));
}
}
return val;
}
// to distinguish arrays and tables, first check it is a table or not.
//
// "[1,2,3]"_toml; // json: [1, 2, 3]
// "[table]"_toml; // json: {"table": {}}
// "[[1,2,3]]"_toml; // json: [[1, 2, 3]]
// "[[table]]"_toml; // json: {"table": [{}]}
//
// "[[1]]"_toml; // json: {"1": [{}]}
// "1 = [{}]"_toml; // json: {"1": [{}]}
// "[[1,]]"_toml; // json: [[1]]
// "[[1],]"_toml; // json: [[1]]
const auto val_start = loc;
const bool is_table_key = syntax::std_table(s).scan(loc).is_ok();
loc = val_start;
const bool is_aots_key = syntax::array_table(s).scan(loc).is_ok();
loc = val_start;
// 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)
{
auto data = parse_value(loc, ctx);
if(data.is_ok())
{
auto val = std::move(data.unwrap());
if(sp.has_value())
{
for(std::size_t i=0; i<sp.value().comments.size(); ++i)
{
val.comments().push_back(std::move(sp.value().comments.at(i)));
}
}
auto com_res = parse_comment_line(loc, ctx);
if(com_res.is_ok() && com_res.unwrap().has_value())
{
val.comments().push_back(com_res.unwrap().value());
}
return val;
}
}
// -------------------------------------------------------------------------
// Note that still it can be a table, because the literal might be something
// like the following.
// ```cpp
// // c++11 raw-string literal
// const auto val = R"(
// key = "value"
// int = 42
// )"_toml;
// ```
// It is a valid toml file.
// It should be parsed as if we parse a file with this content.
loc = front;
auto data = parse_file(loc, ctx);
if(data.is_ok())
{
return data.unwrap();
}
else // not a value && not a file. error.
{
std::string msg;
for(const auto& err : data.unwrap_err())
{
msg += format_error(err);
}
throw ::toml::syntax_error(std::move(msg), std::move(data.unwrap_err()));
}
}
} // detail
inline namespace literals
{
inline namespace toml_literals
{
TOML11_INLINE ::toml::value
operator"" _toml(const char* str, std::size_t len)
{
if(len == 0)
{
return ::toml::value{};
}
::toml::detail::location::container_type c(len);
std::copy(reinterpret_cast<const ::toml::detail::location::char_type*>(str),
reinterpret_cast<const ::toml::detail::location::char_type*>(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<const toml::detail::location::container_type>(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<const ::toml::detail::location::char_type*>(str),
reinterpret_cast<const ::toml::detail::location::char_type*>(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<const toml::detail::location::container_type>(std::move(c)),
"TOML literal encoded in a C++ code"));
}
#endif
} // toml_literals
} // literals
} // toml
#endif // TOML11_LITERAL_IMPL_HPP

View File

@ -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<difference_type>(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<difference_type>(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::size_t>(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::size_t>(std::count(
std::next(iter, static_cast<difference_type>(this->location_)),
std::next(iter, static_cast<difference_type>(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::size_t>(std::count(
std::next(iter, static_cast<difference_type>(this->location_ - n)),
std::next(iter, static_cast<difference_type>(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<location::char_type>(c);
});
return location(std::make_shared<const location::container_type>(
std::move(cont)), "internal temporary");
}
TOML11_INLINE result<location, none_t>
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<location, none_t>
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

View File

@ -0,0 +1,188 @@
#ifndef TOML11_REGION_IMPL_HPP
#define TOML11_REGION_IMPL_HPP
#include "../fwd/region_fwd.hpp"
#include "../utility.hpp"
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#include <cassert>
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<difference_type>(this->first_ + i));
return *iter;
}
TOML11_INLINE region::const_iterator region::begin() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->first_));
}
TOML11_INLINE region::const_iterator region::end() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->last_));
}
TOML11_INLINE region::const_iterator region::cbegin() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->first_));
}
TOML11_INLINE region::const_iterator region::cend() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->last_));
}
TOML11_INLINE std::string region::as_string() const
{
if(this->is_ok())
{
const auto begin = std::next(this->source_->cbegin(), static_cast<difference_type>(this->first_));
const auto end = std::next(this->source_->cbegin(), static_cast<difference_type>(this->last_ ));
return ::toml::detail::make_string(begin, end);
}
else
{
return std::string("");
}
}
TOML11_INLINE std::vector<std::string> region::as_lines() const
{
assert(this->is_ok());
if(this->length_ == 0)
{
return std::vector<std::string>{""};
}
// 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<difference_type>(this->first_);
const auto end_idx = static_cast<difference_type>(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::string>{""};
}
std::istringstream iss(reg_lines);
std::vector<std::string> lines;
std::string line;
while(std::getline(iss, line))
{
lines.push_back(line);
}
return lines;
}
} // namespace detail
} // namespace toml
#endif // TOML11_REGION_IMPL_HPP

View File

@ -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; i<chars_.size(); ++i)
{
if(i != 0)
{
expected += ", ";
}
if(i + 1 == chars_.size())
{
expected += "or ";
}
expected += show_char(chars_.at(i));
}
}
return expected;
}
TOML11_INLINE scanner_base* character_either::clone() const
{
return new character_either(*this);
}
TOML11_INLINE void character_either::push_back(const char_type c)
{
chars_.push_back(c);
}
TOML11_INLINE std::string character_either::name() const
{
std::string n("character_either{");
for(const auto c : this->chars_)
{
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; i<size_; ++i)
{
if(loc.eof() || char_type(value_[i]) != loc.current())
{
loc = first;
return region{};
}
loc.advance(1);
}
return region(first, loc);
}
TOML11_INLINE std::string literal::expected_chars(location&) const
{
return std::string(value_);
}
TOML11_INLINE scanner_base* literal::clone() const
{
return new literal(*this);
}
TOML11_INLINE std::string literal::name() const
{
return std::string("literal{") + std::string(value_, size_) + "}";
}
// ----------------------------------------------------------------------------
// sequence
TOML11_INLINE region sequence::scan(location& loc) const
{
const auto first = loc;
for(const auto& other : others_)
{
const auto reg = other.scan(loc);
if( ! reg.is_ok())
{
loc = first;
return region{};
}
}
return region(first, loc);
}
TOML11_INLINE std::string sequence::expected_chars(location& loc) const
{
const auto first = loc;
for(const auto& other : others_)
{
const auto reg = other.scan(loc);
if( ! reg.is_ok())
{
return other.expected_chars(loc);
}
}
assert(false);
return ""; // XXX
}
TOML11_INLINE scanner_base* sequence::clone() const
{
return new sequence(*this);
}
TOML11_INLINE std::string sequence::name() const
{
std::string n("sequence{");
for(const auto& other : others_)
{
n += other.name();
n += ", ";
}
if( ! this->others_.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; i<others_.size(); ++i)
{
expected += ", ";
if(i + 1 == others_.size())
{
expected += "or ";
}
expected += others_.at(i).expected_chars(loc);
}
}
return expected;
}
TOML11_INLINE scanner_base* either::clone() const
{
return new either(*this);
}
TOML11_INLINE std::string either::name() const
{
std::string n("either{");
for(const auto& other : others_)
{
n += other.name();
n += ", ";
}
if( ! this->others_.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<length_; ++i)
{
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
loc = first;
return region{};
}
}
return region(first, loc);
}
TOML11_INLINE std::string repeat_exact::expected_chars(location& loc) const
{
for(std::size_t i=0; i<length_; ++i)
{
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
return other_.expected_chars(loc);
}
}
assert(false);
return "";
}
TOML11_INLINE scanner_base* repeat_exact::clone() const
{
return new repeat_exact(*this);
}
TOML11_INLINE std::string repeat_exact::name() const
{
return "repeat_exact{" + std::to_string(length_) + ", " + other_.name() + "}";
}
// ----------------------------------------------------------------------------
// repeat_at_least
TOML11_INLINE region repeat_at_least::scan(location& loc) const
{
const auto first = loc;
for(std::size_t i=0; i<length_; ++i)
{
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
loc = first;
return region{};
}
}
while( ! loc.eof())
{
const auto checkpoint = loc;
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
loc = checkpoint;
return region(first, loc);
}
}
return region(first, loc);
}
TOML11_INLINE std::string repeat_at_least::expected_chars(location& loc) const
{
for(std::size_t i=0; i<length_; ++i)
{
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
return other_.expected_chars(loc);
}
}
assert(false);
return "";
}
TOML11_INLINE scanner_base* repeat_at_least::clone() const
{
return new repeat_at_least(*this);
}
TOML11_INLINE std::string repeat_at_least::name() const
{
return "repeat_at_least{" + std::to_string(length_) + ", " + other_.name() + "}";
}
// ----------------------------------------------------------------------------
// maybe
TOML11_INLINE region maybe::scan(location& loc) const
{
const auto first = loc;
const auto reg = other_.scan(loc);
if( ! reg.is_ok())
{
loc = first;
}
return region(first, loc);
}
TOML11_INLINE std::string maybe::expected_chars(location&) const
{
return "";
}
TOML11_INLINE scanner_base* maybe::clone() const
{
return new maybe(*this);
}
TOML11_INLINE std::string maybe::name() const
{
return "maybe{" + other_.name() + "}";
}
} // detail
} // toml
#endif // TOML11_SCANNER_IMPL_HPP

View File

@ -0,0 +1,197 @@
#ifndef TOML11_SOURCE_LOCATION_IMPL_HPP
#define TOML11_SOURCE_LOCATION_IMPL_HPP
#include "../fwd/source_location_fwd.hpp"
#include "../color.hpp"
#include "../utility.hpp"
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <cctype>
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<int>(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

View File

@ -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<std::uint32_t>(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

View File

@ -0,0 +1,40 @@
#ifndef TOML11_VALUE_T_IMPL_HPP
#define TOML11_VALUE_T_IMPL_HPP
#include "../fwd/value_t_fwd.hpp"
#include <ostream>
#include <sstream>
#include <string>
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

View File

@ -1,5 +1,3 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_INTO_HPP #ifndef TOML11_INTO_HPP
#define TOML11_INTO_HPP #define TOML11_INTO_HPP

View File

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

View File

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

View File

@ -0,0 +1,265 @@
#ifndef TOML11_ORDERED_MAP_HPP
#define TOML11_ORDERED_MAP_HPP
#include <algorithm>
#include <stdexcept>
#include <utility>
#include <vector>
namespace toml
{
namespace detail
{
template<typename Cmp>
struct ordered_map_ebo_container
{
Cmp cmp_; // empty base optimization for empty Cmp type
};
} // detail
template<typename Key, typename Val, typename Cmp = std::equal_to<Key>,
typename Allocator = std::allocator<std::pair<Key, Val>>>
class ordered_map : detail::ordered_map_ebo_container<Cmp>
{
public:
using key_type = Key;
using mapped_type = Val;
using value_type = std::pair<Key, Val>;
using key_compare = Cmp;
using allocator_type = Allocator;
using container_type = std::vector<value_type, Allocator>;
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<Cmp>;
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<typename InputIterator>
ordered_map(InputIterator first, InputIterator last, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator())
: ebo_base{cmp}, container_(first, last, alloc)
{}
template<typename InputIterator>
ordered_map(InputIterator first, InputIterator last, const Allocator& alloc)
: container_(first, last, alloc)
{}
ordered_map(std::initializer_list<value_type> v, const Cmp& cmp = Cmp(), const Allocator& alloc = Allocator())
: ebo_base{cmp}, container_(std::move(v), alloc)
{}
ordered_map(std::initializer_list<value_type> v, const Allocator& alloc)
: container_(std::move(v), alloc)
{}
ordered_map& operator=(std::initializer_list<value_type> 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<typename K, typename V, typename C, typename A>
bool operator==(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template<typename K, typename V, typename C, typename A>
bool operator!=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return !(lhs == rhs);
}
template<typename K, typename V, typename C, typename A>
bool operator<(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename K, typename V, typename C, typename A>
bool operator>(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return rhs < lhs;
}
template<typename K, typename V, typename C, typename A>
bool operator<=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return !(lhs > rhs);
}
template<typename K, typename V, typename C, typename A>
bool operator>=(const ordered_map<K,V,C,A>& lhs, const ordered_map<K,V,C,A>& rhs)
{
return !(lhs < rhs);
}
template<typename K, typename V, typename C, typename A>
void swap(ordered_map<K,V,C,A>& lhs, ordered_map<K,V,C,A>& rhs)
{
lhs.swap(rhs);
return;
}
} // toml
#endif // TOML11_ORDERED_MAP_HPP

3829
src/frontend/qt_sdl/toml/toml11/parser.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,486 @@
#ifndef TOML11_RESULT_HPP
#define TOML11_RESULT_HPP
#include "compat.hpp"
#include "exception.hpp"
#include <ostream>
#include <string>
#include <type_traits>
#include <utility>
#include <cassert>
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<typename T>
struct success
{
static_assert( ! std::is_same<T, void>::value, "");
using value_type = T;
explicit success(value_type v)
noexcept(std::is_nothrow_move_constructible<value_type>::value)
: value(std::move(v))
{}
template<typename U, cxx::enable_if_t<
std::is_convertible<cxx::remove_cvref_t<U>, T>::value,
std::nullptr_t> = nullptr>
explicit success(U&& v): value(std::forward<U>(v)) {}
template<typename U>
explicit success(success<U> 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<typename T>
struct success<std::reference_wrapper<T>>
{
static_assert( ! std::is_same<T, void>::value, "");
using value_type = T;
explicit success(std::reference_wrapper<value_type> 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_type> value;
};
template<typename T>
success<typename std::decay<T>::type> ok(T&& v)
{
return success<typename std::decay<T>::type>(std::forward<T>(v));
}
template<std::size_t N>
success<std::string> ok(const char (&literal)[N])
{
return success<std::string>(std::string(literal));
}
// -----------------------------------------------------------------------------
template<typename T>
struct failure
{
using value_type = T;
explicit failure(value_type v)
noexcept(std::is_nothrow_move_constructible<value_type>::value)
: value(std::move(v))
{}
template<typename U, cxx::enable_if_t<
std::is_convertible<cxx::remove_cvref_t<U>, T>::value,
std::nullptr_t> = nullptr>
explicit failure(U&& v): value(std::forward<U>(v)) {}
template<typename U>
explicit failure(failure<U> 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<typename T>
struct failure<std::reference_wrapper<T>>
{
using value_type = T;
explicit failure(std::reference_wrapper<value_type> 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_type> value;
};
template<typename T>
failure<typename std::decay<T>::type> err(T&& v)
{
return failure<typename std::decay<T>::type>(std::forward<T>(v));
}
template<std::size_t N>
failure<std::string> err(const char (&literal)[N])
{
return failure<std::string>(std::string(literal));
}
/* ============================================================================
* _ _
* _ _ ___ ____ _| | |_
* | '_/ -_|_-< || | | _|
* |_| \___/__/\_,_|_|\__|
*/
template<typename T, typename E>
struct result
{
using success_type = success<T>;
using failure_type = failure<E>;
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<typename U, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,
std::is_convertible<cxx::remove_cvref_t<U>, value_type>
>::value, std::nullptr_t> = nullptr>
result(success<U> s): is_ok_(true), succ_(std::move(s.value)) {}
template<typename U, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<U>, error_type>>,
std::is_convertible<cxx::remove_cvref_t<U>, error_type>
>::value, std::nullptr_t> = nullptr>
result(failure<U> 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<typename U>
result& operator=(success<U> 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<typename U>
result& operator=(failure<U> 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<typename U, typename F, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,
cxx::negation<std::is_same<cxx::remove_cvref_t<F>, error_type>>,
std::is_convertible<cxx::remove_cvref_t<U>, value_type>,
std::is_convertible<cxx::remove_cvref_t<F>, error_type>
>::value, std::nullptr_t> = nullptr>
result(result<U, F> 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<typename U, typename F, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<U>, value_type>>,
cxx::negation<std::is_same<cxx::remove_cvref_t<F>, error_type>>,
std::is_convertible<cxx::remove_cvref_t<U>, value_type>,
std::is_convertible<cxx::remove_cvref_t<F>, error_type>
>::value, std::nullptr_t> = nullptr>
result& operator=(result<U, F> 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<detail::none_t> ok() noexcept
{
return success<detail::none_t>(detail::none_t{});
}
inline failure<detail::none_t> err() noexcept
{
return failure<detail::none_t>(detail::none_t{});
}
} // toml
#endif // TOML11_RESULT_HPP

View File

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

File diff suppressed because it is too large Load Diff

392
src/frontend/qt_sdl/toml/toml11/skip.hpp vendored Normal file
View File

@ -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 <cassert>
namespace toml
{
namespace detail
{
template<typename TC>
bool skip_whitespace(location& loc, const context<TC>& ctx)
{
return syntax::ws(ctx.toml_spec()).scan(loc).is_ok();
}
template<typename TC>
bool skip_empty_lines(location& loc, const context<TC>& 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<typename TC>
void skip_comment_block(location& loc, const context<TC>& 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<typename TC>
void skip_empty_or_comment_lines(location& loc, const context<TC>& 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<typename TC>
void skip_string_like(location& loc, const context<TC>&)
{
// 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<typename TC>
void skip_value(location& loc, const context<TC>& ctx);
template<typename TC>
void skip_array_like(location& loc, const context<TC>& ctx);
template<typename TC>
void skip_inline_table_like(location& loc, const context<TC>& ctx);
template<typename TC>
void skip_key_value_pair(location& loc, const context<TC>& ctx);
template<typename TC>
result<value_t, error_info>
guess_value_type(const location& loc, const context<TC>& ctx);
template<typename TC>
void skip_array_like(location& loc, const context<TC>& 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<typename TC>
void skip_inline_table_like(location& loc, const context<TC>& 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<typename TC>
void skip_value(location& loc, const context<TC>& 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<typename TC>
void skip_key_value_pair(location& loc, const context<TC>& 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<typename TC>
void skip_until_next_table(location& loc, const context<TC>& 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 <type_config>(location& loc, const context<type_config>&);
extern template bool skip_empty_lines <type_config>(location& loc, const context<type_config>&);
extern template void skip_comment_block <type_config>(location& loc, const context<type_config>&);
extern template void skip_empty_or_comment_lines<type_config>(location& loc, const context<type_config>&);
extern template void skip_string_like <type_config>(location& loc, const context<type_config>&);
extern template void skip_array_like <type_config>(location& loc, const context<type_config>&);
extern template void skip_inline_table_like <type_config>(location& loc, const context<type_config>&);
extern template void skip_value <type_config>(location& loc, const context<type_config>&);
extern template void skip_key_value_pair <type_config>(location& loc, const context<type_config>&);
extern template void skip_until_next_table <type_config>(location& loc, const context<type_config>&);
extern template bool skip_whitespace <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template bool skip_empty_lines <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_comment_block <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_empty_or_comment_lines<ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_string_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_array_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_inline_table_like <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_value <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_key_value_pair <ordered_type_config>(location& loc, const context<ordered_type_config>&);
extern template void skip_until_next_table <ordered_type_config>(location& loc, const context<ordered_type_config>&);
} // detail
} // toml
#endif // TOML11_COMPILE_SOURCES
#endif // TOML11_SKIP_HPP

View File

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

121
src/frontend/qt_sdl/toml/toml11/spec.hpp vendored Normal file
View File

@ -0,0 +1,121 @@
#ifndef TOML11_SPEC_HPP
#define TOML11_SPEC_HPP
#include <ostream>
#include <sstream>
#include <cstdint>
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

View File

@ -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<toml::value>` 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<std::unique_ptr<toml::value>>`. Although `std::unique_ptr` is
// noncopyable, we want to make `toml::value` copyable. `storage` is introduced
// to resolve those problems.
template<typename T>
struct storage
{
using value_type = T;
explicit storage(value_type v): ptr_(cxx::make_unique<T>(std::move(v))) {}
~storage() = default;
storage(const storage& rhs): ptr_(cxx::make_unique<T>(*rhs.ptr_)) {}
storage& operator=(const storage& rhs)
{
this->ptr_ = cxx::make_unique<T>(*rhs.ptr_);
return *this;
}
storage(storage&&) = default;
storage& operator=(storage&&) = default;
bool is_ok() const noexcept {return static_cast<bool>(ptr_);}
value_type& get() const noexcept {return *ptr_;}
private:
std::unique_ptr<value_type> ptr_;
};
} // detail
} // toml
#endif // TOML11_STORAGE_HPP

View File

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

View File

@ -0,0 +1,240 @@
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP
#include "from.hpp"
#include "into.hpp"
#include "compat.hpp"
#include <array>
#include <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#if defined(TOML11_HAS_STRING_VIEW)
#include <string_view>
#endif
namespace toml
{
template<typename TypeConcig>
class basic_value;
namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class
struct has_iterator_impl
{
template<typename T> static std::true_type check(typename T::iterator*);
template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
template<typename T> static std::true_type check(typename T::value_type*);
template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
template<typename T> static std::true_type check(typename T::key_type*);
template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
template<typename T> static std::true_type check(typename T::mapped_type*);
template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
template<typename T> static std::false_type check(...);
template<typename T> static std::true_type check(
decltype(std::declval<T>() < std::declval<T>())*);
};
struct has_from_toml_method_impl
{
template<typename T, typename TC>
static std::true_type check(
decltype(std::declval<T>().from_toml(std::declval<::toml::basic_value<TC>>()))*);
template<typename T, typename TC>
static std::false_type check(...);
};
struct has_into_toml_method_impl
{
template<typename T>
static std::true_type check(decltype(std::declval<T>().into_toml())*);
template<typename T>
static std::false_type check(...);
};
struct has_template_into_toml_method_impl
{
template<typename T, typename TypeConfig>
static std::true_type check(decltype(std::declval<T>().template into_toml<TypeConfig>())*);
template<typename T, typename TypeConfig>
static std::false_type check(...);
};
struct has_specialized_from_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
template<typename T>
static std::false_type check(...);
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
static std::true_type check(::toml::into<T>*);
};
/// 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<true, decltype(__VA_ARGS__)>::type
#endif
template<typename T>
struct has_iterator: decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type: decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type: decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type: decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method: decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method: decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable: decltype(is_comparable_impl::check<T>(nullptr)){};
template<typename T, typename TC>
struct has_from_toml_method: decltype(has_from_toml_method_impl::check<T, TC>(nullptr)){};
template<typename T>
struct has_into_toml_method: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
template<typename T, typename TypeConfig>
struct has_template_into_toml_method: decltype(has_template_into_toml_method_impl::check<T, TypeConfig>(nullptr)){};
template<typename T>
struct has_specialized_from: decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into: decltype(has_specialized_into_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype
#endif
// ---------------------------------------------------------------------------
// type checkers
template<typename T> struct is_std_pair_impl : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair_impl<std::pair<T1, T2>> : std::true_type{};
template<typename T>
using is_std_pair = is_std_pair_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_std_tuple_impl : std::false_type{};
template<typename ... Ts>
struct is_std_tuple_impl<std::tuple<Ts...>> : std::true_type{};
template<typename T>
using is_std_tuple = is_std_tuple_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_std_array_impl : std::false_type{};
template<typename T, std::size_t N>
struct is_std_array_impl<std::array<T, N>> : std::true_type{};
template<typename T>
using is_std_array = is_std_array_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_std_forward_list_impl : std::false_type{};
template<typename T>
struct is_std_forward_list_impl<std::forward_list<T>> : std::true_type{};
template<typename T>
using is_std_forward_list = is_std_forward_list_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_std_basic_string_impl<std::basic_string<C, T, A>> : std::true_type{};
template<typename T>
using is_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;
template<typename T> struct is_1byte_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_1byte_std_basic_string_impl<std::basic_string<C, T, A>>
: std::integral_constant<bool, sizeof(C) == sizeof(char)> {};
template<typename T>
using is_1byte_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;
#if defined(TOML11_HAS_STRING_VIEW)
template<typename T> struct is_std_basic_string_view_impl : std::false_type{};
template<typename C, typename T>
struct is_std_basic_string_view_impl<std::basic_string_view<C, T>> : std::true_type{};
template<typename T>
using is_std_basic_string_view = is_std_basic_string_view_impl<cxx::remove_cvref_t<T>>;
template<typename V, typename S>
struct is_string_view_of : std::false_type {};
template<typename C, typename T>
struct is_string_view_of<std::basic_string_view<C, T>, std::basic_string<C, T>> : std::true_type {};
#endif
template<typename T> struct is_chrono_duration_impl: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration_impl<std::chrono::duration<Rep, Period>>: std::true_type{};
template<typename T>
using is_chrono_duration = is_chrono_duration_impl<cxx::remove_cvref_t<T>>;
template<typename T>
struct is_map_impl : cxx::conjunction< // map satisfies all the following conditions
has_iterator<T>, // has T::iterator
has_value_type<T>, // has T::value_type
has_key_type<T>, // has T::key_type
has_mapped_type<T> // has T::mapped_type
>{};
template<typename T>
using is_map = is_map_impl<cxx::remove_cvref_t<T>>;
template<typename T>
struct is_container_impl : cxx::conjunction<
cxx::negation<is_map<T>>, // not a map
cxx::negation<std::is_same<T, std::string>>, // not a std::string
#ifdef TOML11_HAS_STRING_VIEW
cxx::negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
has_iterator<T>, // has T::iterator
has_value_type<T> // has T::value_type
>{};
template<typename T>
using is_container = is_container_impl<cxx::remove_cvref_t<T>>;
template<typename T>
struct is_basic_value_impl: std::false_type{};
template<typename TC>
struct is_basic_value_impl<::toml::basic_value<TC>>: std::true_type{};
template<typename T>
using is_basic_value = is_basic_value_impl<cxx::remove_cvref_t<T>>;
}// detail
}//toml
#endif // TOML11_TRAITS_HPP

View File

@ -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 <ostream>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <cstdint>
#include <cstdio>
namespace toml
{
// forward decl
template<typename TypeConfig>
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<typename T>
result<T, error_info>
read_dec_int(const std::string& str, const source_location src)
{
constexpr auto max_digits = std::numeric_limits<T>::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<typename T>
result<T, error_info>
read_hex_int(const std::string& str, const source_location src)
{
constexpr auto max_digits = std::numeric_limits<T>::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<typename T>
result<T, error_info>
read_oct_int(const std::string& str, const source_location src)
{
constexpr auto max_digits = std::numeric_limits<T>::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<typename T>
result<T, error_info>
read_bin_int(const std::string& str, const source_location src)
{
constexpr auto is_bounded = std::numeric_limits<T>::is_bounded;
constexpr auto max_digits = std::numeric_limits<T>::digits;
const auto max_value = (std::numeric_limits<T>::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<typename T>
result<T, error_info>
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<T>(str, src); }
case 8: { return read_oct_int<T>(str, src); }
case 16: { return read_hex_int<T>(str, src); }
default:
{
assert(base == 10);
return read_dec_int<T>(str, src);
}
}
}
inline result<float, error_info>
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<double, error_info>
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<typename T>
cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, double>>,
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, float>>
>::value, result<T, error_info>>
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<typename T>
result<T, error_info>
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<typename T>
result<T, error_info>
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<T>(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<typename T>
using array_type = std::vector<T>;
template<typename K, typename T>
using table_type = std::unordered_map<K, T>;
static result<integer_type, error_info>
parse_int(const std::string& str, const source_location src, const std::uint8_t base)
{
return read_int<integer_type>(str, src, base);
}
static result<floating_type, error_info>
parse_float(const std::string& str, const source_location src, const bool is_hex)
{
return read_float<floating_type>(str, src, is_hex);
}
};
using value = basic_value<type_config>;
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<typename T>
using array_type = std::vector<T>;
template<typename K, typename T>
using table_type = ordered_map<K, T>;
static result<integer_type, error_info>
parse_int(const std::string& str, const source_location src, const std::uint8_t base)
{
return read_int<integer_type>(str, src, base);
}
static result<floating_type, error_info>
parse_float(const std::string& str, const source_location src, const bool is_hex)
{
return read_float<floating_type>(str, src, is_hex);
}
};
using ordered_value = basic_value<ordered_type_config>;
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<typename T> static std::true_type check(typename T::comment_type*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_comment_type = decltype(has_comment_type_impl::check<T>(nullptr));
struct has_integer_type_impl
{
template<typename T> static std::true_type check(typename T::integer_type*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_integer_type = decltype(has_integer_type_impl::check<T>(nullptr));
struct has_floating_type_impl
{
template<typename T> static std::true_type check(typename T::floating_type*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_floating_type = decltype(has_floating_type_impl::check<T>(nullptr));
struct has_string_type_impl
{
template<typename T> static std::true_type check(typename T::string_type*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_string_type = decltype(has_string_type_impl::check<T>(nullptr));
struct has_array_type_impl
{
template<typename T> static std::true_type check(typename T::template array_type<int>*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_array_type = decltype(has_array_type_impl::check<T>(nullptr));
struct has_table_type_impl
{
template<typename T> static std::true_type check(typename T::template table_type<int, int>*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_table_type = decltype(has_table_type_impl::check<T>(nullptr));
struct has_parse_int_impl
{
template<typename T> static std::true_type check(decltype(std::declval<T>().parse_int(
std::declval<const std::string&>(),
std::declval<const source_location>(),
std::declval<const std::uint8_t>()
))*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_parse_int = decltype(has_parse_int_impl::check<T>(nullptr));
struct has_parse_float_impl
{
template<typename T> static std::true_type check(decltype(std::declval<T>().parse_float(
std::declval<const std::string&>(),
std::declval<const source_location>(),
std::declval<const bool>()
))*);
template<typename T> static std::false_type check(...);
};
template<typename T>
using has_parse_float = decltype(has_parse_float_impl::check<T>(nullptr));
template<typename T>
using is_type_config = cxx::conjunction<
has_comment_type<T>,
has_integer_type<T>,
has_floating_type<T>,
has_string_type<T>,
has_array_type<T>,
has_table_type<T>,
has_parse_int<T>,
has_parse_float<T>
>;
} // namespace detail
} // namespace toml
#if defined(TOML11_COMPILE_SOURCES)
namespace toml
{
extern template class basic_value<type_config>;
extern template class basic_value<ordered_type_config>;
} // toml
#endif // TOML11_COMPILE_SOURCES
#endif // TOML11_TYPES_HPP

View File

@ -0,0 +1,170 @@
#ifndef TOML11_UTILITY_HPP
#define TOML11_UTILITY_HPP
#include "result.hpp"
#include "traits.hpp"
#include <array>
#include <sstream>
#include <cassert>
#include <cctype>
#include <cstring>
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<char>(c));
}
else
{
std::array<char, 5> buf;
buf.fill('\0');
const auto r = std::snprintf(buf.data(), buf.size(), "0x%02x", c & 0xFF);
assert(r == static_cast<int>(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<typename Container>
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
{
container.reserve(N);
return;
}
template<typename Container>
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
{
return;
}
template<typename Container>
void try_reserve(Container& container, std::size_t N)
{
try_reserve_impl(container, N, has_reserve_method<Container>{});
return;
}
// ---------------------------------------------------------------------------
template<typename T>
result<T, none_t> 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<typename Iterator>
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<typename Char, typename Traits, typename Alloc,
typename Char2, typename Traits2, typename Alloc2>
struct string_conv_impl
{
static_assert(sizeof(Char) == sizeof(char), "");
static_assert(sizeof(Char2) == sizeof(char), "");
static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char2, Traits2, Alloc2> s)
{
std::basic_string<Char, Traits, Alloc> retval;
std::transform(s.begin(), s.end(), std::back_inserter(retval),
[](const Char2 c) {return static_cast<Char>(c);});
return retval;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char2 (&s)[N])
{
std::basic_string<Char, Traits, Alloc> 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<Char>(c);});
return retval;
}
};
template<typename Char, typename Traits, typename Alloc>
struct string_conv_impl<Char, Traits, Alloc, Char, Traits, Alloc>
{
static_assert(sizeof(Char) == sizeof(char), "");
static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char, Traits, Alloc> s)
{
return s;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char (&s)[N])
{
return std::basic_string<Char, Traits, Alloc>(s);
}
};
template<typename S, typename Char2, typename Traits2, typename Alloc2>
cxx::enable_if_t<is_std_basic_string<S>::value, S>
string_conv(std::basic_string<Char2, Traits2, Alloc2> s)
{
using C = typename S::value_type;
using T = typename S::traits_type;
using A = typename S::allocator_type;
return string_conv_impl<C, T, A, Char2, Traits2, Alloc2>::invoke(std::move(s));
}
template<typename S, std::size_t N>
cxx::enable_if_t<is_std_basic_string<S>::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<C2>;
using A2 = std::allocator<C2>;
return string_conv_impl<C, T, A, C2, T2, A2>::template invoke<N>(s);
}
} // namespace detail
} // namespace toml
#endif // TOML11_UTILITY_HPP

2257
src/frontend/qt_sdl/toml/toml11/value.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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(<string_view>)
# define TOML11_HAS_STRING_VIEW 1
# endif
#endif
#ifndef TOML11_DISABLE_STD_FILESYSTEM
# if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE
# if __has_include(<filesystem>)
# define TOML11_HAS_FILESYSTEM 1
# endif
# endif
#endif
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE
# if __has_include(<optional>)
# 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

View File

@ -0,0 +1,81 @@
#ifndef TOML11_VISIT_HPP
#define TOML11_VISIT_HPP
#include "exception.hpp"
#include "traits.hpp"
#include "value.hpp"
namespace toml
{
template<typename Visitor, typename TC>
cxx::return_type_of_t<Visitor, const typename basic_value<TC>::boolean_type&>
visit(Visitor&& visitor, const basic_value<TC>& 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<typename Visitor, typename TC>
cxx::return_type_of_t<Visitor, typename basic_value<TC>::boolean_type&>
visit(Visitor&& visitor, basic_value<TC>& 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<typename Visitor, typename TC>
cxx::return_type_of_t<Visitor, typename basic_value<TC>::boolean_type&&>
visit(Visitor&& visitor, basic_value<TC>&& 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

88
src/frontend/qt_sdl/toml/toml_fwd.hpp vendored Normal file
View File

@ -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 <cstdint>
#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<typename Key, typename Val, typename Cmp, typename Allocator>
class ordered_map;
struct syntax_error;
struct file_io_error;
struct bad_result_access;
template<typename T>
struct success;
template<typename T>
struct failure;
template<typename T, typename E>
struct result;
struct source_location;
struct semantic_version;
struct spec;
template<typename TypeConfig>
class basic_value;
struct type_error;
struct type_config;
using value = basic_value<type_config>;
struct ordered_type_config;
using ordered_value = basic_value<ordered_type_config>;
enum class value_t : std::uint8_t;
} // toml
#endif// TOML11_TOML_HPP