update toml11. fixes bug with FPS settings corrupting config file
This commit is contained in:
parent
bdc8f635de
commit
f1c96281a9
|
@ -0,0 +1,2 @@
|
|||
@PACKAGE_INIT@
|
||||
include("@PACKAGE_toml11_install_cmake_dir@/toml11Targets.cmake")
|
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
|
@ -816,7 +816,7 @@ Table GetLocalTable(int instance)
|
|||
|
||||
std::string key = "Instance" + std::to_string(instance);
|
||||
toml::value& tbl = RootTable[key];
|
||||
if (tbl.is_uninitialized())
|
||||
if (tbl.is_empty())
|
||||
RootTable[key] = RootTable["Instance0"];
|
||||
|
||||
return Table(tbl, key);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <unordered_map>
|
||||
#include <tuple>
|
||||
|
||||
#include "toml/toml/value.hpp"
|
||||
#include "toml/toml11/types.hpp"
|
||||
|
||||
namespace Config
|
||||
{
|
||||
|
|
|
@ -1,38 +1,62 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Toru Niina
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef TOML11_TOML_HPP
|
||||
#define TOML11_TOML_HPP
|
||||
|
||||
#ifndef TOML_FOR_MODERN_CPP
|
||||
#define TOML_FOR_MODERN_CPP
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2017-now Toru Niina
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#define TOML11_VERSION_MAJOR 3
|
||||
#define TOML11_VERSION_MINOR 7
|
||||
#define TOML11_VERSION_PATCH 1
|
||||
// IWYU pragma: begin_exports
|
||||
#include "toml11/color.hpp"
|
||||
#include "toml11/comments.hpp"
|
||||
#include "toml11/compat.hpp"
|
||||
#include "toml11/context.hpp"
|
||||
#include "toml11/conversion.hpp"
|
||||
#include "toml11/datetime.hpp"
|
||||
#include "toml11/error_info.hpp"
|
||||
#include "toml11/exception.hpp"
|
||||
#include "toml11/find.hpp"
|
||||
#include "toml11/format.hpp"
|
||||
#include "toml11/from.hpp"
|
||||
#include "toml11/get.hpp"
|
||||
#include "toml11/into.hpp"
|
||||
#include "toml11/literal.hpp"
|
||||
#include "toml11/location.hpp"
|
||||
#include "toml11/ordered_map.hpp"
|
||||
#include "toml11/parser.hpp"
|
||||
#include "toml11/region.hpp"
|
||||
#include "toml11/result.hpp"
|
||||
#include "toml11/scanner.hpp"
|
||||
#include "toml11/serializer.hpp"
|
||||
#include "toml11/skip.hpp"
|
||||
#include "toml11/source_location.hpp"
|
||||
#include "toml11/spec.hpp"
|
||||
#include "toml11/storage.hpp"
|
||||
#include "toml11/syntax.hpp"
|
||||
#include "toml11/traits.hpp"
|
||||
#include "toml11/types.hpp"
|
||||
#include "toml11/utility.hpp"
|
||||
#include "toml11/value.hpp"
|
||||
#include "toml11/value_t.hpp"
|
||||
#include "toml11/version.hpp"
|
||||
#include "toml11/visit.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "toml/parser.hpp"
|
||||
#include "toml/literal.hpp"
|
||||
#include "toml/serializer.hpp"
|
||||
#include "toml/get.hpp"
|
||||
#include "toml/macros.hpp"
|
||||
|
||||
#endif// TOML_FOR_MODERN_CPP
|
||||
#endif// TOML11_TOML_HPP
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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(<ime));
|
||||
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
|
|
@ -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
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,105 @@
|
|||
#ifndef TOML11_MACROS_HPP
|
||||
#define TOML11_MACROS_HPP
|
||||
#ifndef TOML11_CONVERSION_HPP
|
||||
#define TOML11_CONVERSION_HPP
|
||||
|
||||
#include "find.hpp"
|
||||
#include "from.hpp" // IWYU pragma: keep
|
||||
#include "into.hpp" // IWYU pragma: keep
|
||||
|
||||
#if defined(TOML11_HAS_OPTIONAL)
|
||||
|
||||
#include <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(x) TOML11_STRINGIZE_AUX(x)
|
||||
|
@ -65,39 +165,20 @@
|
|||
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
|
||||
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||
|
||||
// use it in the following way.
|
||||
// ```cpp
|
||||
// namespace foo
|
||||
// {
|
||||
// struct Foo
|
||||
// {
|
||||
// std::string s;
|
||||
// double d;
|
||||
// int i;
|
||||
// };
|
||||
// } // foo
|
||||
//
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
|
||||
// ```
|
||||
// And then you can use `toml::find<foo::Foo>(file, "foo");`
|
||||
//
|
||||
#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)\
|
||||
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
|
||||
toml::detail::assign_member_variable_to_value(obj.VAR_NAME, v, TOML11_STRINGIZE(VAR_NAME));
|
||||
|
||||
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
|
||||
namespace toml { \
|
||||
template<> \
|
||||
struct from<NAME> \
|
||||
{ \
|
||||
template<typename C, template<typename ...> class T, \
|
||||
template<typename ...> class A> \
|
||||
static NAME from_toml(const basic_value<C, T, A>& v) \
|
||||
template<typename TC> \
|
||||
static NAME from_toml(const basic_value<TC>& v) \
|
||||
{ \
|
||||
NAME obj; \
|
||||
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
|
||||
|
@ -107,9 +188,10 @@
|
|||
template<> \
|
||||
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__) \
|
||||
return v; \
|
||||
} \
|
||||
|
@ -118,4 +200,4 @@
|
|||
|
||||
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
#endif// TOML11_MACROS_HPP
|
||||
#endif // TOML11_CONVERSION_HPP
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef TOML11_DATETIME_HPP
|
||||
#define TOML11_DATETIME_HPP
|
||||
|
||||
#include "fwd/datetime_fwd.hpp" // IWYU pragma: export
|
||||
|
||||
#if ! defined(TOML11_COMPILE_SOURCES)
|
||||
#include "impl/datetime_impl.hpp" // IWYU pragma: export
|
||||
#endif
|
||||
|
||||
#endif // TOML11_DATETIME_HPP
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_FROM_HPP
|
||||
#define TOML11_FROM_HPP
|
||||
|
|
@ -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
|
|
@ -1,7 +1,10 @@
|
|||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_COMMENTS_HPP
|
||||
#define TOML11_COMMENTS_HPP
|
||||
#ifndef TOML11_COMMENTS_FWD_HPP
|
||||
#define TOML11_COMMENTS_FWD_HPP
|
||||
|
||||
// to use __has_builtin
|
||||
#include "../version.hpp" // IWYU pragma: keep
|
||||
|
||||
#include <exception>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
@ -9,12 +12,7 @@
|
|||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
|
||||
#else
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
|
||||
#endif
|
||||
#include <ostream>
|
||||
|
||||
// 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>`
|
||||
|
@ -25,16 +23,11 @@
|
|||
// error whenever you access to the element.
|
||||
namespace toml
|
||||
{
|
||||
struct discard_comments; // forward decl
|
||||
class discard_comments; // forward decl
|
||||
|
||||
// use it in the following way
|
||||
//
|
||||
// const toml::basic_value<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
|
||||
class preserve_comments
|
||||
{
|
||||
public:
|
||||
// `container_type` is not provided in discard_comments.
|
||||
// do not use this inner-type in a generic code.
|
||||
using container_type = std::vector<std::string>;
|
||||
|
@ -51,6 +44,8 @@ struct preserve_comments
|
|||
using reverse_iterator = container_type::reverse_iterator;
|
||||
using const_reverse_iterator = container_type::const_reverse_iterator;
|
||||
|
||||
public:
|
||||
|
||||
preserve_comments() = default;
|
||||
~preserve_comments() = default;
|
||||
preserve_comments(preserve_comments const&) = default;
|
||||
|
@ -90,11 +85,9 @@ struct preserve_comments
|
|||
|
||||
// Related to the issue #97.
|
||||
//
|
||||
// It is known that `std::vector::insert` and `std::vector::erase` in
|
||||
// the standard library implementation included in GCC 4.8.5 takes
|
||||
// `std::vector::iterator` instead of `std::vector::const_iterator`.
|
||||
// Because of the const-correctness, we cannot convert a `const_iterator` to
|
||||
// an `iterator`. It causes compilation error in GCC 4.8.5.
|
||||
// `std::vector::insert` and `std::vector::erase` in the STL implementation
|
||||
// included in GCC 4.8.5 takes `std::vector::iterator` instead of
|
||||
// `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5.
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
|
||||
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
|
||||
# define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
|
||||
|
@ -233,39 +226,18 @@ struct preserve_comments
|
|||
container_type comments;
|
||||
};
|
||||
|
||||
inline bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;}
|
||||
inline bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;}
|
||||
inline bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments < rhs.comments;}
|
||||
inline bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;}
|
||||
inline bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments > rhs.comments;}
|
||||
inline bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;}
|
||||
bool operator==(const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
bool operator< (const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
bool operator> (const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs);
|
||||
|
||||
inline void swap(preserve_comments& lhs, preserve_comments& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
return;
|
||||
}
|
||||
inline void swap(preserve_comments& lhs, std::vector<std::string>& rhs)
|
||||
{
|
||||
lhs.comments.swap(rhs);
|
||||
return;
|
||||
}
|
||||
inline void swap(std::vector<std::string>& lhs, preserve_comments& rhs)
|
||||
{
|
||||
lhs.swap(rhs.comments);
|
||||
return;
|
||||
}
|
||||
void swap(preserve_comments& lhs, preserve_comments& rhs);
|
||||
void swap(preserve_comments& lhs, std::vector<std::string>& rhs);
|
||||
void swap(std::vector<std::string>& lhs, preserve_comments& rhs);
|
||||
|
||||
template<typename charT, typename traits>
|
||||
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;
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, const preserve_comments& com);
|
||||
|
||||
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.
|
||||
//
|
||||
// To reduce the memory footprint, later we can try empty base optimization (EBO).
|
||||
struct discard_comments
|
||||
class discard_comments
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::string;
|
||||
|
@ -363,6 +336,7 @@ struct discard_comments
|
|||
using reverse_iterator = detail::empty_iterator<std::string, false>;
|
||||
using const_reverse_iterator = detail::empty_iterator<std::string, true>;
|
||||
|
||||
public:
|
||||
discard_comments() = default;
|
||||
~discard_comments() = default;
|
||||
discard_comments(discard_comments const&) = default;
|
||||
|
@ -425,14 +399,14 @@ struct discard_comments
|
|||
// empty, so accessing through operator[], front/back, data causes address
|
||||
// error.
|
||||
|
||||
reference operator[](const size_type) noexcept {return *data();}
|
||||
const_reference operator[](const size_type) const noexcept {return *data();}
|
||||
reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
reference front() noexcept {return *data();}
|
||||
const_reference front() const noexcept {return *data();}
|
||||
reference back() noexcept {return *data();}
|
||||
const_reference back() const noexcept {return *data();}
|
||||
reference front() noexcept {never_call("toml::discard_comment::front");}
|
||||
const_reference front() const noexcept {never_call("toml::discard_comment::front");}
|
||||
reference back() noexcept {never_call("toml::discard_comment::back");}
|
||||
const_reference back() const noexcept {never_call("toml::discard_comment::back");}
|
||||
|
||||
pointer data() noexcept {return nullptr;}
|
||||
const_pointer data() const noexcept {return nullptr;}
|
||||
|
@ -450,6 +424,16 @@ struct discard_comments
|
|||
const_reverse_iterator rend() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crend() const noexcept {return const_iterator{};}
|
||||
|
||||
private:
|
||||
|
||||
[[noreturn]] static void never_call(const char *const this_function)
|
||||
{
|
||||
#if __has_builtin(__builtin_unreachable)
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
throw std::logic_error{this_function};
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
|
||||
|
@ -461,12 +445,7 @@ inline bool operator>=(const discard_comments&, const discard_comments&) noexcep
|
|||
|
||||
inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}
|
||||
|
||||
template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const discard_comments&)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& os, const discard_comments&) {return os;}
|
||||
|
||||
} // toml11
|
||||
#endif// TOML11_COMMENTS_HPP
|
||||
#endif // TOML11_COMMENTS_FWD_HPP
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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(<ime));
|
||||
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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,3 @@
|
|||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_INTO_HPP
|
||||
#define TOML11_INTO_HPP
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef TOML11_LITERAL_HPP
|
||||
#define TOML11_LITERAL_HPP
|
||||
|
||||
#include "fwd/literal_fwd.hpp" // IWYU pragma: export
|
||||
|
||||
#if ! defined(TOML11_COMPILE_SOURCES)
|
||||
#include "impl/literal_impl.hpp" // IWYU pragma: export
|
||||
#endif
|
||||
|
||||
#endif // TOML11_LITERAL_HPP
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue