mirror of https://github.com/exaloop/codon.git
Complete plugin support
parent
321c53cb6e
commit
3914b44a7d
|
@ -16,6 +16,22 @@ namespace codon {
|
|||
/// the DSL, like keywords and IR passes.
|
||||
class DSL {
|
||||
public:
|
||||
/// General information about this plugin.
|
||||
struct Info {
|
||||
/// Extension name
|
||||
std::string name;
|
||||
/// Extension description
|
||||
std::string description;
|
||||
/// Extension version
|
||||
std::string version;
|
||||
/// Extension URL
|
||||
std::string url;
|
||||
/// Supported Codon versions (semver range)
|
||||
std::string supported;
|
||||
/// Plugin stdlib path
|
||||
std::string stdlibPath;
|
||||
};
|
||||
|
||||
using KeywordCallback =
|
||||
std::function<ast::StmtPtr(ast::SimplifyVisitor *, ast::CustomStmt *)>;
|
||||
|
||||
|
@ -32,17 +48,6 @@ public:
|
|||
|
||||
virtual ~DSL() noexcept = default;
|
||||
|
||||
/// @return the name of this DSL
|
||||
virtual std::string getName() const = 0;
|
||||
|
||||
/// @param major major version number (i.e. X in X.Y.Z)
|
||||
/// @param minor minor version number (i.e. Y in X.Y.Z)
|
||||
/// @param patch patch version number (i.e. Z in X.Y.Z)
|
||||
/// @return true if the given major, minor and patch versions are supported
|
||||
virtual bool isVersionSupported(unsigned major, unsigned minor, unsigned patch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Registers this DSL's IR passes with the given pass manager.
|
||||
/// @param pm the pass manager to add the passes to
|
||||
/// @param debug true if compiling in debug mode
|
||||
|
|
|
@ -1,29 +1,82 @@
|
|||
#include "plugins.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "codon/parser/common.h"
|
||||
#include "codon/util/common.h"
|
||||
#include "codon/util/semver/semver.h"
|
||||
#include "codon/util/toml++/toml.h"
|
||||
|
||||
namespace codon {
|
||||
namespace {
|
||||
bool isVersionSupported(const std::string &versionRange, int major, int minor,
|
||||
int patch) {
|
||||
try {
|
||||
return semver::range::satisfies(semver::version(major, minor, patch), versionRange);
|
||||
} catch (const std::invalid_argument &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
typedef std::unique_ptr<DSL> LoadFunc();
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
PluginManager::Error PluginManager::load(const std::string &path) {
|
||||
std::string errMsg;
|
||||
auto handle = llvm::sys::DynamicLibrary::getPermanentLibrary(path.c_str(), &errMsg);
|
||||
#if __APPLE__
|
||||
const std::string libExt = "dylib";
|
||||
#else
|
||||
const std::string libExt = "so";
|
||||
#endif
|
||||
|
||||
if (!handle.isValid())
|
||||
return Error::NOT_FOUND;
|
||||
fs::path tomlPath = path;
|
||||
auto tml = toml::parse_file(path);
|
||||
auto about = tml["about"];
|
||||
auto library = tml["library"];
|
||||
|
||||
auto *entry = (LoadFunc *)handle.getAddressOfSymbol("load");
|
||||
if (!entry)
|
||||
return Error::NO_ENTRYPOINT;
|
||||
std::string cppLib = library["cpp"].value_or("");
|
||||
std::string dylibPath;
|
||||
if (!cppLib.empty())
|
||||
dylibPath = fs::path(tomlPath)
|
||||
.replace_filename(library["cpp"].value_or("lib"))
|
||||
.replace_extension(libExt)
|
||||
.string();
|
||||
|
||||
auto dsl = (*entry)();
|
||||
plugins.push_back(std::make_unique<Plugin>(std::move(dsl), path, handle));
|
||||
return load(plugins.back()->dsl.get());
|
||||
std::string codonLib = library["codon"].value_or("");
|
||||
std::string stdlibPath;
|
||||
if (!codonLib.empty())
|
||||
stdlibPath = fs::path(tomlPath).replace_filename(codonLib).string();
|
||||
|
||||
DSL::Info info = {about["name"].value_or(""), about["description"].value_or(""),
|
||||
about["version"].value_or(""), about["url"].value_or(""),
|
||||
about["supported"].value_or(""), stdlibPath};
|
||||
|
||||
if (!isVersionSupported(info.supported, CODON_VERSION_MAJOR, CODON_VERSION_MINOR,
|
||||
CODON_VERSION_PATCH))
|
||||
return Error::UNSUPPORTED_VERSION;
|
||||
|
||||
if (!dylibPath.empty()) {
|
||||
std::string errMsg;
|
||||
auto handle =
|
||||
llvm::sys::DynamicLibrary::getPermanentLibrary(dylibPath.c_str(), &errMsg);
|
||||
if (!handle.isValid())
|
||||
return Error::NOT_FOUND;
|
||||
|
||||
auto *entry = (LoadFunc *)handle.getAddressOfSymbol("load");
|
||||
if (!entry)
|
||||
return Error::NO_ENTRYPOINT;
|
||||
|
||||
auto dsl = (*entry)();
|
||||
plugins.push_back(std::make_unique<Plugin>(std::move(dsl), info, handle));
|
||||
return load(plugins.back()->dsl.get());
|
||||
} else {
|
||||
plugins.push_back(std::make_unique<Plugin>(std::make_unique<DSL>(), info,
|
||||
llvm::sys::DynamicLibrary()));
|
||||
return Error::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
PluginManager::Error PluginManager::load(DSL *dsl) {
|
||||
if (!dsl || !dsl->isVersionSupported(CODON_VERSION_MAJOR, CODON_VERSION_MINOR,
|
||||
CODON_VERSION_PATCH))
|
||||
return Error::UNSUPPORTED_VERSION;
|
||||
dsl->addIRPasses(pm, debug);
|
||||
return Error::NONE;
|
||||
}
|
||||
|
|
|
@ -15,14 +15,13 @@ namespace codon {
|
|||
struct Plugin {
|
||||
/// the associated DSL
|
||||
std::unique_ptr<DSL> dsl;
|
||||
/// plugin load path
|
||||
std::string path;
|
||||
/// plugin information
|
||||
DSL::Info info;
|
||||
/// library handle
|
||||
llvm::sys::DynamicLibrary handle;
|
||||
|
||||
Plugin(std::unique_ptr<DSL> dsl, const std::string &path,
|
||||
const llvm::sys::DynamicLibrary &handle)
|
||||
: dsl(std::move(dsl)), path(path), handle(handle) {}
|
||||
Plugin(std::unique_ptr<DSL> dsl, DSL::Info info, llvm::sys::DynamicLibrary handle)
|
||||
: dsl(std::move(dsl)), info(std::move(info)), handle(std::move(handle)) {}
|
||||
};
|
||||
|
||||
/// Manager for loading, applying and unloading plugins.
|
||||
|
@ -36,8 +35,6 @@ private:
|
|||
bool debug;
|
||||
|
||||
public:
|
||||
using LoadFunc = std::function<std::unique_ptr<DSL>()>;
|
||||
|
||||
/// Error codes when loading plugins
|
||||
enum Error { NONE = 0, NOT_FOUND, NO_ENTRYPOINT, UNSUPPORTED_VERSION };
|
||||
|
||||
|
|
|
@ -192,6 +192,9 @@ struct Cache : public std::enable_shared_from_this<Cache> {
|
|||
std::function<StmtPtr(ast::SimplifyVisitor *, ast::CustomStmt *)>>
|
||||
customExprStmts;
|
||||
|
||||
/// Plugin-added import paths
|
||||
std::vector<std::string> pluginImportPaths;
|
||||
|
||||
public:
|
||||
explicit Cache(std::string argv0 = "");
|
||||
|
||||
|
|
|
@ -198,23 +198,29 @@ std::string executable_path(const char *argv0) { return std::string(argv0); }
|
|||
std::shared_ptr<ImportFile> getImportFile(const std::string &argv0,
|
||||
const std::string &what,
|
||||
const std::string &relativeTo,
|
||||
bool forceStdlib,
|
||||
const std::string &module0) {
|
||||
bool forceStdlib, const std::string &module0,
|
||||
const std::vector<std::string> &plugins) {
|
||||
using fmt::format;
|
||||
|
||||
auto getStdLibPaths = [](const std::string &argv0) {
|
||||
auto getStdLibPaths = [](const std::string &argv0,
|
||||
const std::vector<std::string> &plugins) {
|
||||
std::vector<std::string> paths;
|
||||
char abs[PATH_MAX + 1];
|
||||
if (auto c = getenv("CODON_PATH")) {
|
||||
if (realpath(c, abs))
|
||||
paths.push_back(abs);
|
||||
}
|
||||
if (!argv0.empty())
|
||||
if (!argv0.empty()) {
|
||||
for (auto loci : {"../lib/codon/stdlib", "../stdlib", "stdlib"}) {
|
||||
strncpy(abs, executable_path(argv0.c_str()).c_str(), PATH_MAX);
|
||||
if (realpath(format("{}/{}", dirname(abs), loci).c_str(), abs))
|
||||
paths.push_back(abs);
|
||||
}
|
||||
}
|
||||
for (auto &path : plugins) {
|
||||
if (realpath(path.c_str(), abs))
|
||||
paths.push_back(abs);
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
|
@ -224,7 +230,7 @@ std::shared_ptr<ImportFile> getImportFile(const std::string &argv0,
|
|||
auto getRoot = [&](const std::string &s) {
|
||||
bool isStdLib = false;
|
||||
std::string root;
|
||||
for (auto &p : getStdLibPaths(argv0))
|
||||
for (auto &p : getStdLibPaths(argv0, plugins))
|
||||
if (startswith(s, p)) {
|
||||
root = p;
|
||||
isStdLib = true;
|
||||
|
@ -248,7 +254,7 @@ std::shared_ptr<ImportFile> getImportFile(const std::string &argv0,
|
|||
paths.push_back(format("{}/{}.codon", parent, what));
|
||||
paths.push_back(format("{}/{}/__init__.codon", parent, what));
|
||||
}
|
||||
for (auto &p : getStdLibPaths(argv0)) {
|
||||
for (auto &p : getStdLibPaths(argv0, plugins)) {
|
||||
paths.push_back(format("{}/{}.codon", p, what));
|
||||
paths.push_back(format("{}/{}/__init__.codon", p, what));
|
||||
}
|
||||
|
|
|
@ -184,7 +184,8 @@ std::shared_ptr<ImportFile> getImportFile(const std::string &argv0,
|
|||
const std::string &what,
|
||||
const std::string &relativeTo,
|
||||
bool forceStdlib = false,
|
||||
const std::string &module0 = "");
|
||||
const std::string &module0 = "",
|
||||
const std::vector<std::string> &plugins = {});
|
||||
|
||||
} // namespace ast
|
||||
} // namespace codon
|
||||
|
|
|
@ -49,6 +49,9 @@ ir::Module *parse(const std::string &argv0, const std::string &file,
|
|||
auto cache = std::make_shared<ast::Cache>(argv0);
|
||||
if (plm) {
|
||||
for (auto *plugin : *plm) {
|
||||
if (!plugin->info.stdlibPath.empty())
|
||||
cache->pluginImportPaths.push_back(plugin->info.stdlibPath);
|
||||
|
||||
for (auto &kw : plugin->dsl->getExprKeywords()) {
|
||||
cache->customExprStmts[kw.keyword] = kw.callback;
|
||||
}
|
||||
|
|
|
@ -373,7 +373,7 @@ void SimplifyVisitor::visit(ImportStmt *stmt) {
|
|||
path += dirs[i] + (i ? "/" : "");
|
||||
// Fetch the import!
|
||||
auto file = getImportFile(ctx->cache->argv0, path, ctx->getFilename(), false,
|
||||
ctx->cache->module0);
|
||||
ctx->cache->module0, ctx->cache->pluginImportPaths);
|
||||
if (!file)
|
||||
error("cannot locate import '{}'", join(dirs, "."));
|
||||
|
||||
|
|
|
@ -0,0 +1,837 @@
|
|||
// _____ _ _
|
||||
// / ____| | | (_)
|
||||
// | (___ ___ _ __ ___ __ _ _ __ | |_ _ ___
|
||||
// \___ \ / _ \ '_ ` _ \ / _` | '_ \| __| |/ __|
|
||||
// ____) | __/ | | | | | (_| | | | | |_| | (__
|
||||
// |_____/ \___|_| |_| |_|\__,_|_| |_|\__|_|\___|
|
||||
// __ __ _ _ _____
|
||||
// \ \ / / (_) (_) / ____|_ _
|
||||
// \ \ / /__ _ __ ___ _ ___ _ __ _ _ __ __ _ | | _| |_ _| |_
|
||||
// \ \/ / _ \ '__/ __| |/ _ \| '_ \| | '_ \ / _` | | | |_ _|_ _|
|
||||
// \ / __/ | \__ \ | (_) | | | | | | | | (_| | | |____|_| |_|
|
||||
// \/ \___|_| |___/_|\___/|_| |_|_|_| |_|\__, | \_____|
|
||||
// https://github.com/Neargye/semver __/ |
|
||||
// version 0.3.0 |___/
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2018 - 2021 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2021 Alexander Gorbunov <naratzul@gmail.com>.
|
||||
//
|
||||
// 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 NEARGYE_SEMANTIC_VERSIONING_HPP
|
||||
#define NEARGYE_SEMANTIC_VERSIONING_HPP
|
||||
|
||||
#define SEMVER_VERSION_MAJOR 0
|
||||
#define SEMVER_VERSION_MINOR 3
|
||||
#define SEMVER_VERSION_PATCH 0
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#if __has_include(<charconv>)
|
||||
#include <charconv>
|
||||
#else
|
||||
#include <system_error>
|
||||
#endif
|
||||
|
||||
// Allow to disable exceptions.
|
||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && \
|
||||
!defined(SEMVER_NOEXCEPTION)
|
||||
#include <stdexcept>
|
||||
#define NEARGYE_THROW(exception) throw exception
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#define NEARGYE_THROW(exception) std::abort()
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored \
|
||||
"-Wmissing-braces" // Ignore warning: suggest braces around initialization of
|
||||
// subobject 'return {first, std::errc::invalid_argument};'.
|
||||
#endif
|
||||
|
||||
namespace semver {
|
||||
|
||||
enum struct prerelease : std::uint8_t { alpha = 0, beta = 1, rc = 2, none = 3 };
|
||||
|
||||
#if __has_include(<charconv>)
|
||||
struct from_chars_result : std::from_chars_result {
|
||||
[[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; }
|
||||
};
|
||||
|
||||
struct to_chars_result : std::to_chars_result {
|
||||
[[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; }
|
||||
};
|
||||
#else
|
||||
struct from_chars_result {
|
||||
const char *ptr;
|
||||
std::errc ec;
|
||||
|
||||
[[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; }
|
||||
};
|
||||
|
||||
struct to_chars_result {
|
||||
char *ptr;
|
||||
std::errc ec;
|
||||
|
||||
[[nodiscard]] constexpr operator bool() const noexcept { return ec == std::errc{}; }
|
||||
};
|
||||
#endif
|
||||
|
||||
// Max version string length = 3(<major>) + 1(.) + 3(<minor>) + 1(.) + 3(<patch>) + 1(-)
|
||||
// + 5(<prerelease>) + 1(.) + 3(<prereleaseversion>) = 21.
|
||||
inline constexpr auto max_version_string_length = std::size_t{21};
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline constexpr auto alpha = std::string_view{"alpha", 5};
|
||||
inline constexpr auto beta = std::string_view{"beta", 4};
|
||||
inline constexpr auto rc = std::string_view{"rc", 2};
|
||||
|
||||
// Min version string length = 1(<major>) + 1(.) + 1(<minor>) + 1(.) + 1(<patch>) = 5.
|
||||
inline constexpr auto min_version_string_length = 5;
|
||||
|
||||
constexpr char to_lower(char c) noexcept {
|
||||
return (c >= 'A' && c <= 'Z') ? static_cast<char>(c + ('a' - 'A')) : c;
|
||||
}
|
||||
|
||||
constexpr bool is_digit(char c) noexcept { return c >= '0' && c <= '9'; }
|
||||
|
||||
constexpr bool is_space(char c) noexcept { return c == ' '; }
|
||||
|
||||
constexpr bool is_operator(char c) noexcept { return c == '<' || c == '>' || c == '='; }
|
||||
|
||||
constexpr bool is_dot(char c) noexcept { return c == '.'; }
|
||||
|
||||
constexpr bool is_logical_or(char c) noexcept { return c == '|'; }
|
||||
|
||||
constexpr bool is_hyphen(char c) noexcept { return c == '-'; }
|
||||
|
||||
constexpr bool is_letter(char c) noexcept {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
constexpr std::uint8_t to_digit(char c) noexcept {
|
||||
return static_cast<std::uint8_t>(c - '0');
|
||||
}
|
||||
|
||||
constexpr std::uint8_t length(std::uint8_t x) noexcept {
|
||||
return x < 10 ? 1 : (x < 100 ? 2 : 3);
|
||||
}
|
||||
|
||||
constexpr std::uint8_t length(prerelease t) noexcept {
|
||||
if (t == prerelease::alpha) {
|
||||
return static_cast<std::uint8_t>(alpha.length());
|
||||
} else if (t == prerelease::beta) {
|
||||
return static_cast<std::uint8_t>(beta.length());
|
||||
} else if (t == prerelease::rc) {
|
||||
return static_cast<std::uint8_t>(rc.length());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr bool equals(const char *first, const char *last,
|
||||
std::string_view str) noexcept {
|
||||
for (std::size_t i = 0; first != last && i < str.length(); ++i, ++first) {
|
||||
if (to_lower(*first) != to_lower(str[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr char *to_chars(char *str, std::uint8_t x, bool dot = true) noexcept {
|
||||
do {
|
||||
*(--str) = static_cast<char>('0' + (x % 10));
|
||||
x /= 10;
|
||||
} while (x != 0);
|
||||
|
||||
if (dot) {
|
||||
*(--str) = '.';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
constexpr char *to_chars(char *str, prerelease t) noexcept {
|
||||
const auto p = t == prerelease::alpha ? alpha
|
||||
: t == prerelease::beta ? beta
|
||||
: t == prerelease::rc ? rc
|
||||
: std::string_view{};
|
||||
|
||||
if (p.size() > 0) {
|
||||
for (auto it = p.rbegin(); it != p.rend(); ++it) {
|
||||
*(--str) = *it;
|
||||
}
|
||||
*(--str) = '-';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
constexpr const char *from_chars(const char *first, const char *last,
|
||||
std::uint8_t &d) noexcept {
|
||||
if (first != last && is_digit(*first)) {
|
||||
std::int32_t t = 0;
|
||||
for (; first != last && is_digit(*first); ++first) {
|
||||
t = t * 10 + to_digit(*first);
|
||||
}
|
||||
if (t <= (std::numeric_limits<std::uint8_t>::max)()) {
|
||||
d = static_cast<std::uint8_t>(t);
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr const char *from_chars(const char *first, const char *last,
|
||||
prerelease &p) noexcept {
|
||||
if (is_hyphen(*first)) {
|
||||
++first;
|
||||
}
|
||||
|
||||
if (equals(first, last, alpha)) {
|
||||
p = prerelease::alpha;
|
||||
return first + alpha.length();
|
||||
} else if (equals(first, last, beta)) {
|
||||
p = prerelease::beta;
|
||||
return first + beta.length();
|
||||
} else if (equals(first, last, rc)) {
|
||||
p = prerelease::rc;
|
||||
return first + rc.length();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr bool check_delimiter(const char *first, const char *last, char d) noexcept {
|
||||
return first != last && first != nullptr && *first == d;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct version {
|
||||
std::uint8_t major = 0;
|
||||
std::uint8_t minor = 1;
|
||||
std::uint8_t patch = 0;
|
||||
prerelease prerelease_type = prerelease::none;
|
||||
std::uint8_t prerelease_number = 0;
|
||||
|
||||
constexpr version(std::uint8_t mj, std::uint8_t mn, std::uint8_t pt,
|
||||
prerelease prt = prerelease::none, std::uint8_t prn = 0) noexcept
|
||||
: major{mj}, minor{mn}, patch{pt}, prerelease_type{prt},
|
||||
prerelease_number{prt == prerelease::none ? static_cast<std::uint8_t>(0)
|
||||
: prn} {}
|
||||
|
||||
explicit constexpr version(std::string_view str)
|
||||
: version(0, 0, 0, prerelease::none, 0) {
|
||||
from_string(str);
|
||||
}
|
||||
|
||||
constexpr version() =
|
||||
default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase
|
||||
|
||||
constexpr version(const version &) = default;
|
||||
|
||||
constexpr version(version &&) = default;
|
||||
|
||||
~version() = default;
|
||||
|
||||
version &operator=(const version &) = default;
|
||||
|
||||
version &operator=(version &&) = default;
|
||||
|
||||
[[nodiscard]] constexpr from_chars_result from_chars(const char *first,
|
||||
const char *last) noexcept {
|
||||
if (first == nullptr || last == nullptr ||
|
||||
(last - first) < detail::min_version_string_length) {
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
auto next = first;
|
||||
if (next = detail::from_chars(next, last, major);
|
||||
detail::check_delimiter(next, last, '.')) {
|
||||
if (next = detail::from_chars(++next, last, minor);
|
||||
detail::check_delimiter(next, last, '.')) {
|
||||
if (next = detail::from_chars(++next, last, patch); next == last) {
|
||||
prerelease_type = prerelease::none;
|
||||
prerelease_number = 0;
|
||||
return {next, std::errc{}};
|
||||
} else if (detail::check_delimiter(next, last, '-')) {
|
||||
if (next = detail::from_chars(next, last, prerelease_type); next == last) {
|
||||
prerelease_number = 0;
|
||||
return {next, std::errc{}};
|
||||
} else if (detail::check_delimiter(next, last, '.')) {
|
||||
if (next = detail::from_chars(++next, last, prerelease_number);
|
||||
next == last) {
|
||||
return {next, std::errc{}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr to_chars_result to_chars(char *first,
|
||||
char *last) const noexcept {
|
||||
const auto length = string_length();
|
||||
if (first == nullptr || last == nullptr || (last - first) < length) {
|
||||
return {last, std::errc::value_too_large};
|
||||
}
|
||||
|
||||
auto next = first + length;
|
||||
if (prerelease_type != prerelease::none) {
|
||||
if (prerelease_number != 0) {
|
||||
next = detail::to_chars(next, prerelease_number);
|
||||
}
|
||||
next = detail::to_chars(next, prerelease_type);
|
||||
}
|
||||
next = detail::to_chars(next, patch);
|
||||
next = detail::to_chars(next, minor);
|
||||
next = detail::to_chars(next, major, false);
|
||||
|
||||
return {first + length, std::errc{}};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool from_string_noexcept(std::string_view str) noexcept {
|
||||
return from_chars(str.data(), str.data() + str.length());
|
||||
}
|
||||
|
||||
constexpr version &from_string(std::string_view str) {
|
||||
if (!from_string_noexcept(str)) {
|
||||
NEARGYE_THROW(
|
||||
std::invalid_argument{"semver::version::from_string invalid version."});
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string to_string() const {
|
||||
auto str = std::string(string_length(), '\0');
|
||||
if (!to_chars(str.data(), str.data() + str.length())) {
|
||||
NEARGYE_THROW(
|
||||
std::invalid_argument{"semver::version::to_string invalid version."});
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::uint8_t string_length() const noexcept {
|
||||
// (<major>) + 1(.) + (<minor>) + 1(.) + (<patch>)
|
||||
auto length =
|
||||
detail::length(major) + detail::length(minor) + detail::length(patch) + 2;
|
||||
if (prerelease_type != prerelease::none) {
|
||||
// + 1(-) + (<prerelease>)
|
||||
length += detail::length(prerelease_type) + 1;
|
||||
if (prerelease_number != 0) {
|
||||
// + 1(.) + (<prereleaseversion>)
|
||||
length += detail::length(prerelease_number) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<std::uint8_t>(length);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr int compare(const version &other) const noexcept {
|
||||
if (major != other.major) {
|
||||
return major - other.major;
|
||||
}
|
||||
|
||||
if (minor != other.minor) {
|
||||
return minor - other.minor;
|
||||
}
|
||||
|
||||
if (patch != other.patch) {
|
||||
return patch - other.patch;
|
||||
}
|
||||
|
||||
if (prerelease_type != other.prerelease_type) {
|
||||
return static_cast<std::uint8_t>(prerelease_type) -
|
||||
static_cast<std::uint8_t>(other.prerelease_type);
|
||||
}
|
||||
|
||||
if (prerelease_number != other.prerelease_number) {
|
||||
return prerelease_number - other.prerelease_number;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator>(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator>=(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) >= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator<(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator<=(const version &lhs,
|
||||
const version &rhs) noexcept {
|
||||
return lhs.compare(rhs) <= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr version operator""_version(const char *str,
|
||||
std::size_t length) {
|
||||
return version{std::string_view{str, length}};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool valid(std::string_view str) noexcept {
|
||||
return version{}.from_string_noexcept(str);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr from_chars_result
|
||||
from_chars(const char *first, const char *last, version &v) noexcept {
|
||||
return v.from_chars(first, last);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr to_chars_result to_chars(char *first, char *last,
|
||||
const version &v) noexcept {
|
||||
return v.to_chars(first, last);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::optional<version>
|
||||
from_string_noexcept(std::string_view str) noexcept {
|
||||
if (version v{}; v.from_string_noexcept(str)) {
|
||||
return v;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr version from_string(std::string_view str) {
|
||||
return version{str};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string to_string(const version &v) { return v.to_string(); }
|
||||
|
||||
template <typename Char, typename Traits>
|
||||
inline std::basic_ostream<Char, Traits> &
|
||||
operator<<(std::basic_ostream<Char, Traits> &os, const version &v) {
|
||||
for (const auto c : v.to_string()) {
|
||||
os.put(c);
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
inline namespace comparators {
|
||||
|
||||
enum struct comparators_option : std::uint8_t {
|
||||
exclude_prerelease,
|
||||
include_prerelease
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr int
|
||||
compare(const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
if (option == comparators_option::exclude_prerelease) {
|
||||
return version{lhs.major, lhs.minor, lhs.patch}.compare(
|
||||
version{rhs.major, rhs.minor, rhs.patch});
|
||||
}
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
equal_to(const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool not_equal_to(
|
||||
const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
greater(const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool greater_equal(
|
||||
const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) >= 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
less(const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) < 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool less_equal(
|
||||
const version &lhs, const version &rhs,
|
||||
comparators_option option = comparators_option::include_prerelease) noexcept {
|
||||
return compare(lhs, rhs, option) <= 0;
|
||||
}
|
||||
|
||||
} // namespace comparators
|
||||
|
||||
namespace range {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using namespace semver::detail;
|
||||
|
||||
class range {
|
||||
public:
|
||||
constexpr explicit range(std::string_view str) noexcept : str_{str} {}
|
||||
|
||||
constexpr bool satisfies(const version &ver, bool include_prerelease) const {
|
||||
range_parser parser{str_};
|
||||
|
||||
auto is_logical_or = [&parser]() constexpr noexcept->bool {
|
||||
return parser.current_token.type == range_token_type::logical_or;
|
||||
};
|
||||
|
||||
auto is_operator = [&parser]() constexpr noexcept->bool {
|
||||
return parser.current_token.type == range_token_type::range_operator;
|
||||
};
|
||||
|
||||
auto is_number = [&parser]() constexpr noexcept->bool {
|
||||
return parser.current_token.type == range_token_type::number;
|
||||
};
|
||||
|
||||
const bool has_prerelease = ver.prerelease_type != prerelease::none;
|
||||
|
||||
do {
|
||||
if (is_logical_or()) {
|
||||
parser.advance_token(range_token_type::logical_or);
|
||||
}
|
||||
|
||||
bool contains = true;
|
||||
bool allow_compare = include_prerelease;
|
||||
|
||||
while (is_operator() || is_number()) {
|
||||
const auto range = parser.parse_range();
|
||||
const bool equal_without_tags =
|
||||
equal_to(range.ver, ver, comparators_option::exclude_prerelease);
|
||||
|
||||
if (has_prerelease && equal_without_tags) {
|
||||
allow_compare = true;
|
||||
}
|
||||
|
||||
if (!range.satisfies(ver)) {
|
||||
contains = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_prerelease) {
|
||||
if (allow_compare && contains) {
|
||||
return true;
|
||||
}
|
||||
} else if (contains) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} while (is_logical_or());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
enum struct range_operator : std::uint8_t {
|
||||
less,
|
||||
less_or_equal,
|
||||
greater,
|
||||
greater_or_equal,
|
||||
equal
|
||||
};
|
||||
|
||||
struct range_comparator {
|
||||
range_operator op;
|
||||
version ver;
|
||||
|
||||
constexpr bool satisfies(const version &version) const {
|
||||
switch (op) {
|
||||
case range_operator::equal:
|
||||
return version == ver;
|
||||
case range_operator::greater:
|
||||
return version > ver;
|
||||
case range_operator::greater_or_equal:
|
||||
return version >= ver;
|
||||
case range_operator::less:
|
||||
return version < ver;
|
||||
case range_operator::less_or_equal:
|
||||
return version <= ver;
|
||||
default:
|
||||
NEARGYE_THROW(std::invalid_argument{"semver::range unexpected operator."});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum struct range_token_type : std::uint8_t {
|
||||
none,
|
||||
number,
|
||||
range_operator,
|
||||
dot,
|
||||
logical_or,
|
||||
hyphen,
|
||||
prerelease,
|
||||
end_of_line
|
||||
};
|
||||
|
||||
struct range_token {
|
||||
range_token_type type = range_token_type::none;
|
||||
std::uint8_t number = 0;
|
||||
range_operator op = range_operator::equal;
|
||||
prerelease prerelease_type = prerelease::none;
|
||||
};
|
||||
|
||||
struct range_lexer {
|
||||
std::string_view text;
|
||||
std::size_t pos;
|
||||
|
||||
constexpr explicit range_lexer(std::string_view text) noexcept
|
||||
: text{text}, pos{0} {}
|
||||
|
||||
constexpr range_token get_next_token() noexcept {
|
||||
while (!end_of_line()) {
|
||||
|
||||
if (is_space(text[pos])) {
|
||||
advance(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_logical_or(text[pos])) {
|
||||
advance(2);
|
||||
return {range_token_type::logical_or};
|
||||
}
|
||||
|
||||
if (is_operator(text[pos])) {
|
||||
const auto op = get_operator();
|
||||
return {range_token_type::range_operator, 0, op};
|
||||
}
|
||||
|
||||
if (is_digit(text[pos])) {
|
||||
const auto number = get_number();
|
||||
return {range_token_type::number, number};
|
||||
}
|
||||
|
||||
if (is_dot(text[pos])) {
|
||||
advance(1);
|
||||
return {range_token_type::dot};
|
||||
}
|
||||
|
||||
if (is_hyphen(text[pos])) {
|
||||
advance(1);
|
||||
return {range_token_type::hyphen};
|
||||
}
|
||||
|
||||
if (is_letter(text[pos])) {
|
||||
const auto prerelease = get_prerelease();
|
||||
return {range_token_type::prerelease, 0, range_operator::equal, prerelease};
|
||||
}
|
||||
}
|
||||
|
||||
return {range_token_type::end_of_line};
|
||||
}
|
||||
|
||||
constexpr bool end_of_line() const noexcept { return pos >= text.length(); }
|
||||
|
||||
constexpr void advance(std::size_t i) noexcept { pos += i; }
|
||||
|
||||
constexpr range_operator get_operator() noexcept {
|
||||
if (text[pos] == '<') {
|
||||
advance(1);
|
||||
if (text[pos] == '=') {
|
||||
advance(1);
|
||||
return range_operator::less_or_equal;
|
||||
}
|
||||
return range_operator::less;
|
||||
} else if (text[pos] == '>') {
|
||||
advance(1);
|
||||
if (text[pos] == '=') {
|
||||
advance(1);
|
||||
return range_operator::greater_or_equal;
|
||||
}
|
||||
return range_operator::greater;
|
||||
} else if (text[pos] == '=') {
|
||||
advance(1);
|
||||
return range_operator::equal;
|
||||
}
|
||||
|
||||
return range_operator::equal;
|
||||
}
|
||||
|
||||
constexpr std::uint8_t get_number() noexcept {
|
||||
const auto first = text.data() + pos;
|
||||
const auto last = text.data() + text.length();
|
||||
if (std::uint8_t n{}; from_chars(first, last, n) != nullptr) {
|
||||
advance(length(n));
|
||||
return n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr prerelease get_prerelease() noexcept {
|
||||
const auto first = text.data() + pos;
|
||||
const auto last = text.data() + text.length();
|
||||
if (first > last) {
|
||||
advance(1);
|
||||
return prerelease::none;
|
||||
}
|
||||
|
||||
if (prerelease p{}; from_chars(first, last, p) != nullptr) {
|
||||
advance(length(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
advance(1);
|
||||
|
||||
return prerelease::none;
|
||||
}
|
||||
};
|
||||
|
||||
struct range_parser {
|
||||
range_lexer lexer;
|
||||
range_token current_token;
|
||||
|
||||
constexpr explicit range_parser(std::string_view str)
|
||||
: lexer{str}, current_token{range_token_type::none} {
|
||||
advance_token(range_token_type::none);
|
||||
}
|
||||
|
||||
constexpr void advance_token(range_token_type token_type) {
|
||||
if (current_token.type != token_type) {
|
||||
NEARGYE_THROW(std::invalid_argument{"semver::range unexpected token."});
|
||||
}
|
||||
current_token = lexer.get_next_token();
|
||||
}
|
||||
|
||||
constexpr range_comparator parse_range() {
|
||||
if (current_token.type == range_token_type::number) {
|
||||
const auto version = parse_version();
|
||||
return {range_operator::equal, version};
|
||||
} else if (current_token.type == range_token_type::range_operator) {
|
||||
const auto range_operator = current_token.op;
|
||||
advance_token(range_token_type::range_operator);
|
||||
const auto version = parse_version();
|
||||
return {range_operator, version};
|
||||
}
|
||||
|
||||
return {range_operator::equal, version{}};
|
||||
}
|
||||
|
||||
constexpr version parse_version() {
|
||||
const auto major = parse_number();
|
||||
|
||||
advance_token(range_token_type::dot);
|
||||
const auto minor = parse_number();
|
||||
|
||||
advance_token(range_token_type::dot);
|
||||
const auto patch = parse_number();
|
||||
|
||||
prerelease prerelease = prerelease::none;
|
||||
std::uint8_t prerelease_number = 0;
|
||||
|
||||
if (current_token.type == range_token_type::hyphen) {
|
||||
advance_token(range_token_type::hyphen);
|
||||
prerelease = parse_prerelease();
|
||||
advance_token(range_token_type::dot);
|
||||
prerelease_number = parse_number();
|
||||
}
|
||||
|
||||
return {major, minor, patch, prerelease, prerelease_number};
|
||||
}
|
||||
|
||||
constexpr std::uint8_t parse_number() {
|
||||
const auto token = current_token;
|
||||
advance_token(range_token_type::number);
|
||||
|
||||
return token.number;
|
||||
}
|
||||
|
||||
constexpr prerelease parse_prerelease() {
|
||||
const auto token = current_token;
|
||||
advance_token(range_token_type::prerelease);
|
||||
|
||||
return token.prerelease_type;
|
||||
}
|
||||
};
|
||||
|
||||
std::string_view str_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum struct satisfies_option : std::uint8_t { exclude_prerelease, include_prerelease };
|
||||
|
||||
constexpr bool
|
||||
satisfies(const version &ver, std::string_view str,
|
||||
satisfies_option option = satisfies_option::exclude_prerelease) {
|
||||
switch (option) {
|
||||
case satisfies_option::exclude_prerelease:
|
||||
return detail::range{str}.satisfies(ver, false);
|
||||
case satisfies_option::include_prerelease:
|
||||
return detail::range{str}.satisfies(ver, true);
|
||||
default:
|
||||
NEARGYE_THROW(std::invalid_argument{"semver::range unexpected satisfies_option."});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace range
|
||||
|
||||
// Version lib semver.
|
||||
inline constexpr auto semver_version =
|
||||
version{SEMVER_VERSION_MAJOR, SEMVER_VERSION_MINOR, SEMVER_VERSION_PATCH};
|
||||
|
||||
} // namespace semver
|
||||
|
||||
#undef NEARGYE_THROW
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // NEARGYE_SEMANTIC_VERSIONING_HPP
|
|
@ -0,0 +1,152 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_TOMLPLUSPLUS_H
|
||||
#define INCLUDE_TOMLPLUSPLUS_H
|
||||
|
||||
//# Note: most of these would be included transitively but
|
||||
//# they're listed explicitly here because this file
|
||||
//# is used as the source for generate_single_header.py.
|
||||
|
||||
#include "toml_preprocessor.h"
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SPAM_WARNINGS;
|
||||
|
||||
#include "toml_array.h"
|
||||
#include "toml_common.h"
|
||||
#include "toml_date_time.h"
|
||||
#include "toml_node.h"
|
||||
#include "toml_node_view.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_utf8.h"
|
||||
#include "toml_value.h"
|
||||
#if TOML_PARSER
|
||||
#include "toml_parse_error.h"
|
||||
#include "toml_parse_result.h"
|
||||
#include "toml_parser.h"
|
||||
#include "toml_utf8_streams.h"
|
||||
#endif // TOML_PARSER
|
||||
#include "toml_default_formatter.h"
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_json_formatter.h"
|
||||
|
||||
#if TOML_IMPLEMENTATION
|
||||
#include "toml_array.hpp"
|
||||
#include "toml_node.hpp"
|
||||
#include "toml_table.hpp"
|
||||
#if TOML_PARSER
|
||||
#include "toml_parser.hpp"
|
||||
#include "toml_utf8_streams.hpp"
|
||||
#endif // TOML_PARSER
|
||||
#include "toml_default_formatter.hpp"
|
||||
#include "toml_json_formatter.hpp"
|
||||
#if !TOML_HEADER_ONLY
|
||||
#include "toml_instantiations.hpp"
|
||||
#endif // !TOML_HEADER_ONLY
|
||||
#endif // TOML_IMPLEMENTATION
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SPAM_WARNINGS
|
||||
|
||||
// macro hygiene
|
||||
#if TOML_UNDEF_MACROS
|
||||
#undef TOML_ABI_NAMESPACES
|
||||
#undef TOML_ABI_NAMESPACE_BOOL
|
||||
#undef TOML_ABI_NAMESPACE_END
|
||||
#undef TOML_ABI_NAMESPACE_START
|
||||
#undef TOML_ABSTRACT_BASE
|
||||
#undef TOML_ALWAYS_INLINE
|
||||
#undef TOML_ANON_NAMESPACE
|
||||
#undef TOML_ANON_NAMESPACE_END
|
||||
#undef TOML_ANON_NAMESPACE_START
|
||||
#undef TOML_ARM
|
||||
#undef TOML_ASSERT
|
||||
#undef TOML_ASSUME
|
||||
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
|
||||
#undef TOML_ATTR
|
||||
#undef TOML_CLANG
|
||||
#undef TOML_COMPILER_EXCEPTIONS
|
||||
#undef TOML_CONCAT
|
||||
#undef TOML_CONCAT_1
|
||||
#undef TOML_CONSTEVAL
|
||||
#undef TOML_CPP
|
||||
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
|
||||
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
|
||||
#undef TOML_DISABLE_INIT_WARNINGS
|
||||
#undef TOML_DISABLE_SPAM_WARNINGS
|
||||
#undef TOML_DISABLE_SHADOW_WARNINGS
|
||||
#undef TOML_DISABLE_SUGGEST_WARNINGS
|
||||
#undef TOML_DISABLE_SWITCH_WARNINGS
|
||||
#undef TOML_DISABLE_WARNINGS
|
||||
#undef TOML_ENABLE_WARNINGS
|
||||
#undef TOML_EMPTY_BASES
|
||||
#undef TOML_EVAL_BOOL_0
|
||||
#undef TOML_EVAL_BOOL_1
|
||||
#undef TOML_EXTERNAL_LINKAGE
|
||||
#undef TOML_FLOAT128
|
||||
#undef TOML_FLOAT16
|
||||
#undef TOML_FLOAT_CHARCONV
|
||||
#undef TOML_FP16
|
||||
#undef TOML_GCC
|
||||
#undef TOML_HAS_ATTR
|
||||
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
|
||||
#undef TOML_HAS_CHAR8
|
||||
#undef TOML_HAS_INCLUDE
|
||||
#undef TOML_ICC
|
||||
#undef TOML_ICC_CL
|
||||
#undef TOML_IMPLEMENTATION
|
||||
#undef TOML_IMPL_NAMESPACE_END
|
||||
#undef TOML_IMPL_NAMESPACE_START
|
||||
#undef TOML_INCLUDE_WINDOWS_H
|
||||
#undef TOML_INT128
|
||||
#undef TOML_INTELLISENSE
|
||||
#undef TOML_INTERNAL_LINKAGE
|
||||
#undef TOML_INT_CHARCONV
|
||||
#undef TOML_LANG_AT_LEAST
|
||||
#undef TOML_LANG_EFFECTIVE_VERSION
|
||||
#undef TOML_LANG_HIGHER_THAN
|
||||
#undef TOML_LANG_UNRELEASED
|
||||
#undef TOML_LAUNDER
|
||||
#undef TOML_LIFETIME_HOOKS
|
||||
#undef TOML_LIKELY
|
||||
#undef TOML_MAKE_FLAGS_
|
||||
#undef TOML_MAKE_FLAGS
|
||||
#undef TOML_MAKE_VERSION
|
||||
#undef TOML_MAY_THROW
|
||||
#undef TOML_MSVC
|
||||
#undef TOML_NAMESPACE
|
||||
#undef TOML_NAMESPACE_END
|
||||
#undef TOML_NAMESPACE_START
|
||||
#undef TOML_NEVER_INLINE
|
||||
#undef TOML_NODISCARD_CTOR
|
||||
#undef TOML_NO_DEFAULT_CASE
|
||||
#undef TOML_PARSER_TYPENAME
|
||||
#undef TOML_POP_WARNINGS
|
||||
#undef TOML_PUSH_WARNINGS
|
||||
#undef TOML_SA_LIST_BEG
|
||||
#undef TOML_SA_LIST_END
|
||||
#undef TOML_SA_LIST_NEW
|
||||
#undef TOML_SA_LIST_NXT
|
||||
#undef TOML_SA_LIST_SEP
|
||||
#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
|
||||
#undef TOML_SA_NEWLINE
|
||||
#undef TOML_SA_NODE_TYPE_LIST
|
||||
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
|
||||
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
|
||||
#undef TOML_SA_VALUE_FUNC_MESSAGE
|
||||
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
|
||||
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
|
||||
#undef TOML_SA_VALUE_MESSAGE_WSTRING
|
||||
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
|
||||
#undef TOML_TRIVIAL_ABI
|
||||
#undef TOML_UINT128
|
||||
#undef TOML_UNLIKELY
|
||||
#undef TOML_UNREACHABLE
|
||||
#undef TOML_USING_ANON_NAMESPACE
|
||||
#endif
|
||||
|
||||
#endif // INCLUDE_TOMLPLUSPLUS_H
|
|
@ -0,0 +1,961 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_value.h"
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
template <bool IsConst> class TOML_TRIVIAL_ABI array_iterator final {
|
||||
private:
|
||||
template <bool C> friend class array_iterator;
|
||||
friend class TOML_NAMESPACE::array;
|
||||
|
||||
using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
|
||||
using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
|
||||
using raw_iterator =
|
||||
std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
|
||||
|
||||
mutable raw_iterator raw_;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
array_iterator(raw_mutable_iterator raw) noexcept : raw_{raw} {}
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<C>>
|
||||
TOML_NODISCARD_CTOR array_iterator(raw_const_iterator raw) noexcept : raw_{raw} {}
|
||||
|
||||
public:
|
||||
using value_type = std::conditional_t<IsConst, const node, node>;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category =
|
||||
typename std::iterator_traits<raw_iterator>::iterator_category;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
array_iterator() noexcept = default;
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
array_iterator(const array_iterator &) noexcept = default;
|
||||
|
||||
array_iterator &operator=(const array_iterator &) noexcept = default;
|
||||
|
||||
array_iterator &operator++() noexcept // ++pre
|
||||
{
|
||||
++raw_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator operator++(int) noexcept // post++
|
||||
{
|
||||
array_iterator out{raw_};
|
||||
++raw_;
|
||||
return out;
|
||||
}
|
||||
|
||||
array_iterator &operator--() noexcept // --pre
|
||||
{
|
||||
--raw_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator operator--(int) noexcept // post--
|
||||
{
|
||||
array_iterator out{raw_};
|
||||
--raw_;
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const noexcept { return *raw_->get(); }
|
||||
|
||||
[[nodiscard]] pointer operator->() const noexcept { return raw_->get(); }
|
||||
|
||||
array_iterator &operator+=(ptrdiff_t rhs) noexcept {
|
||||
raw_ += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array_iterator &operator-=(ptrdiff_t rhs) noexcept {
|
||||
raw_ -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend array_iterator operator+(const array_iterator &lhs,
|
||||
ptrdiff_t rhs) noexcept {
|
||||
return {lhs.raw_ + rhs};
|
||||
}
|
||||
|
||||
[[nodiscard]] friend array_iterator operator+(ptrdiff_t lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return {rhs.raw_ + lhs};
|
||||
}
|
||||
|
||||
[[nodiscard]] friend array_iterator operator-(const array_iterator &lhs,
|
||||
ptrdiff_t rhs) noexcept {
|
||||
return {lhs.raw_ - rhs};
|
||||
}
|
||||
|
||||
[[nodiscard]] friend ptrdiff_t operator-(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ - rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator==(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ == rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator!=(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ != rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator<(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ < rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator<=(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ <= rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator>(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ > rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend bool operator>=(const array_iterator &lhs,
|
||||
const array_iterator &rhs) noexcept {
|
||||
return lhs.raw_ >= rhs.raw_;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator[](ptrdiff_t idx) const noexcept {
|
||||
return *(raw_ + idx)->get();
|
||||
}
|
||||
|
||||
TOML_DISABLE_WARNINGS;
|
||||
|
||||
template <bool C = IsConst, typename = std::enable_if_t<!C>>
|
||||
operator array_iterator<true>() const noexcept {
|
||||
return array_iterator<true>{raw_};
|
||||
}
|
||||
|
||||
TOML_ENABLE_WARNINGS;
|
||||
};
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
|
||||
using array_iterator = impl::array_iterator<false>;
|
||||
|
||||
/// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
|
||||
using const_array_iterator = impl::array_iterator<true>;
|
||||
|
||||
/// \brief A TOML array.
|
||||
///
|
||||
/// \detail The interface of this type is modeled after std::vector, with some
|
||||
/// additional considerations made for the heterogeneous nature of a
|
||||
/// TOML array.
|
||||
///
|
||||
/// \godbolt{sjK4da}
|
||||
///
|
||||
/// \cpp
|
||||
///
|
||||
/// toml::table tbl = toml::parse(R"(
|
||||
/// arr = [1, 2, 3, 4, 'five']
|
||||
/// )"sv);
|
||||
///
|
||||
/// // get the element as an array
|
||||
/// toml::array& arr = *tbl.get_as<toml::array>("arr");
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// // increment each element with visit()
|
||||
/// for (auto&& elem : arr)
|
||||
/// {
|
||||
/// elem.visit([](auto&& el) noexcept
|
||||
/// {
|
||||
/// if constexpr (toml::is_number<decltype(el)>)
|
||||
/// (*el)++;
|
||||
/// else if constexpr (toml::is_string<decltype(el)>)
|
||||
/// el = "six"sv;
|
||||
/// });
|
||||
/// }
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// // add and remove elements
|
||||
/// arr.push_back(7);
|
||||
/// arr.push_back(8.0f);
|
||||
/// arr.push_back("nine"sv);
|
||||
/// arr.erase(arr.cbegin());
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// // emplace elements
|
||||
/// arr.emplace_back<std::string>("ten");
|
||||
/// arr.emplace_back<toml::array>(11, 12.0);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, 3, 4, 'five' ]
|
||||
/// [ 2, 3, 4, 5, 'six' ]
|
||||
/// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ]
|
||||
/// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ]
|
||||
/// \eout
|
||||
class TOML_API array final : public node {
|
||||
private:
|
||||
/// \cond
|
||||
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
std::vector<std::unique_ptr<node>> elements;
|
||||
|
||||
void preinsertion_resize(size_t idx, size_t count) noexcept;
|
||||
|
||||
template <typename T> void emplace_back_if_not_empty_view(T &&val) noexcept {
|
||||
if constexpr (is_node_view<T>) {
|
||||
if (!val)
|
||||
return;
|
||||
}
|
||||
elements.emplace_back(impl::make_node(static_cast<T &&>(val)));
|
||||
}
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
void lh_ctor() noexcept;
|
||||
void lh_dtor() noexcept;
|
||||
#endif
|
||||
|
||||
[[nodiscard]] size_t total_leaf_count() const noexcept;
|
||||
|
||||
void flatten_child(array &&child, size_t &dest_index) noexcept;
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
using value_type = node;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = node &;
|
||||
using const_reference = const node &;
|
||||
|
||||
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
|
||||
using iterator = array_iterator;
|
||||
/// \brief A RandomAccessIterator for iterating over const elements in a
|
||||
/// toml::array.
|
||||
using const_iterator = const_array_iterator;
|
||||
|
||||
/// \brief Default constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
array() noexcept;
|
||||
|
||||
/// \brief Copy constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
array(const array &) noexcept;
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
array(array &&other) noexcept;
|
||||
|
||||
/// \brief Copy-assignment operator.
|
||||
array &operator=(const array &) noexcept;
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
array &operator=(array &&rhs) noexcept;
|
||||
|
||||
/// \brief Destructor.
|
||||
~array() noexcept override;
|
||||
|
||||
/// \brief Constructs an array with one or more initial elements.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2.0, 'three', [ 4, 5 ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \remark \parblock If you need to construct an array with one child array
|
||||
/// element, the array's move constructor will take precedence and perform
|
||||
/// a move-construction instead. You can use toml::inserter to suppress
|
||||
/// this behaviour: \cpp
|
||||
/// // desired result: [ [ 42 ] ]
|
||||
/// auto bad = toml::array{ toml::array{ 42 } }
|
||||
/// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
|
||||
/// std::cout << "bad: " << bad << "\n";
|
||||
/// std::cout << "good:" << good << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// bad: [ 42 ]
|
||||
/// good: [ [ 42 ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \endparblock
|
||||
///
|
||||
/// \tparam ElemType One of the TOML node or value types (or a type
|
||||
/// promotable to one).
|
||||
/// \tparam ElemTypes One of the TOML node or value types (or a type
|
||||
/// promotable to one). \param val The node or value used to initialize
|
||||
/// element 0. \param vals The nodes or values used to initialize
|
||||
/// elements 1...N.
|
||||
template <typename ElemType, typename... ElemTypes,
|
||||
typename = std::enable_if_t<
|
||||
(sizeof...(ElemTypes) > 0_sz) ||
|
||||
!std::is_same_v<impl::remove_cvref_t<ElemType>, array>>>
|
||||
TOML_NODISCARD_CTOR explicit array(ElemType &&val, ElemTypes &&...vals) {
|
||||
elements.reserve(sizeof...(ElemTypes) + 1_sz);
|
||||
emplace_back_if_not_empty_view(static_cast<ElemType &&>(val));
|
||||
if constexpr (sizeof...(ElemTypes) > 0) {
|
||||
(emplace_back_if_not_empty_view(static_cast<ElemTypes &&>(vals)), ...);
|
||||
}
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \name Type checks
|
||||
/// @{
|
||||
|
||||
[[nodiscard]] node_type type() const noexcept override;
|
||||
[[nodiscard]] bool is_table() const noexcept override;
|
||||
[[nodiscard]] bool is_array() const noexcept override;
|
||||
[[nodiscard]] bool is_value() const noexcept override;
|
||||
[[nodiscard]] array *as_array() noexcept override;
|
||||
[[nodiscard]] const array *as_array() const noexcept override;
|
||||
[[nodiscard]] bool is_array_of_tables() const noexcept override;
|
||||
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype,
|
||||
node *&first_nonmatch) noexcept override;
|
||||
[[nodiscard]] bool
|
||||
is_homogeneous(node_type ntype,
|
||||
const node *&first_nonmatch) const noexcept override;
|
||||
|
||||
template <typename ElemType = void>
|
||||
[[nodiscard]] bool is_homogeneous() const noexcept {
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
static_assert(std::is_void_v<type> ||
|
||||
((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
|
||||
"The template type argument of array::is_homogeneous() must be "
|
||||
"void or one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
return is_homogeneous(impl::node_type_of<type>);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Array operations
|
||||
/// @{
|
||||
|
||||
/// \brief Gets a reference to the element at a specific index.
|
||||
[[nodiscard]] node &operator[](size_t index) noexcept;
|
||||
/// \brief Gets a reference to the element at a specific index.
|
||||
[[nodiscard]] const node &operator[](size_t index) const noexcept;
|
||||
|
||||
/// \brief Returns a reference to the first element in the array.
|
||||
[[nodiscard]] node &front() noexcept;
|
||||
/// \brief Returns a reference to the first element in the array.
|
||||
[[nodiscard]] const node &front() const noexcept;
|
||||
/// \brief Returns a reference to the last element in the array.
|
||||
[[nodiscard]] node &back() noexcept;
|
||||
/// \brief Returns a reference to the last element in the array.
|
||||
[[nodiscard]] const node &back() const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to the first element.
|
||||
[[nodiscard]] iterator begin() noexcept;
|
||||
/// \brief Returns an iterator to the first element.
|
||||
[[nodiscard]] const_iterator begin() const noexcept;
|
||||
/// \brief Returns an iterator to the first element.
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept;
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last element.
|
||||
[[nodiscard]] iterator end() noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last element.
|
||||
[[nodiscard]] const_iterator end() const noexcept;
|
||||
/// \brief Returns an iterator to one-past-the-last element.
|
||||
[[nodiscard]] const_iterator cend() const noexcept;
|
||||
|
||||
/// \brief Returns true if the array is empty.
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
/// \brief Returns the number of elements in the array.
|
||||
[[nodiscard]] size_t size() const noexcept;
|
||||
/// \brief Reserves internal storage capacity up to a pre-determined number of
|
||||
/// elements.
|
||||
void reserve(size_t new_capacity);
|
||||
/// \brief Removes all elements from the array.
|
||||
void clear() noexcept;
|
||||
|
||||
/// \brief Returns the maximum number of elements that can be stored in an array on
|
||||
/// the current platform.
|
||||
[[nodiscard]] size_t max_size() const noexcept;
|
||||
/// \brief Returns the current max number of elements that may be held in the
|
||||
/// array's internal storage.
|
||||
[[nodiscard]] size_t capacity() const noexcept;
|
||||
/// \brief Requests the removal of any unused internal storage capacity.
|
||||
void shrink_to_fit();
|
||||
|
||||
/// \brief Inserts a new element at a specific position in the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 3 };
|
||||
/// arr.insert(arr.cbegin() + 1, "two");
|
||||
/// arr.insert(arr.cend(), toml::array{ 4, 5 });
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 'two', 3, [ 4, 5 ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array,
|
||||
/// or a native TOML value type (or a type
|
||||
/// promotable to one). \param pos The insertion position. \param val
|
||||
/// The node or value being inserted.
|
||||
///
|
||||
/// \returns \conditional_return{Valid input}
|
||||
/// An iterator to the newly-inserted element.
|
||||
/// \conditional_return{Input is an empty toml::node_view}
|
||||
/// end()
|
||||
///
|
||||
/// \attention The return value will always be `end()` if the input value was an
|
||||
/// empty toml::node_view, because no insertion can take place. This is
|
||||
/// the only circumstance in which this can occur.
|
||||
template <typename ElemType>
|
||||
iterator insert(const_iterator pos, ElemType &&val) noexcept {
|
||||
if constexpr (is_node_view<ElemType>) {
|
||||
if (!val)
|
||||
return end();
|
||||
}
|
||||
return {
|
||||
elements.emplace(pos.raw_, impl::make_node(static_cast<ElemType &&>(val)))};
|
||||
}
|
||||
|
||||
/// \brief Repeatedly inserts a new element starting at a specific position in the
|
||||
/// array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{
|
||||
/// "with an evil twinkle in its eye the goose said",
|
||||
/// "and immediately we knew peace was never an option."
|
||||
/// };
|
||||
/// arr.insert(arr.cbegin() + 1, 3, "honk");
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [
|
||||
/// 'with an evil twinkle in its eye the goose said',
|
||||
/// 'honk',
|
||||
/// 'honk',
|
||||
/// 'honk',
|
||||
/// 'and immediately we knew peace was never an option.'
|
||||
/// ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array,
|
||||
/// or a native TOML value type (or a type
|
||||
/// promotable to one). \param pos The insertion position. \param count
|
||||
/// The number of times the node or value should be inserted. \param val
|
||||
/// The node or value being inserted.
|
||||
///
|
||||
/// \returns \conditional_return{Valid input}
|
||||
/// An iterator to the newly-inserted element.
|
||||
/// \conditional_return{count == 0}
|
||||
/// A copy of pos
|
||||
/// \conditional_return{Input is an empty toml::node_view}
|
||||
/// end()
|
||||
///
|
||||
/// \attention The return value will always be `end()` if the input value was an
|
||||
/// empty toml::node_view, because no insertion can take place. This is
|
||||
/// the only circumstance in which this can occur.
|
||||
template <typename ElemType>
|
||||
iterator insert(const_iterator pos, size_t count, ElemType &&val) noexcept {
|
||||
if constexpr (is_node_view<ElemType>) {
|
||||
if (!val)
|
||||
return end();
|
||||
}
|
||||
switch (count) {
|
||||
case 0:
|
||||
return {elements.begin() + (pos.raw_ - elements.cbegin())};
|
||||
case 1:
|
||||
return insert(pos, static_cast<ElemType &&>(val));
|
||||
default: {
|
||||
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
|
||||
preinsertion_resize(start_idx, count);
|
||||
size_t i = start_idx;
|
||||
for (size_t e = start_idx + count - 1_sz; i < e; i++)
|
||||
elements[i].reset(impl::make_node(val));
|
||||
|
||||
//# potentially move the initial value into the last element
|
||||
elements[i].reset(impl::make_node(static_cast<ElemType &&>(val)));
|
||||
return {elements.begin() + static_cast<ptrdiff_t>(start_idx)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Inserts a range of elements into the array at a specific position.
|
||||
///
|
||||
/// \tparam Iter An iterator type. Must satisfy ForwardIterator.
|
||||
/// \param pos The insertion position.
|
||||
/// \param first Iterator to the first node or value being inserted.
|
||||
/// \param last Iterator to the one-past-the-last node or value being inserted.
|
||||
///
|
||||
/// \returns \conditional_return{Valid input}
|
||||
/// An iterator to the first newly-inserted element.
|
||||
/// \conditional_return{first >= last}
|
||||
/// A copy of pos
|
||||
/// \conditional_return{All objects in the range were empty
|
||||
/// toml::node_views} A copy of pos
|
||||
template <typename Iter>
|
||||
iterator insert(const_iterator pos, Iter first, Iter last) noexcept {
|
||||
const auto distance = std::distance(first, last);
|
||||
if (distance <= 0)
|
||||
return {elements.begin() + (pos.raw_ - elements.cbegin())};
|
||||
else {
|
||||
auto count = distance;
|
||||
using deref_type = decltype(*first);
|
||||
if constexpr (is_node_view<deref_type>) {
|
||||
for (auto it = first; it != last; it++)
|
||||
if (!(*it))
|
||||
count--;
|
||||
if (!count)
|
||||
return {elements.begin() + (pos.raw_ - elements.cbegin())};
|
||||
}
|
||||
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
|
||||
preinsertion_resize(start_idx, static_cast<size_t>(count));
|
||||
size_t i = start_idx;
|
||||
for (auto it = first; it != last; it++) {
|
||||
if constexpr (is_node_view<deref_type>) {
|
||||
if (!(*it))
|
||||
continue;
|
||||
}
|
||||
if constexpr (std::is_rvalue_reference_v<deref_type>)
|
||||
elements[i++].reset(impl::make_node(std::move(*it)));
|
||||
else
|
||||
elements[i++].reset(impl::make_node(*it));
|
||||
}
|
||||
return {elements.begin() + static_cast<ptrdiff_t>(start_idx)};
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Inserts a range of elements into the array at a specific position.
|
||||
///
|
||||
/// \tparam ElemType toml::node_view, toml::table, toml::array, or a native
|
||||
/// TOML value type (or a type promotable to
|
||||
/// one). \param pos The insertion position. \param
|
||||
/// ilist An initializer list containing the values to be inserted.
|
||||
///
|
||||
/// \returns \conditional_return{Valid input}
|
||||
/// An iterator to the first newly-inserted element.
|
||||
/// \conditional_return{Input list is empty}
|
||||
/// A copy of pos
|
||||
/// \conditional_return{All objects in the list were empty
|
||||
/// toml::node_views}
|
||||
/// A copy of pos
|
||||
template <typename ElemType>
|
||||
iterator insert(const_iterator pos,
|
||||
std::initializer_list<ElemType> ilist) noexcept {
|
||||
return insert(pos, ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new element at a specific position in the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
///
|
||||
/// //add a string using std::string's substring constructor
|
||||
/// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 'drill', 2 ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::table, toml::array, or any native TOML value type.
|
||||
/// \tparam Args Value constructor argument types.
|
||||
/// \param pos The insertion position.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns An iterator to the inserted element.
|
||||
///
|
||||
/// \remarks There is no difference between insert() and emplace()
|
||||
/// for trivial value types (floats, ints, bools).
|
||||
template <typename ElemType, typename... Args>
|
||||
iterator emplace(const_iterator pos, Args &&...args) noexcept {
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"Emplacement type parameter must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
return {elements.emplace(
|
||||
pos.raw_, new impl::wrap_node<type>{static_cast<Args &&>(args)...})};
|
||||
}
|
||||
|
||||
/// \brief Removes the specified element from the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.erase(arr.cbegin() + 1);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, 3 ]
|
||||
/// [ 1, 3 ]
|
||||
/// \eout
|
||||
///
|
||||
/// \param pos Iterator to the element being erased.
|
||||
///
|
||||
/// \returns Iterator to the first element immediately following the removed
|
||||
/// element.
|
||||
iterator erase(const_iterator pos) noexcept;
|
||||
|
||||
/// \brief Removes the elements in the range [first, last) from the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, "bad", "karma" 2 };
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 'bad', 'karma', 3 ]
|
||||
/// [ 1, 3 ]
|
||||
/// \eout
|
||||
///
|
||||
/// \param first Iterator to the first element being erased.
|
||||
/// \param last Iterator to the one-past-the-last element being erased.
|
||||
///
|
||||
/// \returns Iterator to the first element immediately following the last removed
|
||||
/// element.
|
||||
iterator erase(const_iterator first, const_iterator last) noexcept;
|
||||
|
||||
/// \brief Resizes the array.
|
||||
///
|
||||
/// \detail \godbolt{W5zqx3}
|
||||
///
|
||||
/// \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.resize(6, 42);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.resize(2, 0);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, 3 ]
|
||||
/// [ 1, 2, 3, 42, 42, 42 ]
|
||||
/// [ 1, 2 ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML
|
||||
/// value type (or a type promotable to one).
|
||||
///
|
||||
/// \param new_size The number of elements the array will
|
||||
/// have after resizing.
|
||||
/// \param default_init_val The node or value used to initialize new
|
||||
/// elements if the array needs to grow.
|
||||
template <typename ElemType>
|
||||
void resize(size_t new_size, ElemType &&default_init_val) noexcept {
|
||||
static_assert(!is_node_view<ElemType>,
|
||||
"The default element type argument to toml::array::resize may not "
|
||||
"be toml::node_view.");
|
||||
|
||||
if (!new_size)
|
||||
elements.clear();
|
||||
else if (new_size < elements.size())
|
||||
elements.resize(new_size);
|
||||
else if (new_size > elements.size())
|
||||
insert(cend(), new_size - elements.size(),
|
||||
static_cast<ElemType &&>(default_init_val));
|
||||
}
|
||||
|
||||
/// \brief Shrinks the array to the given size.
|
||||
///
|
||||
/// \detail \godbolt{rxEzK5}
|
||||
///
|
||||
/// \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.truncate(5); // no-op
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.truncate(1);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, 3 ]
|
||||
/// [ 1, 2, 3 ]
|
||||
/// [ 1]
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks Does nothing if the requested size is larger than or equal to
|
||||
/// the current size.
|
||||
void truncate(size_t new_size);
|
||||
|
||||
/// \brief Appends a new element to the end of the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
/// arr.push_back(3);
|
||||
/// arr.push_back(4.0);
|
||||
/// arr.push_back(toml::array{ 5, "six"sv });
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array,
|
||||
/// or a native TOML value type
|
||||
/// \param val The node or value being added.
|
||||
///
|
||||
/// \attention No insertion takes place if the input value is an empty
|
||||
/// toml::node_view. This is the only circumstance in which
|
||||
/// this can occur.
|
||||
template <typename ElemType> void push_back(ElemType &&val) noexcept {
|
||||
emplace_back_if_not_empty_view(static_cast<ElemType &&>(val));
|
||||
}
|
||||
|
||||
/// \brief Emplaces a new element at the end of the array.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2 };
|
||||
/// arr.emplace_back<toml::array>(3, "four"sv);
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, [ 3, 'four' ] ]
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::table, toml::array, or a native TOML value type
|
||||
/// \tparam Args Value constructor argument types.
|
||||
/// \param args Arguments to forward to the value's constructor.
|
||||
///
|
||||
/// \returns A reference to the newly-constructed element.
|
||||
///
|
||||
/// \remarks There is no difference between push_back() and emplace_back()
|
||||
/// For trivial value types (floats, ints, bools).
|
||||
template <typename ElemType, typename... Args>
|
||||
decltype(auto) emplace_back(Args &&...args) noexcept {
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"Emplacement type parameter must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
auto nde = new impl::wrap_node<type>{static_cast<Args &&>(args)...};
|
||||
elements.emplace_back(nde);
|
||||
return *nde;
|
||||
}
|
||||
|
||||
/// \brief Removes the last element from the array.
|
||||
void pop_back() noexcept;
|
||||
|
||||
/// \brief Gets the element at a specific index.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 99, "bottles of beer on the wall" };
|
||||
/// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n";
|
||||
/// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n";
|
||||
/// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
|
||||
/// if (toml::node* val = arr.get(0))
|
||||
/// std::cout << "element [0] is an "sv << val->type() << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// element [0] exists: true
|
||||
/// element [1] exists: true
|
||||
/// element [2] exists: false
|
||||
/// element [0] is an integer
|
||||
/// \eout
|
||||
///
|
||||
/// \param index The element's index.
|
||||
///
|
||||
/// \returns A pointer to the element at the specified index if one existed,
|
||||
/// or nullptr.
|
||||
[[nodiscard]] node *get(size_t index) noexcept;
|
||||
|
||||
/// \brief Gets the element at a specific index (const overload).
|
||||
///
|
||||
/// \param index The element's index.
|
||||
///
|
||||
/// \returns A pointer to the element at the specified index if one existed,
|
||||
/// or nullptr.
|
||||
[[nodiscard]] const node *get(size_t index) const noexcept;
|
||||
|
||||
/// \brief Gets the element at a specific index if it is a particular type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
|
||||
/// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
|
||||
/// std::cout << "element [0] is an integer with value "sv << *val << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// element [0] is an integer with value 42
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType toml::table, toml::array, or a native TOML value type
|
||||
/// \param index The element's index.
|
||||
///
|
||||
/// \returns A pointer to the selected element if it existed and was of the
|
||||
/// specified type, or nullptr.
|
||||
template <typename ElemType>
|
||||
[[nodiscard]] impl::wrap_node<ElemType> *get_as(size_t index) noexcept {
|
||||
if (auto val = get(index))
|
||||
return val->as<ElemType>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Gets the element at a specific index if it is a particular type (const
|
||||
/// overload).
|
||||
///
|
||||
/// \tparam ElemType toml::table, toml::array, or a native TOML value type
|
||||
/// \param index The element's index.
|
||||
///
|
||||
/// \returns A pointer to the selected element if it existed and was of the
|
||||
/// specified type, or nullptr.
|
||||
template <typename ElemType>
|
||||
[[nodiscard]] const impl::wrap_node<ElemType> *get_as(size_t index) const noexcept {
|
||||
if (auto val = get(index))
|
||||
return val->as<ElemType>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Flattens this array, recursively hoisting the contents of child arrays
|
||||
/// up into itself.
|
||||
///
|
||||
/// \detail \cpp
|
||||
///
|
||||
/// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6,
|
||||
/// toml::array{} }; std::cout << arr << "\n";
|
||||
///
|
||||
/// arr.flatten();
|
||||
/// std::cout << arr << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
|
||||
/// [ 1, 2, 3, 4, 5, 6 ]
|
||||
/// \eout
|
||||
///
|
||||
/// \remarks Arrays inside child tables are not flattened.
|
||||
///
|
||||
/// \returns A reference to the array.
|
||||
array &flatten() &;
|
||||
|
||||
/// \brief Flattens this array, recursively hoisting the contents of child arrays
|
||||
/// up into itself (rvalue overload). \returns An rvalue reference to the array.
|
||||
array &&flatten() && { return static_cast<toml::array &&>(this->flatten()); }
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Equality
|
||||
/// @{
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS array.
|
||||
/// \param rhs The RHS array.
|
||||
///
|
||||
/// \returns True if the arrays contained the same elements.
|
||||
friend bool operator==(const array &lhs, const array &rhs) noexcept;
|
||||
|
||||
/// \brief Inequality operator.
|
||||
///
|
||||
/// \param lhs The LHS array.
|
||||
/// \param rhs The RHS array.
|
||||
///
|
||||
/// \returns True if the arrays did not contain the same elements.
|
||||
friend bool operator!=(const array &lhs, const array &rhs) noexcept;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
[[nodiscard]] static bool container_equality(const array &lhs,
|
||||
const T &rhs) noexcept {
|
||||
using element_type = std::remove_const_t<typename T::value_type>;
|
||||
static_assert(impl::is_native<element_type> ||
|
||||
impl::is_losslessly_convertible_to_native<element_type>,
|
||||
"Container element type must be (or be promotable to) one of the "
|
||||
"TOML value types");
|
||||
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
if (rhs.size() == 0_sz)
|
||||
return true;
|
||||
|
||||
size_t i{};
|
||||
for (auto &list_elem : rhs) {
|
||||
const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
|
||||
if (!elem || *elem != list_elem)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Initializer list equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const array &lhs,
|
||||
const std::initializer_list<T> &rhs) noexcept {
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array &, const std::initializer_list<T> &,
|
||||
template <typename T>
|
||||
);
|
||||
|
||||
/// \brief Vector equality operator.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const array &lhs,
|
||||
const std::vector<T> &rhs) noexcept {
|
||||
return container_equality(lhs, rhs);
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const array &, const std::vector<T> &,
|
||||
template <typename T>
|
||||
);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Prints the array out to a stream as formatted TOML.
|
||||
template <typename Char>
|
||||
friend std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &,
|
||||
const array &);
|
||||
// implemented in toml_default_formatter.h
|
||||
};
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
|
@ -0,0 +1,356 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_array.h"
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::lh_ctor() noexcept
|
||||
{
|
||||
TOML_ARRAY_CREATED;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::lh_dtor() noexcept
|
||||
{
|
||||
TOML_ARRAY_DESTROYED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::array() noexcept
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::array(const array& other) noexcept
|
||||
: node( other )
|
||||
{
|
||||
elements.reserve(other.elements.size());
|
||||
for (const auto& elem : other)
|
||||
elements.emplace_back(impl::make_node(elem));
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::array(array&& other) noexcept
|
||||
: node( std::move(other) ),
|
||||
elements{ std::move(other.elements) }
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array& array::operator= (const array& rhs) noexcept
|
||||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
node::operator=(rhs);
|
||||
elements.clear();
|
||||
elements.reserve(rhs.elements.size());
|
||||
for (const auto& elem : rhs)
|
||||
elements.emplace_back(impl::make_node(elem));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array& array::operator= (array&& rhs) noexcept
|
||||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
node::operator=(std::move(rhs));
|
||||
elements = std::move(rhs.elements);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::~array() noexcept
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_dtor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::preinsertion_resize(size_t idx, size_t count) noexcept
|
||||
{
|
||||
TOML_ASSERT(idx <= elements.size());
|
||||
TOML_ASSERT(count >= 1_sz);
|
||||
const auto old_size = elements.size();
|
||||
const auto new_size = old_size + count;
|
||||
const auto inserting_at_end = idx == old_size;
|
||||
elements.resize(new_size);
|
||||
if (!inserting_at_end)
|
||||
{
|
||||
for(size_t left = old_size, right = new_size - 1_sz; left --> idx; right--)
|
||||
elements[right] = std::move(elements[left]);
|
||||
}
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) node_type array::type() const noexcept { return node_type::array; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_table() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_array() const noexcept { return true; }
|
||||
TOML_MEMBER_ATTR(const) bool array::is_value() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) const array* array::as_array() const noexcept { return this; }
|
||||
TOML_MEMBER_ATTR(const) array* array::as_array() noexcept { return this; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *elements[index]; }
|
||||
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *elements[index]; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *elements.front(); }
|
||||
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *elements.back(); }
|
||||
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *elements.front(); }
|
||||
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *elements.back(); }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { elements.begin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { elements.end() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { elements.cbegin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { elements.cend() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { elements.begin() }; }
|
||||
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { elements.end() }; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return elements.size(); }
|
||||
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return elements.capacity(); }
|
||||
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return elements.empty(); }
|
||||
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return elements.max_size(); }
|
||||
|
||||
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { elements.reserve(new_capacity); }
|
||||
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { elements.clear(); }
|
||||
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { elements.shrink_to_fit(); }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool array::is_homogeneous(node_type ntype) const noexcept
|
||||
{
|
||||
if (elements.empty())
|
||||
return false;
|
||||
|
||||
if (ntype == node_type::none)
|
||||
ntype = elements[0]->type();
|
||||
|
||||
for (const auto& val : elements)
|
||||
if (val->type() != ntype)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace impl
|
||||
{
|
||||
template <typename T, typename U>
|
||||
TOML_INTERNAL_LINKAGE
|
||||
bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept
|
||||
{
|
||||
if (elements.empty())
|
||||
{
|
||||
first_nonmatch = {};
|
||||
return false;
|
||||
}
|
||||
if (ntype == node_type::none)
|
||||
ntype = elements[0]->type();
|
||||
for (const auto& val : elements)
|
||||
{
|
||||
if (val->type() != ntype)
|
||||
{
|
||||
first_nonmatch = val.get();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool array::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
|
||||
{
|
||||
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
|
||||
{
|
||||
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::truncate(size_t new_size)
|
||||
{
|
||||
if (new_size < elements.size())
|
||||
elements.resize(new_size);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::iterator array::erase(const_iterator pos) noexcept
|
||||
{
|
||||
return { elements.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
|
||||
{
|
||||
return { elements.erase(first.raw_, last.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::pop_back() noexcept
|
||||
{
|
||||
elements.pop_back();
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
TOML_ATTR(pure)
|
||||
node* array::get(size_t index) noexcept
|
||||
{
|
||||
return index < elements.size() ? elements[index].get() : nullptr;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
TOML_ATTR(pure)
|
||||
const node* array::get(size_t index) const noexcept
|
||||
{
|
||||
return index < elements.size() ? elements[index].get() : nullptr;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator == (const array& lhs, const array& rhs) noexcept
|
||||
{
|
||||
if (&lhs == &rhs)
|
||||
return true;
|
||||
if (lhs.elements.size() != rhs.elements.size())
|
||||
return false;
|
||||
for (size_t i = 0, e = lhs.elements.size(); i < e; i++)
|
||||
{
|
||||
const auto lhs_type = lhs.elements[i]->type();
|
||||
const node& rhs_ = *rhs.elements[i];
|
||||
const auto rhs_type = rhs_.type();
|
||||
if (lhs_type != rhs_type)
|
||||
return false;
|
||||
|
||||
const bool equal = lhs.elements[i]->visit([&](const auto& lhs_) noexcept
|
||||
{
|
||||
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
|
||||
});
|
||||
if (!equal)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator != (const array& lhs, const array& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
size_t array::total_leaf_count() const noexcept
|
||||
{
|
||||
size_t leaves{};
|
||||
for (size_t i = 0, e = elements.size(); i < e; i++)
|
||||
{
|
||||
auto arr = elements[i]->as_array();
|
||||
leaves += arr ? arr->total_leaf_count() : 1_sz;
|
||||
}
|
||||
return leaves;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void array::flatten_child(array&& child, size_t& dest_index) noexcept
|
||||
{
|
||||
for (size_t i = 0, e = child.size(); i < e; i++)
|
||||
{
|
||||
auto type = child.elements[i]->type();
|
||||
if (type == node_type::array)
|
||||
{
|
||||
array& arr = *reinterpret_cast<array*>(child.elements[i].get());
|
||||
if (!arr.empty())
|
||||
flatten_child(std::move(arr), dest_index);
|
||||
}
|
||||
else
|
||||
elements[dest_index++] = std::move(child.elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
array& array::flatten() &
|
||||
{
|
||||
if (elements.empty())
|
||||
return *this;
|
||||
|
||||
bool requires_flattening = false;
|
||||
size_t size_after_flattening = elements.size();
|
||||
for (size_t i = elements.size(); i --> 0_sz;)
|
||||
{
|
||||
auto arr = elements[i]->as_array();
|
||||
if (!arr)
|
||||
continue;
|
||||
size_after_flattening--; //discount the array itself
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
if (leaf_count > 0_sz)
|
||||
{
|
||||
requires_flattening = true;
|
||||
size_after_flattening += leaf_count;
|
||||
}
|
||||
else
|
||||
elements.erase(elements.cbegin() + static_cast<ptrdiff_t>(i));
|
||||
}
|
||||
|
||||
if (!requires_flattening)
|
||||
return *this;
|
||||
|
||||
elements.reserve(size_after_flattening);
|
||||
|
||||
size_t i = 0;
|
||||
while (i < elements.size())
|
||||
{
|
||||
auto arr = elements[i]->as_array();
|
||||
if (!arr)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<node> arr_storage = std::move(elements[i]);
|
||||
const auto leaf_count = arr->total_leaf_count();
|
||||
if (leaf_count > 1_sz)
|
||||
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
|
||||
flatten_child(std::move(*arr), i); //increments i
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool array::is_array_of_tables() const noexcept
|
||||
{
|
||||
return is_homogeneous(node_type::table);
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,362 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A local date.
|
||||
struct TOML_TRIVIAL_ABI date {
|
||||
/// \brief The year component.
|
||||
uint16_t year;
|
||||
/// \brief The month component, from 1 - 12.
|
||||
uint8_t month;
|
||||
/// \brief The day component, from 1 - 31.
|
||||
uint8_t day;
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]] friend constexpr bool operator==(date lhs, date rhs) noexcept {
|
||||
return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]] friend constexpr bool operator!=(date lhs, date rhs) noexcept {
|
||||
return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE static constexpr uint32_t pack(date d) noexcept {
|
||||
return static_cast<uint32_t>(d.year) << 16 | static_cast<uint32_t>(d.month) << 8 |
|
||||
static_cast<uint32_t>(d.day);
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator<(date lhs, date rhs) noexcept {
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator<=(date lhs, date rhs) noexcept {
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator>(date lhs, date rhs) noexcept {
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator>=(date lhs, date rhs) noexcept {
|
||||
return pack(lhs) >= pack(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date{ 1987, 3, 16 } << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const date &rhs) {
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &, const date &);
|
||||
#endif
|
||||
|
||||
/// \brief A local time-of-day.
|
||||
struct TOML_TRIVIAL_ABI time {
|
||||
/// \brief The hour component, from 0 - 23.
|
||||
uint8_t hour;
|
||||
/// \brief The minute component, from 0 - 59.
|
||||
uint8_t minute;
|
||||
/// \brief The second component, from 0 - 59.
|
||||
uint8_t second;
|
||||
/// \brief The fractional nanoseconds component, from 0 - 999999999.
|
||||
uint32_t nanosecond;
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]] friend constexpr bool operator==(const time &lhs,
|
||||
const time &rhs) noexcept {
|
||||
return lhs.hour == rhs.hour && lhs.minute == rhs.minute &&
|
||||
lhs.second == rhs.second && lhs.nanosecond == rhs.nanosecond;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]] friend constexpr bool operator!=(const time &lhs,
|
||||
const time &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE static constexpr uint64_t pack(time t) noexcept {
|
||||
return static_cast<uint64_t>(t.hour) << 48 |
|
||||
static_cast<uint64_t>(t.minute) << 40 |
|
||||
static_cast<uint64_t>(t.second) << 32 |
|
||||
static_cast<uint64_t>(t.nanosecond);
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator<(time lhs, time rhs) noexcept {
|
||||
return pack(lhs) < pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator<=(time lhs, time rhs) noexcept {
|
||||
return pack(lhs) <= pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator>(time lhs, time rhs) noexcept {
|
||||
return pack(lhs) > pack(rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator>=(time lhs, time rhs) noexcept {
|
||||
return pack(lhs) >= pack(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time{ 10, 20, 34 } << "\n";
|
||||
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 10:20:34
|
||||
/// 10:20:34.5
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const time &rhs) {
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &, const time &);
|
||||
#endif
|
||||
|
||||
/// \brief A timezone offset.
|
||||
struct TOML_TRIVIAL_ABI time_offset {
|
||||
/// \brief Offset from UTC+0, in minutes.
|
||||
int16_t minutes;
|
||||
|
||||
/// \brief Default-constructs a zero time-offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset() noexcept : minutes{} {}
|
||||
|
||||
/// \brief Constructs a timezone offset from separate hour and minute totals.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
|
||||
/// std::cout << toml::time_offset{ 0, 0 } << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// +02:30
|
||||
/// -01:30
|
||||
/// -02:30
|
||||
/// Z
|
||||
/// \eout
|
||||
///
|
||||
/// \param h The total hours.
|
||||
/// \param m The total minutes.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr time_offset(int8_t h, int8_t m) noexcept
|
||||
: minutes{static_cast<int16_t>(h * 60 + m)} {}
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]] friend constexpr bool operator==(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes == rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]] friend constexpr bool operator!=(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes != rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator<(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes < rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator<=(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes <= rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator>(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes > rhs.minutes;
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator>=(time_offset lhs,
|
||||
time_offset rhs) noexcept {
|
||||
return lhs.minutes >= rhs.minutes;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
|
||||
/// std::cout << toml::time_offset{ 2, -30 } << "\n";
|
||||
/// std::cout << toml::time_offset{} << "\n";
|
||||
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
|
||||
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// +02:30
|
||||
/// +01:30
|
||||
/// Z
|
||||
/// -01:30
|
||||
/// -02:30
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const time_offset &rhs) {
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const time_offset &);
|
||||
#endif
|
||||
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt);
|
||||
|
||||
/// \brief A date-time.
|
||||
struct date_time {
|
||||
/// \brief The date component.
|
||||
toml::date date;
|
||||
/// \brief The time component.
|
||||
toml::time time;
|
||||
/// \brief The timezone offset component.
|
||||
///
|
||||
/// \remarks The date_time is said to be 'local' if the offset is empty.
|
||||
optional<toml::time_offset> offset;
|
||||
|
||||
/// \brief Default-constructs a zero date-time.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time() noexcept
|
||||
: date{}, time{}, offset{} // TINAE - icc bugfix
|
||||
{}
|
||||
|
||||
/// \brief Constructs a local date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t) noexcept
|
||||
: date{d}, time{t}, offset{} // TINAE - icc bugfix
|
||||
{}
|
||||
|
||||
/// \brief Constructs an offset date-time.
|
||||
///
|
||||
/// \param d The date component.
|
||||
/// \param t The time component.
|
||||
/// \param off The timezone offset.
|
||||
TOML_NODISCARD_CTOR
|
||||
constexpr date_time(toml::date d, toml::time t, toml::time_offset off) noexcept
|
||||
: date{d}, time{t}, offset{off} {}
|
||||
|
||||
/// \brief Returns true if this date_time does not contain timezone offset
|
||||
/// information.
|
||||
[[nodiscard]] constexpr bool is_local() const noexcept {
|
||||
return !offset.has_value();
|
||||
}
|
||||
|
||||
/// \brief Equality operator.
|
||||
[[nodiscard]] friend constexpr bool operator==(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
return lhs.date == rhs.date && lhs.time == rhs.time && lhs.offset == rhs.offset;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
[[nodiscard]] friend constexpr bool operator!=(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator<(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
if (lhs.date != rhs.date)
|
||||
return lhs.date < rhs.date;
|
||||
if (lhs.time != rhs.time)
|
||||
return lhs.time < rhs.time;
|
||||
return lhs.offset < rhs.offset;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator<=(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
if (lhs.date != rhs.date)
|
||||
return lhs.date < rhs.date;
|
||||
if (lhs.time != rhs.time)
|
||||
return lhs.time < rhs.time;
|
||||
return lhs.offset <= rhs.offset;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
[[nodiscard]] friend constexpr bool operator>(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend constexpr bool operator>=(const date_time &lhs,
|
||||
const date_time &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
|
||||
|
||||
/// \brief Prints a date_time out to a stream in RFC 3339 format.
|
||||
/// \detail \cpp
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << "\n";
|
||||
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } <<
|
||||
/// "\n"; std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 1987-03-16T10:20:34
|
||||
/// 1987-03-16T10:20:34-02:30
|
||||
/// 1987-03-16T10:20:34Z
|
||||
/// \eout
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const date_time &rhs) {
|
||||
impl::print_to_stream(rhs, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &, const date_time &);
|
||||
#endif
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
|
@ -0,0 +1,441 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_array.h"
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_utf8.h"
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
[[nodiscard]] TOML_API std::string default_formatter_make_key_segment(
|
||||
const std::string &) noexcept;
|
||||
[[nodiscard]] TOML_API size_t default_formatter_inline_columns(const node &) noexcept;
|
||||
[[nodiscard]] TOML_API bool default_formatter_forces_multiline(const node &,
|
||||
size_t = 0) noexcept;
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
|
||||
///
|
||||
/// \remarks You generally don't need to create an instance of this class explicitly;
|
||||
/// the stream operators of the TOML node types already print
|
||||
/// themselves out using this formatter.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::table{{
|
||||
/// { "description", "This is some TOML, yo." },
|
||||
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
|
||||
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
|
||||
/// { "table", toml::table{{ { "foo", "bar" } }} }
|
||||
/// }};
|
||||
///
|
||||
/// // these two lines are equivalent:
|
||||
/// std::cout << toml::default_formatter{ tbl } << "\n";
|
||||
/// std::cout << tbl << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// description = "This is some TOML, yo."
|
||||
/// fruit = ["apple", "orange", "pear"]
|
||||
/// numbers = [1, 2, 3, 4, 5]
|
||||
///
|
||||
/// [table]
|
||||
/// foo = "bar"
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The underlying character type of the output stream. Must be 1
|
||||
/// byte in size.
|
||||
template <typename Char = char>
|
||||
class TOML_API default_formatter final : impl::formatter<Char> {
|
||||
private:
|
||||
/// \cond
|
||||
|
||||
using base = impl::formatter<Char>;
|
||||
std::vector<std::string> key_path;
|
||||
bool pending_table_separator_ = false;
|
||||
|
||||
void print_pending_table_separator() {
|
||||
if (pending_table_separator_) {
|
||||
base::print_newline(true);
|
||||
base::print_newline(true);
|
||||
pending_table_separator_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void print_key_segment(const std::string &str) {
|
||||
if (str.empty())
|
||||
impl::print_to_stream("''"sv, base::stream());
|
||||
else {
|
||||
bool requiresQuotes = false;
|
||||
{
|
||||
impl::utf8_decoder decoder;
|
||||
for (size_t i = 0; i < str.length() && !requiresQuotes; i++) {
|
||||
decoder(static_cast<uint8_t>(str[i]));
|
||||
if (decoder.error())
|
||||
requiresQuotes = true;
|
||||
else if (decoder.has_code_point())
|
||||
requiresQuotes = !impl::is_bare_key_character(decoder.codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresQuotes) {
|
||||
impl::print_to_stream('"', base::stream());
|
||||
impl::print_to_stream_with_escapes(str, base::stream());
|
||||
impl::print_to_stream('"', base::stream());
|
||||
} else
|
||||
impl::print_to_stream(str, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print_key_path() {
|
||||
for (const auto &segment : key_path) {
|
||||
if (std::addressof(segment) > key_path.data())
|
||||
impl::print_to_stream('.', base::stream());
|
||||
impl::print_to_stream(segment, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print_inline(const table & /*tbl*/);
|
||||
|
||||
void print(const array &arr) {
|
||||
if (arr.empty())
|
||||
impl::print_to_stream("[]"sv, base::stream());
|
||||
else {
|
||||
const auto original_indent = base::indent();
|
||||
const auto multiline = impl::default_formatter_forces_multiline(
|
||||
arr, base::indent_columns *
|
||||
static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
|
||||
impl::print_to_stream("["sv, base::stream());
|
||||
if (multiline) {
|
||||
if (original_indent < 0)
|
||||
base::indent(0);
|
||||
base::increase_indent();
|
||||
} else
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
if (i > 0_sz) {
|
||||
impl::print_to_stream(',', base::stream());
|
||||
if (!multiline)
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
}
|
||||
|
||||
if (multiline) {
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
}
|
||||
|
||||
auto &v = arr[i];
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type) {
|
||||
case node_type::table:
|
||||
print_inline(*reinterpret_cast<const table *>(&v));
|
||||
break;
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array *>(&v));
|
||||
break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
if (multiline) {
|
||||
base::indent(original_indent);
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
} else
|
||||
impl::print_to_stream(' ', base::stream());
|
||||
impl::print_to_stream("]"sv, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print(const table &tbl) {
|
||||
static constexpr auto is_non_inline_array_of_tables = [](auto &&nde) noexcept {
|
||||
auto arr = nde.as_array();
|
||||
return arr && arr->is_array_of_tables() &&
|
||||
!arr->template get_as<table>(0_sz)->is_inline();
|
||||
};
|
||||
|
||||
// values, arrays, and inline tables/table arrays
|
||||
for (auto &&[k, v] : tbl) {
|
||||
const auto type = v.type();
|
||||
if ((type == node_type::table &&
|
||||
!reinterpret_cast<const table *>(&v)->is_inline()) ||
|
||||
(type == node_type::array && is_non_inline_array_of_tables(v)))
|
||||
continue;
|
||||
|
||||
pending_table_separator_ = true;
|
||||
base::print_newline();
|
||||
base::print_indent();
|
||||
print_key_segment(k);
|
||||
impl::print_to_stream(" = "sv, base::stream());
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type) {
|
||||
case node_type::table:
|
||||
print_inline(*reinterpret_cast<const table *>(&v));
|
||||
break;
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array *>(&v));
|
||||
break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
|
||||
// non-inline tables
|
||||
for (auto &&[k, v] : tbl) {
|
||||
const auto type = v.type();
|
||||
if (type != node_type::table ||
|
||||
reinterpret_cast<const table *>(&v)->is_inline())
|
||||
continue;
|
||||
auto &child_tbl = *reinterpret_cast<const table *>(&v);
|
||||
|
||||
// we can skip indenting and emitting the headers for tables that only contain
|
||||
// other tables (so we don't over-nest)
|
||||
size_t child_value_count{}; // includes inline tables and non-table arrays
|
||||
size_t child_table_count{};
|
||||
size_t child_table_array_count{};
|
||||
for (auto &&[child_k, child_v] : child_tbl) {
|
||||
(void)child_k;
|
||||
const auto child_type = child_v.type();
|
||||
TOML_ASSUME(child_type != node_type::none);
|
||||
switch (child_type) {
|
||||
case node_type::table:
|
||||
if (reinterpret_cast<const table *>(&child_v)->is_inline())
|
||||
child_value_count++;
|
||||
else
|
||||
child_table_count++;
|
||||
break;
|
||||
|
||||
case node_type::array:
|
||||
if (is_non_inline_array_of_tables(child_v))
|
||||
child_table_array_count++;
|
||||
else
|
||||
child_value_count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
child_value_count++;
|
||||
}
|
||||
}
|
||||
bool skip_self = false;
|
||||
if (child_value_count == 0_sz &&
|
||||
(child_table_count > 0_sz || child_table_array_count > 0_sz))
|
||||
skip_self = true;
|
||||
|
||||
key_path.push_back(impl::default_formatter_make_key_segment(k));
|
||||
|
||||
if (!skip_self) {
|
||||
print_pending_table_separator();
|
||||
base::increase_indent();
|
||||
base::print_indent();
|
||||
impl::print_to_stream("["sv, base::stream());
|
||||
print_key_path();
|
||||
impl::print_to_stream("]"sv, base::stream());
|
||||
pending_table_separator_ = true;
|
||||
}
|
||||
|
||||
print(child_tbl);
|
||||
|
||||
key_path.pop_back();
|
||||
if (!skip_self)
|
||||
base::decrease_indent();
|
||||
}
|
||||
|
||||
// table arrays
|
||||
for (auto &&[k, v] : tbl) {
|
||||
if (!is_non_inline_array_of_tables(v))
|
||||
continue;
|
||||
auto &arr = *reinterpret_cast<const array *>(&v);
|
||||
|
||||
base::increase_indent();
|
||||
key_path.push_back(impl::default_formatter_make_key_segment(k));
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
print_pending_table_separator();
|
||||
base::print_indent();
|
||||
impl::print_to_stream("[["sv, base::stream());
|
||||
print_key_path();
|
||||
impl::print_to_stream("]]"sv, base::stream());
|
||||
pending_table_separator_ = true;
|
||||
print(*reinterpret_cast<const table *>(&arr[i]));
|
||||
}
|
||||
|
||||
key_path.pop_back();
|
||||
base::decrease_indent();
|
||||
}
|
||||
}
|
||||
|
||||
void print() {
|
||||
if (base::dump_failed_parse_result())
|
||||
return;
|
||||
|
||||
switch (auto source_type = base::source().type()) {
|
||||
case node_type::table: {
|
||||
auto &tbl = *reinterpret_cast<const table *>(&base::source());
|
||||
if (tbl.is_inline())
|
||||
print_inline(tbl);
|
||||
else {
|
||||
base::decrease_indent(); // so root kvps and tables have the same indent
|
||||
print(tbl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array *>(&base::source()));
|
||||
break;
|
||||
|
||||
default:
|
||||
base::print_value(base::source(), source_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \brief The default flags for a default_formatter.
|
||||
static constexpr format_flags default_flags =
|
||||
format_flags::allow_literal_strings | format_flags::allow_multi_line_strings |
|
||||
format_flags::allow_value_format_flags;
|
||||
|
||||
/// \brief Constructs a default formatter and binds it to a TOML object.
|
||||
///
|
||||
/// \param source The source TOML object.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit default_formatter(const toml::node &source,
|
||||
format_flags flags = default_flags) noexcept
|
||||
: base{source, flags} {}
|
||||
|
||||
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
|
||||
|
||||
/// \brief Constructs a default TOML formatter and binds it to a
|
||||
/// toml::parse_result.
|
||||
///
|
||||
/// \availability This constructor is only available when exceptions are disabled.
|
||||
///
|
||||
/// \attention Formatting a failed parse result will simply dump the error message
|
||||
/// out as-is.
|
||||
/// This will not be valid TOML, but at least gives you something to log or
|
||||
/// show up in diagnostics:
|
||||
/// \cpp
|
||||
/// std::cout << toml::default_formatter{ toml::parse("a = 'b'"sv) } // ok
|
||||
/// << "\n\n"
|
||||
/// << toml::default_formatter{ toml::parse("a = "sv) } // malformed
|
||||
/// << "\n";
|
||||
/// \ecpp
|
||||
/// \out
|
||||
/// a = 'b'
|
||||
///
|
||||
/// Error while parsing key-value pair: encountered end-of-file
|
||||
/// (error occurred at line 1, column 5)
|
||||
/// \eout
|
||||
/// Use the library with exceptions if you want to avoid this scenario.
|
||||
///
|
||||
/// \param result The parse result.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit default_formatter(const toml::parse_result &result,
|
||||
format_flags flags = default_flags) noexcept
|
||||
: base{result, flags} {}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T> &operator<<(std::basic_ostream<T> &,
|
||||
default_formatter<U> &);
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T> &operator<<(std::basic_ostream<T> &,
|
||||
default_formatter<U> &&);
|
||||
};
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template class TOML_API default_formatter<char>;
|
||||
#endif
|
||||
|
||||
default_formatter(const table &)->default_formatter<char>;
|
||||
default_formatter(const array &)->default_formatter<char>;
|
||||
template <typename T> default_formatter(const value<T> &) -> default_formatter<char>;
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
|
||||
template <typename T, typename U>
|
||||
inline std::basic_ostream<T> &operator<<(std::basic_ostream<T> &lhs,
|
||||
default_formatter<U> &rhs) {
|
||||
rhs.attach(lhs);
|
||||
rhs.key_path.clear();
|
||||
rhs.print();
|
||||
rhs.detach();
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue
|
||||
/// overload).
|
||||
template <typename T, typename U>
|
||||
inline std::basic_ostream<T> &operator<<(std::basic_ostream<T> &lhs,
|
||||
default_formatter<U> &&rhs) {
|
||||
return lhs << rhs; // as lvalue
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
#if !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
default_formatter<char> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
default_formatter<char> &&);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &, const table &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &, const array &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<std::string> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<int64_t> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<double> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<bool> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<toml::date> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<toml::time> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const value<toml::date_time> &);
|
||||
#endif
|
||||
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const table &rhs) {
|
||||
return lhs << default_formatter<Char>{rhs};
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const array &rhs) {
|
||||
return lhs << default_formatter<Char>{rhs};
|
||||
}
|
||||
|
||||
template <typename Char, typename T>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const value<T> &rhs) {
|
||||
return lhs << default_formatter<Char>{rhs};
|
||||
}
|
||||
|
||||
#endif // !DOXYGEN
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
|
|
@ -0,0 +1,288 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_default_formatter.h"
|
||||
TOML_DISABLE_WARNINGS;
|
||||
#include <cmath>
|
||||
TOML_ENABLE_WARNINGS;
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
inline constexpr size_t default_formatter_line_wrap = 120_sz;
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::string default_formatter_make_key_segment(const std::string& str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return "''"s;
|
||||
else
|
||||
{
|
||||
bool requires_quotes = false;
|
||||
{
|
||||
utf8_decoder decoder;
|
||||
for (size_t i = 0; i < str.length() && !requires_quotes; i++)
|
||||
{
|
||||
decoder(static_cast<uint8_t>(str[i]));
|
||||
if (decoder.error())
|
||||
requires_quotes = true;
|
||||
else if (decoder.has_code_point())
|
||||
requires_quotes = !is_bare_key_character(decoder.codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (requires_quotes)
|
||||
{
|
||||
std::string s;
|
||||
s.reserve(str.length() + 2_sz);
|
||||
s += '"';
|
||||
for (auto c : str)
|
||||
{
|
||||
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
|
||||
s.append(low_character_escape_table[c]);
|
||||
else if TOML_UNLIKELY(c == '\x7F')
|
||||
s.append("\\u007F"sv);
|
||||
else if TOML_UNLIKELY(c == '"')
|
||||
s.append("\\\""sv);
|
||||
else
|
||||
s += c;
|
||||
}
|
||||
s += '"';
|
||||
return s;
|
||||
}
|
||||
else
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
size_t default_formatter_inline_columns(const node& node) noexcept
|
||||
{
|
||||
switch (node.type())
|
||||
{
|
||||
case node_type::table:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const table*>(&node);
|
||||
if (n.empty())
|
||||
return 2_sz; // "{}"
|
||||
size_t weight = 3_sz; // "{ }"
|
||||
for (auto&& [k, v] : n)
|
||||
{
|
||||
weight += k.length() + default_formatter_inline_columns(v) + 2_sz; // + ", "
|
||||
if (weight >= default_formatter_line_wrap)
|
||||
break;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
case node_type::array:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const array*>(&node);
|
||||
if (n.empty())
|
||||
return 2_sz; // "[]"
|
||||
size_t weight = 3_sz; // "[ ]"
|
||||
for (auto& elem : n)
|
||||
{
|
||||
weight += default_formatter_inline_columns(elem) + 2_sz; // + ", "
|
||||
if (weight >= default_formatter_line_wrap)
|
||||
break;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
case node_type::string:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<std::string>*>(&node);
|
||||
return n.get().length() + 2_sz; // + ""
|
||||
}
|
||||
|
||||
case node_type::integer:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<int64_t>*>(&node);
|
||||
auto v = n.get();
|
||||
if (!v)
|
||||
return 1_sz;
|
||||
size_t weight = {};
|
||||
if (v < 0)
|
||||
{
|
||||
weight += 1;
|
||||
v *= -1;
|
||||
}
|
||||
return weight + static_cast<size_t>(log10(static_cast<double>(v))) + 1_sz;
|
||||
}
|
||||
|
||||
case node_type::floating_point:
|
||||
{
|
||||
auto& n = *reinterpret_cast<const value<double>*>(&node);
|
||||
auto v = n.get();
|
||||
if (v == 0.0)
|
||||
return 3_sz; // "0.0"
|
||||
size_t weight = 2_sz; // ".0"
|
||||
if (v < 0.0)
|
||||
{
|
||||
weight += 1;
|
||||
v *= -1.0;
|
||||
}
|
||||
return weight + static_cast<size_t>(log10(v)) + 1_sz;
|
||||
break;
|
||||
}
|
||||
|
||||
case node_type::boolean: return 5_sz;
|
||||
case node_type::date: [[fallthrough]];
|
||||
case node_type::time: return 10_sz;
|
||||
case node_type::date_time: return 30_sz;
|
||||
case node_type::none: TOML_UNREACHABLE;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool default_formatter_forces_multiline(const node& node, size_t starting_column_bias) noexcept
|
||||
{
|
||||
return (default_formatter_inline_columns(node) + starting_column_bias) >= default_formatter_line_wrap;
|
||||
}
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
template <typename Char>
|
||||
inline void default_formatter<Char>::print_inline(const toml::table& tbl)
|
||||
{
|
||||
if (tbl.empty())
|
||||
impl::print_to_stream("{}"sv, base::stream());
|
||||
else
|
||||
{
|
||||
impl::print_to_stream("{ "sv, base::stream());
|
||||
|
||||
bool first = false;
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
if (first)
|
||||
impl::print_to_stream(", "sv, base::stream());
|
||||
first = true;
|
||||
|
||||
print_key_segment(k);
|
||||
impl::print_to_stream(" = "sv, base::stream());
|
||||
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
|
||||
impl::print_to_stream(" }"sv, base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
// implementations of windows wide string nonsense
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
#ifndef _WINDOWS_
|
||||
#if TOML_INCLUDE_WINDOWS_H
|
||||
#include <Windows.h>
|
||||
#else
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport)
|
||||
int __stdcall WideCharToMultiByte(
|
||||
unsigned int CodePage,
|
||||
unsigned long dwFlags,
|
||||
const wchar_t* lpWideCharStr,
|
||||
int cchWideChar,
|
||||
char* lpMultiByteStr,
|
||||
int cbMultiByte,
|
||||
const char* lpDefaultChar,
|
||||
int* lpUsedDefaultChar
|
||||
);
|
||||
|
||||
__declspec(dllimport)
|
||||
int __stdcall MultiByteToWideChar(
|
||||
unsigned int CodePage,
|
||||
unsigned long dwFlags,
|
||||
const char* lpMultiByteStr,
|
||||
int cbMultiByte,
|
||||
wchar_t* lpWideCharStr,
|
||||
int cchWideChar
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif // _WINDOWS_
|
||||
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::string narrow(std::wstring_view str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return {};
|
||||
|
||||
std::string s;
|
||||
const auto len = ::WideCharToMultiByte(
|
||||
65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr
|
||||
);
|
||||
if (len)
|
||||
{
|
||||
s.resize(static_cast<size_t>(len));
|
||||
::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len, nullptr, nullptr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::wstring widen(std::string_view str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return {};
|
||||
|
||||
std::wstring s;
|
||||
const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
|
||||
if (len)
|
||||
{
|
||||
s.resize(static_cast<size_t>(len));
|
||||
::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
std::wstring widen(std::u8string_view str) noexcept
|
||||
{
|
||||
if (str.empty())
|
||||
return {};
|
||||
|
||||
return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
|
||||
}
|
||||
|
||||
#endif // TOML_HAS_CHAR8
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_ARITHMETIC_WARNINGS
|
|
@ -0,0 +1,232 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
/// \cond
|
||||
|
||||
#pragma once
|
||||
#include "toml_print_to_stream.h"
|
||||
#if TOML_PARSER && !TOML_EXCEPTIONS
|
||||
#include "toml_parse_result.h"
|
||||
#endif
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
template <typename Char = char> class TOML_API formatter {
|
||||
private:
|
||||
const toml::node *source_;
|
||||
std::basic_ostream<Char> *stream_ = {};
|
||||
format_flags flags_;
|
||||
int indent_;
|
||||
bool naked_newline_;
|
||||
#if TOML_PARSER && !TOML_EXCEPTIONS
|
||||
const parse_result *result_ = {};
|
||||
#endif
|
||||
|
||||
protected:
|
||||
[[nodiscard]] const toml::node &source() const noexcept { return *source_; }
|
||||
[[nodiscard]] std::basic_ostream<Char> &stream() const noexcept { return *stream_; }
|
||||
|
||||
static constexpr size_t indent_columns = 4;
|
||||
static constexpr std::string_view indent_string = " "sv;
|
||||
[[nodiscard]] int indent() const noexcept { return indent_; }
|
||||
void indent(int level) noexcept { indent_ = level; }
|
||||
void increase_indent() noexcept { indent_++; }
|
||||
void decrease_indent() noexcept { indent_--; }
|
||||
|
||||
[[nodiscard]] bool quote_dates_and_times() const noexcept {
|
||||
return (flags_ & format_flags::quote_dates_and_times) != format_flags::none;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool literal_strings_allowed() const noexcept {
|
||||
return (flags_ & format_flags::allow_literal_strings) != format_flags::none;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool multi_line_strings_allowed() const noexcept {
|
||||
return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool value_format_flags_allowed() const noexcept {
|
||||
return (flags_ & format_flags::allow_value_format_flags) != format_flags::none;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool naked_newline() const noexcept { return naked_newline_; }
|
||||
|
||||
void clear_naked_newline() noexcept { naked_newline_ = false; }
|
||||
|
||||
void attach(std::basic_ostream<Char> &stream) noexcept {
|
||||
indent_ = {};
|
||||
naked_newline_ = true;
|
||||
stream_ = &stream;
|
||||
}
|
||||
|
||||
void detach() noexcept { stream_ = nullptr; }
|
||||
|
||||
void print_newline(bool force = false) {
|
||||
if (!naked_newline_ || force) {
|
||||
print_to_stream('\n', *stream_);
|
||||
naked_newline_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void print_indent() {
|
||||
for (int i = 0; i < indent_; i++) {
|
||||
print_to_stream(indent_string, *stream_);
|
||||
naked_newline_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void print_quoted_string(std::string_view str, bool allow_multi_line = true) {
|
||||
auto literals = literal_strings_allowed();
|
||||
if (str.empty()) {
|
||||
print_to_stream(literals ? "''"sv : "\"\""sv, *stream_);
|
||||
clear_naked_newline();
|
||||
return;
|
||||
}
|
||||
|
||||
auto multi_line = allow_multi_line && multi_line_strings_allowed();
|
||||
if (multi_line || literals) {
|
||||
utf8_decoder decoder;
|
||||
bool has_line_breaks = false;
|
||||
bool has_control_chars = false;
|
||||
bool has_single_quotes = false;
|
||||
for (size_t i = 0; i < str.length() &&
|
||||
!(has_line_breaks && has_control_chars && has_single_quotes);
|
||||
i++) {
|
||||
decoder(static_cast<uint8_t>(str[i]));
|
||||
if (decoder.error()) {
|
||||
has_line_breaks = false;
|
||||
has_control_chars = true; // force ""
|
||||
has_single_quotes = true;
|
||||
break;
|
||||
} else if (decoder.has_code_point()) {
|
||||
if (is_line_break(decoder.codepoint))
|
||||
has_line_breaks = true;
|
||||
else if (is_nontab_control_character(decoder.codepoint))
|
||||
has_control_chars = true;
|
||||
else if (decoder.codepoint == U'\'')
|
||||
has_single_quotes = true;
|
||||
}
|
||||
}
|
||||
multi_line = multi_line && has_line_breaks;
|
||||
literals =
|
||||
literals && !has_control_chars && !(!multi_line && has_single_quotes);
|
||||
}
|
||||
|
||||
if (literals) {
|
||||
const auto quot = multi_line ? "'''"sv : "'"sv;
|
||||
print_to_stream(quot, *stream_);
|
||||
print_to_stream(str, *stream_);
|
||||
print_to_stream(quot, *stream_);
|
||||
} else {
|
||||
const auto quot = multi_line ? R"(""")"sv : R"(")"sv;
|
||||
print_to_stream(quot, *stream_);
|
||||
print_to_stream_with_escapes(str, *stream_);
|
||||
print_to_stream(quot, *stream_);
|
||||
}
|
||||
clear_naked_newline();
|
||||
}
|
||||
|
||||
template <typename T> void print(const value<T> &val) {
|
||||
if constexpr (std::is_same_v<T, std::string>) {
|
||||
print_quoted_string(val.get());
|
||||
} else {
|
||||
if constexpr (is_one_of<T, date, time, date_time>) {
|
||||
if (quote_dates_and_times()) {
|
||||
const auto quot = literal_strings_allowed() ? '\'' : '"';
|
||||
print_to_stream(quot, *stream_);
|
||||
print_to_stream(*val, *stream_);
|
||||
print_to_stream(quot, *stream_);
|
||||
} else
|
||||
print_to_stream(*val, *stream_);
|
||||
} else if constexpr (is_one_of<T, int64_t /*, double*/>) {
|
||||
if (value_format_flags_allowed() && *val >= 0) {
|
||||
const auto fmt = val.flags() & value_flags::format_as_hexadecimal;
|
||||
if (fmt != value_flags::none) {
|
||||
switch (fmt) {
|
||||
case value_flags::format_as_binary:
|
||||
print_to_stream("0b"sv, *stream_);
|
||||
break;
|
||||
case value_flags::format_as_octal:
|
||||
print_to_stream("0o"sv, *stream_);
|
||||
break;
|
||||
case value_flags::format_as_hexadecimal:
|
||||
print_to_stream("0x"sv, *stream_);
|
||||
break;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
print_to_stream(*val, *stream_, fmt);
|
||||
} else
|
||||
print_to_stream(*val, *stream_);
|
||||
} else
|
||||
print_to_stream(*val, *stream_);
|
||||
} else
|
||||
print_to_stream(*val, *stream_);
|
||||
|
||||
naked_newline_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void print_value(const node &val_node, node_type type) {
|
||||
TOML_ASSUME(type > node_type::array);
|
||||
switch (type) {
|
||||
case node_type::string:
|
||||
print(*reinterpret_cast<const value<std::string> *>(&val_node));
|
||||
break;
|
||||
case node_type::integer:
|
||||
print(*reinterpret_cast<const value<int64_t> *>(&val_node));
|
||||
break;
|
||||
case node_type::floating_point:
|
||||
print(*reinterpret_cast<const value<double> *>(&val_node));
|
||||
break;
|
||||
case node_type::boolean:
|
||||
print(*reinterpret_cast<const value<bool> *>(&val_node));
|
||||
break;
|
||||
case node_type::date:
|
||||
print(*reinterpret_cast<const value<date> *>(&val_node));
|
||||
break;
|
||||
case node_type::time:
|
||||
print(*reinterpret_cast<const value<time> *>(&val_node));
|
||||
break;
|
||||
case node_type::date_time:
|
||||
print(*reinterpret_cast<const value<date_time> *>(&val_node));
|
||||
break;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool dump_failed_parse_result() {
|
||||
#if TOML_PARSER && !TOML_EXCEPTIONS
|
||||
if (result_ && !(*result_)) {
|
||||
stream() << result_->error();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
formatter(const toml::node &source, format_flags flags) noexcept
|
||||
: source_{&source}, flags_{flags} {}
|
||||
|
||||
#if TOML_PARSER && !TOML_EXCEPTIONS
|
||||
|
||||
formatter(const parse_result &result, format_flags flags) noexcept
|
||||
: source_{result ? &result.table() : nullptr}, flags_{flags}, result_{&result} {
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template class TOML_API formatter<char>;
|
||||
#endif
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
|
||||
|
||||
/// \endcond
|
|
@ -0,0 +1,147 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
#if TOML_HEADER_ONLY && !TOML_INTELLISENSE
|
||||
#error This header cannot not be included when TOML_HEADER_ONLY is enabled.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
TOML_DISABLE_WARNINGS;
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
TOML_ENABLE_WARNINGS;
|
||||
|
||||
#include "toml_node_view.h"
|
||||
#include "toml_default_formatter.h"
|
||||
#include "toml_json_formatter.h"
|
||||
#if TOML_PARSER
|
||||
#include "toml_parser.h"
|
||||
#endif
|
||||
|
||||
// internal implementation namespace
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
// formatters
|
||||
template class formatter<char>;
|
||||
|
||||
// print to stream machinery
|
||||
template void print_floating_point_to_stream(double, std::ostream&, bool);
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
// public namespace
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
// value<>
|
||||
template class value<std::string>;
|
||||
template class value<int64_t>;
|
||||
template class value<double>;
|
||||
template class value<bool>;
|
||||
template class value<date>;
|
||||
template class value<time>;
|
||||
template class value<date_time>;
|
||||
|
||||
// node_view
|
||||
template class node_view<node>;
|
||||
template class node_view<const node>;
|
||||
|
||||
// formatters
|
||||
template class default_formatter<char>;
|
||||
template class json_formatter<char>;
|
||||
|
||||
// various ostream operators
|
||||
template std::ostream& operator << (std::ostream&, const source_position&);
|
||||
template std::ostream& operator << (std::ostream&, const source_region&);
|
||||
template std::ostream& operator << (std::ostream&, const date&);
|
||||
template std::ostream& operator << (std::ostream&, const time&);
|
||||
template std::ostream& operator << (std::ostream&, const time_offset&);
|
||||
template std::ostream& operator << (std::ostream&, const date_time&);
|
||||
template std::ostream& operator << (std::ostream&, const value<std::string>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<int64_t>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<double>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<bool>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<toml::date>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<toml::time>&);
|
||||
template std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
|
||||
template std::ostream& operator << (std::ostream&, default_formatter<char>&);
|
||||
template std::ostream& operator << (std::ostream&, default_formatter<char>&&);
|
||||
template std::ostream& operator << (std::ostream&, json_formatter<char>&);
|
||||
template std::ostream& operator << (std::ostream&, json_formatter<char>&&);
|
||||
template std::ostream& operator << (std::ostream&, const table&);
|
||||
template std::ostream& operator << (std::ostream&, const array&);
|
||||
template std::ostream& operator << (std::ostream&, const node_view<node>&);
|
||||
template std::ostream& operator << (std::ostream&, const node_view<const node>&);
|
||||
template std::ostream& operator << (std::ostream&, node_type);
|
||||
|
||||
// node::value, node_view:::value etc
|
||||
#define TOML_INSTANTIATE(name, T) \
|
||||
template optional<T> node::name<T>() const noexcept; \
|
||||
template optional<T> node_view<node>::name<T>() const noexcept; \
|
||||
template optional<T> node_view<const node>::name<T>() const noexcept
|
||||
TOML_INSTANTIATE(value_exact, std::string_view);
|
||||
TOML_INSTANTIATE(value_exact, std::string);
|
||||
TOML_INSTANTIATE(value_exact, const char*);
|
||||
TOML_INSTANTIATE(value_exact, int64_t);
|
||||
TOML_INSTANTIATE(value_exact, double);
|
||||
TOML_INSTANTIATE(value_exact, date);
|
||||
TOML_INSTANTIATE(value_exact, time);
|
||||
TOML_INSTANTIATE(value_exact, date_time);
|
||||
TOML_INSTANTIATE(value_exact, bool);
|
||||
TOML_INSTANTIATE(value, std::string_view);
|
||||
TOML_INSTANTIATE(value, std::string);
|
||||
TOML_INSTANTIATE(value, const char*);
|
||||
TOML_INSTANTIATE(value, signed char);
|
||||
TOML_INSTANTIATE(value, signed short);
|
||||
TOML_INSTANTIATE(value, signed int);
|
||||
TOML_INSTANTIATE(value, signed long);
|
||||
TOML_INSTANTIATE(value, signed long long);
|
||||
TOML_INSTANTIATE(value, unsigned char);
|
||||
TOML_INSTANTIATE(value, unsigned short);
|
||||
TOML_INSTANTIATE(value, unsigned int);
|
||||
TOML_INSTANTIATE(value, unsigned long);
|
||||
TOML_INSTANTIATE(value, unsigned long long);
|
||||
TOML_INSTANTIATE(value, double);
|
||||
TOML_INSTANTIATE(value, float);
|
||||
TOML_INSTANTIATE(value, date);
|
||||
TOML_INSTANTIATE(value, time);
|
||||
TOML_INSTANTIATE(value, date_time);
|
||||
TOML_INSTANTIATE(value, bool);
|
||||
#if TOML_HAS_CHAR8
|
||||
TOML_INSTANTIATE(value_exact, std::u8string_view);
|
||||
TOML_INSTANTIATE(value_exact, std::u8string);
|
||||
TOML_INSTANTIATE(value_exact, const char8_t*);
|
||||
TOML_INSTANTIATE(value, std::u8string_view);
|
||||
TOML_INSTANTIATE(value, std::u8string);
|
||||
TOML_INSTANTIATE(value, const char8_t*);
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_INSTANTIATE(value_exact, std::wstring);
|
||||
TOML_INSTANTIATE(value, std::wstring);
|
||||
#endif
|
||||
#undef TOML_INSTANTIATE
|
||||
|
||||
// parser instantiations
|
||||
#if TOML_PARSER
|
||||
|
||||
// parse error ostream
|
||||
template std::ostream& operator << (std::ostream&, const parse_error&);
|
||||
|
||||
// parse() and parse_file()
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
template parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
|
||||
template parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
|
||||
#endif // TOML_PARSER
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
|
@ -0,0 +1,203 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_array.h"
|
||||
#include "toml_formatter.h"
|
||||
#include "toml_table.h"
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto some_toml = toml::parse(R"(
|
||||
/// [fruit]
|
||||
/// apple.color = "red"
|
||||
/// apple.taste.sweet = true
|
||||
///
|
||||
/// [fruit.apple.texture]
|
||||
/// smooth = true
|
||||
/// )"sv);
|
||||
/// std::cout << toml::json_formatter{ some_toml } << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// {
|
||||
/// "fruit" : {
|
||||
/// "apple" : {
|
||||
/// "color" : "red",
|
||||
/// "taste" : {
|
||||
/// "sweet" : true
|
||||
/// },
|
||||
/// "texture" : {
|
||||
/// "smooth" : true
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The underlying character type of the output stream. Must be 1
|
||||
/// byte in size.
|
||||
template <typename Char = char>
|
||||
class TOML_API json_formatter final : impl::formatter<Char> {
|
||||
private:
|
||||
/// \cond
|
||||
|
||||
using base = impl::formatter<Char>;
|
||||
|
||||
void print(const toml::table &tbl);
|
||||
|
||||
void print(const array &arr) {
|
||||
if (arr.empty())
|
||||
impl::print_to_stream("[]"sv, base::stream());
|
||||
else {
|
||||
impl::print_to_stream('[', base::stream());
|
||||
base::increase_indent();
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
if (i > 0_sz)
|
||||
impl::print_to_stream(',', base::stream());
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
|
||||
auto &v = arr[i];
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type) {
|
||||
case node_type::table:
|
||||
print(*reinterpret_cast<const table *>(&v));
|
||||
break;
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array *>(&v));
|
||||
break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
}
|
||||
base::decrease_indent();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream(']', base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
|
||||
void print() {
|
||||
if (base::dump_failed_parse_result())
|
||||
return;
|
||||
|
||||
switch (auto source_type = base::source().type()) {
|
||||
case node_type::table:
|
||||
print(*reinterpret_cast<const table *>(&base::source()));
|
||||
break;
|
||||
|
||||
case node_type::array:
|
||||
print(*reinterpret_cast<const array *>(&base::source()));
|
||||
break;
|
||||
|
||||
default:
|
||||
base::print_value(base::source(), source_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \brief The default flags for a json_formatter.
|
||||
static constexpr format_flags default_flags = format_flags::quote_dates_and_times;
|
||||
|
||||
/// \brief Constructs a JSON formatter and binds it to a TOML object.
|
||||
///
|
||||
/// \param source The source TOML object.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit json_formatter(const toml::node &source,
|
||||
format_flags flags = default_flags) noexcept
|
||||
: base{source, flags} {}
|
||||
|
||||
#if defined(DOXYGEN) || (TOML_PARSER && !TOML_EXCEPTIONS)
|
||||
|
||||
/// \brief Constructs a JSON formatter and binds it to a toml::parse_result.
|
||||
///
|
||||
/// \availability This constructor is only available when exceptions are disabled.
|
||||
///
|
||||
/// \attention Formatting a failed parse result will simply dump the error message
|
||||
/// out as-is.
|
||||
/// This will not be valid JSON, but at least gives you something to log or
|
||||
/// show up in diagnostics:
|
||||
/// \cpp
|
||||
/// std::cout << toml::json_formatter{ toml::parse("a = 'b'"sv) } // ok
|
||||
/// << "\n\n"
|
||||
/// << toml::json_formatter{ toml::parse("a = "sv) } // malformed
|
||||
/// << "\n";
|
||||
/// \ecpp
|
||||
/// \out
|
||||
/// {
|
||||
/// "a" : "b"
|
||||
/// }
|
||||
///
|
||||
/// Error while parsing key-value pair: encountered end-of-file
|
||||
/// (error occurred at line 1, column 5)
|
||||
/// \eout
|
||||
/// Use the library with exceptions if you want to avoid this scenario.
|
||||
///
|
||||
/// \param result The parse result.
|
||||
/// \param flags Format option flags.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit json_formatter(const toml::parse_result &result,
|
||||
format_flags flags = default_flags) noexcept
|
||||
: base{result, flags} {}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T> &operator<<(std::basic_ostream<T> &,
|
||||
json_formatter<U> &);
|
||||
template <typename T, typename U>
|
||||
friend std::basic_ostream<T> &operator<<(std::basic_ostream<T> &,
|
||||
json_formatter<U> &&);
|
||||
};
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template class TOML_API json_formatter<char>;
|
||||
#endif
|
||||
|
||||
json_formatter(const table &)->json_formatter<char>;
|
||||
json_formatter(const array &)->json_formatter<char>;
|
||||
template <typename T> json_formatter(const value<T> &) -> json_formatter<char>;
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as JSON.
|
||||
template <typename T, typename U>
|
||||
inline std::basic_ostream<T> &operator<<(std::basic_ostream<T> &lhs,
|
||||
json_formatter<U> &rhs) {
|
||||
rhs.attach(lhs);
|
||||
rhs.print();
|
||||
rhs.detach();
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue
|
||||
/// overload).
|
||||
template <typename T, typename U>
|
||||
inline std::basic_ostream<T> &operator<<(std::basic_ostream<T> &lhs,
|
||||
json_formatter<U> &&rhs) {
|
||||
return lhs << rhs; // as lvalue
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
json_formatter<char> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
json_formatter<char> &&);
|
||||
#endif
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
|
|
@ -0,0 +1,63 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_json_formatter.h"
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
template <typename Char>
|
||||
inline void json_formatter<Char>::print(const toml::table& tbl)
|
||||
{
|
||||
if (tbl.empty())
|
||||
impl::print_to_stream("{}"sv, base::stream());
|
||||
else
|
||||
{
|
||||
impl::print_to_stream('{', base::stream());
|
||||
base::increase_indent();
|
||||
bool first = false;
|
||||
for (auto&& [k, v] : tbl)
|
||||
{
|
||||
if (first)
|
||||
impl::print_to_stream(", "sv, base::stream());
|
||||
first = true;
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
|
||||
base::print_quoted_string(k, false);
|
||||
impl::print_to_stream(" : "sv, base::stream());
|
||||
|
||||
const auto type = v.type();
|
||||
TOML_ASSUME(type != node_type::none);
|
||||
switch (type)
|
||||
{
|
||||
case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
|
||||
case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
|
||||
default:
|
||||
base::print_value(v, type);
|
||||
}
|
||||
|
||||
}
|
||||
base::decrease_indent();
|
||||
base::print_newline(true);
|
||||
base::print_indent();
|
||||
impl::print_to_stream('}', base::stream());
|
||||
}
|
||||
base::clear_naked_newline();
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
|
|
@ -0,0 +1,873 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_common.h"
|
||||
|
||||
#if defined(DOXYGEN) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES
|
||||
|
||||
#define TOML_SA_NEWLINE " "
|
||||
#define TOML_SA_LIST_SEP ", "
|
||||
#define TOML_SA_LIST_BEG " ("
|
||||
#define TOML_SA_LIST_END ")"
|
||||
#define TOML_SA_LIST_NEW " "
|
||||
#define TOML_SA_LIST_NXT ", "
|
||||
|
||||
#else
|
||||
|
||||
#define TOML_SA_NEWLINE "\n| "
|
||||
#define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - "
|
||||
#define TOML_SA_LIST_BEG TOML_SA_LIST_SEP
|
||||
#define TOML_SA_LIST_END
|
||||
#define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE
|
||||
#define TOML_SA_LIST_NXT TOML_SA_LIST_NEW
|
||||
|
||||
#endif
|
||||
|
||||
#define TOML_SA_NATIVE_VALUE_TYPE_LIST \
|
||||
TOML_SA_LIST_BEG "std::string" TOML_SA_LIST_SEP "int64_t" TOML_SA_LIST_SEP \
|
||||
"double" TOML_SA_LIST_SEP "bool" TOML_SA_LIST_SEP \
|
||||
"toml::date" TOML_SA_LIST_SEP "toml::time" TOML_SA_LIST_SEP \
|
||||
"toml::date_time" TOML_SA_LIST_END
|
||||
|
||||
#define TOML_SA_NODE_TYPE_LIST \
|
||||
TOML_SA_LIST_BEG \
|
||||
"toml::table" TOML_SA_LIST_SEP "toml::array" TOML_SA_LIST_SEP \
|
||||
"toml::value<std::string>" TOML_SA_LIST_SEP "toml::value<int64_t>" TOML_SA_LIST_SEP \
|
||||
"toml::value<double>" TOML_SA_LIST_SEP "toml::value<bool>" TOML_SA_LIST_SEP \
|
||||
"toml::value<toml::date>" TOML_SA_LIST_SEP \
|
||||
"toml::value<toml::time>" TOML_SA_LIST_SEP \
|
||||
"toml::value<toml::date_time>" TOML_SA_LIST_END
|
||||
|
||||
#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \
|
||||
TOML_SA_LIST_NEW "A native TOML value type" TOML_SA_NATIVE_VALUE_TYPE_LIST \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A TOML node type" TOML_SA_NODE_TYPE_LIST
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A TOML node.
|
||||
///
|
||||
/// \detail A parsed TOML document forms a tree made up of tables, arrays and values.
|
||||
/// This type is the base of each of those, providing a lot of the
|
||||
/// polymorphic plumbing.
|
||||
class TOML_ABSTRACT_BASE TOML_API node {
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
source_region source_{};
|
||||
|
||||
/// \cond
|
||||
|
||||
template <typename T> [[nodiscard]] decltype(auto) get_value_exact() const noexcept;
|
||||
|
||||
template <typename T, typename N>
|
||||
[[nodiscard]] TOML_ATTR(pure) static decltype(auto) do_ref(N &&n) noexcept {
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"The template type argument of node::ref() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
TOML_ASSERT(n.template is<T>() &&
|
||||
"template type argument T provided to toml::node::ref() didn't match "
|
||||
"the node's actual type");
|
||||
if constexpr (impl::is_native<type>)
|
||||
return static_cast<N &&>(n).template ref_cast<type>().get();
|
||||
else
|
||||
return static_cast<N &&>(n).template ref_cast<type>();
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
protected:
|
||||
node() noexcept = default;
|
||||
node(const node &) noexcept;
|
||||
node(node &&) noexcept;
|
||||
node &operator=(const node &) noexcept;
|
||||
node &operator=(node &&) noexcept;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(pure) impl::wrap_node<T> &ref_cast() &noexcept {
|
||||
return *reinterpret_cast<impl::wrap_node<T> *>(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(pure) impl::wrap_node<T> &&ref_cast() &&noexcept {
|
||||
return std::move(*reinterpret_cast<impl::wrap_node<T> *>(this));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(pure) const impl::wrap_node<T> &ref_cast() const &noexcept {
|
||||
return *reinterpret_cast<const impl::wrap_node<T> *>(this);
|
||||
}
|
||||
|
||||
template <typename N, typename T>
|
||||
using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
|
||||
|
||||
public:
|
||||
virtual ~node() noexcept = default;
|
||||
|
||||
/// \name Type checks
|
||||
/// @{
|
||||
|
||||
#if defined(DOXYGEN) || !TOML_ICC || TOML_ICC_CL
|
||||
|
||||
/// \brief Returns the node's type identifier.
|
||||
[[nodiscard]] virtual node_type type() const noexcept = 0;
|
||||
|
||||
#else
|
||||
|
||||
[[nodiscard]] virtual node_type type() const noexcept {
|
||||
// Q: "what the fuck?"
|
||||
// A: https://github.com/marzer/tomlplusplus/issues/83
|
||||
// tl,dr: go home ICC, you're drunk.
|
||||
|
||||
return type();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// \brief Returns true if this node is a table.
|
||||
[[nodiscard]] virtual bool is_table() const noexcept = 0;
|
||||
/// \brief Returns true if this node is an array.
|
||||
[[nodiscard]] virtual bool is_array() const noexcept = 0;
|
||||
/// \brief Returns true if this node is a value.
|
||||
[[nodiscard]] virtual bool is_value() const noexcept = 0;
|
||||
|
||||
/// \brief Returns true if this node is a string value.
|
||||
[[nodiscard]] virtual bool is_string() const noexcept;
|
||||
/// \brief Returns true if this node is an integer value.
|
||||
[[nodiscard]] virtual bool is_integer() const noexcept;
|
||||
/// \brief Returns true if this node is an floating-point value.
|
||||
[[nodiscard]] virtual bool is_floating_point() const noexcept;
|
||||
/// \brief Returns true if this node is an integer or floating-point value.
|
||||
[[nodiscard]] virtual bool is_number() const noexcept;
|
||||
/// \brief Returns true if this node is a boolean value.
|
||||
[[nodiscard]] virtual bool is_boolean() const noexcept;
|
||||
/// \brief Returns true if this node is a local date value.
|
||||
[[nodiscard]] virtual bool is_date() const noexcept;
|
||||
/// \brief Returns true if this node is a local time value.
|
||||
[[nodiscard]] virtual bool is_time() const noexcept;
|
||||
/// \brief Returns true if this node is a date-time value.
|
||||
[[nodiscard]] virtual bool is_date_time() const noexcept;
|
||||
/// \brief Returns true if this node is an array containing only tables.
|
||||
[[nodiscard]] virtual bool is_array_of_tables() const noexcept;
|
||||
|
||||
/// \brief Checks if a node is a specific type.
|
||||
///
|
||||
/// \tparam T A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if this node is an instance of the specified type.
|
||||
template <typename T> [[nodiscard]] TOML_ATTR(pure) bool is() const noexcept {
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"The template type argument of node::is() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>)
|
||||
return is_table();
|
||||
else if constexpr (std::is_same_v<type, array>)
|
||||
return is_array();
|
||||
else if constexpr (std::is_same_v<type, std::string>)
|
||||
return is_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>)
|
||||
return is_integer();
|
||||
else if constexpr (std::is_same_v<type, double>)
|
||||
return is_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>)
|
||||
return is_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>)
|
||||
return is_date();
|
||||
else if constexpr (std::is_same_v<type, time>)
|
||||
return is_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>)
|
||||
return is_date_time();
|
||||
}
|
||||
|
||||
/// \brief Checks if a node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
|
||||
/// toml::array& arr = *cfg["arr"].as_array();
|
||||
///
|
||||
/// toml::node* nonmatch{};
|
||||
/// if (arr.is_homogeneous(toml::node_type::integer, nonmatch))
|
||||
/// std::cout << "array was homogeneous"sv << "\n";
|
||||
/// else
|
||||
/// std::cout << "array was not homogeneous!\n"
|
||||
/// << "first non-match was a "sv << nonmatch->type() << " at " <<
|
||||
/// nonmatch->source() << "\n"; \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// array was not homogeneous!
|
||||
/// first non-match was a floating-point at line 1, column 18
|
||||
/// \eout
|
||||
///
|
||||
/// \param ntype A TOML node type. <br>
|
||||
/// \conditional_return{toml::node_type::none}
|
||||
/// "is every element the same type?"
|
||||
/// \conditional_return{Anything else}
|
||||
/// "is every element one of these?"
|
||||
///
|
||||
/// \param first_nonmatch Reference to a pointer in which the address of the first
|
||||
/// non-matching element will be stored
|
||||
/// if the return value is false.
|
||||
///
|
||||
/// \returns True if the node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` for empty tables and arrays.
|
||||
[[nodiscard]] virtual bool is_homogeneous(node_type ntype,
|
||||
node *&first_nonmatch) noexcept = 0;
|
||||
|
||||
/// \brief Checks if a node contains values/elements of only one type (const
|
||||
/// overload).
|
||||
[[nodiscard]] virtual bool
|
||||
is_homogeneous(node_type ntype, const node *&first_nonmatch) const noexcept = 0;
|
||||
|
||||
/// \brief Checks if the node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) <<
|
||||
/// "\n"; std::cout << "all floats: "sv <<
|
||||
/// arr.is_homogeneous(toml::node_type::floating_point) << "\n"; std::cout << "all
|
||||
/// arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n"; std::cout <<
|
||||
/// "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// homogeneous: true
|
||||
/// all floats: false
|
||||
/// all arrays: false
|
||||
/// all ints: true
|
||||
/// \eout
|
||||
///
|
||||
/// \param ntype A TOML node type. <br>
|
||||
/// \conditional_return{toml::node_type::none}
|
||||
/// "is every element the same type?"
|
||||
/// \conditional_return{Anything else}
|
||||
/// "is every element one of these?"
|
||||
///
|
||||
/// \returns True if the node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` for empty tables and arrays.
|
||||
[[nodiscard]] virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
|
||||
|
||||
/// \brief Checks if the node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto arr = toml::array{ 1, 2, 3 };
|
||||
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << "\n";
|
||||
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
|
||||
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
|
||||
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// homogeneous: true
|
||||
/// all floats: false
|
||||
/// all arrays: false
|
||||
/// all ints: true
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType A TOML node or value type. <br>
|
||||
/// \conditional_return{Left as `void`}
|
||||
/// "is every element the same type?" <br>
|
||||
/// \conditional_return{Explicitly
|
||||
/// specified}
|
||||
/// "is every element a T?"
|
||||
///
|
||||
/// \returns True if the node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` for empty tables and arrays.
|
||||
template <typename ElemType = void>
|
||||
[[nodiscard]] TOML_ATTR(pure) bool is_homogeneous() const noexcept {
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
static_assert(std::is_void_v<type> ||
|
||||
((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
|
||||
"The template type argument of node::is_homogeneous() must be void "
|
||||
"or one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
return is_homogeneous(impl::node_type_of<type>);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Type casts
|
||||
/// @{
|
||||
|
||||
/// \brief Returns a pointer to the node as a toml::table, if it is one.
|
||||
[[nodiscard]] virtual table *as_table() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::array, if it is one.
|
||||
[[nodiscard]] virtual array *as_array() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<string>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<std::string> *as_string() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<int64_t> *as_integer() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<double>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<double> *as_floating_point() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<bool>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<bool> *as_boolean() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<date>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<date> *as_date() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<time>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<time> *as_time() noexcept;
|
||||
/// \brief Returns a pointer to the node as a toml::value<date_time>, if it is one.
|
||||
[[nodiscard]] virtual toml::value<date_time> *as_date_time() noexcept;
|
||||
|
||||
[[nodiscard]] virtual const table *as_table() const noexcept;
|
||||
[[nodiscard]] virtual const array *as_array() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<std::string> *as_string() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<int64_t> *as_integer() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<double> *as_floating_point() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<bool> *as_boolean() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<date> *as_date() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<time> *as_time() const noexcept;
|
||||
[[nodiscard]] virtual const toml::value<date_time> *as_date_time() const noexcept;
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type.
|
||||
///
|
||||
/// \details \cpp
|
||||
///
|
||||
/// toml::value<int64_t>* int_value = node->as<int64_t>();
|
||||
/// toml::table* tbl = node->as<toml::table>();
|
||||
/// if (int_value)
|
||||
/// std::cout << "Node is a value<int64_t>\n";
|
||||
/// else if (tbl)
|
||||
/// std::cout << "Node is a table\n";
|
||||
///
|
||||
/// // fully-qualified value node types also work (useful for template code):
|
||||
/// toml::value<int64_t>* int_value2 = node->as<toml::value<int64_t>>();
|
||||
/// if (int_value2)
|
||||
/// std::cout << "Node is a value<int64_t>\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam T The node type or TOML value type to cast to.
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a
|
||||
/// different type.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(pure) impl::wrap_node<T> *as() noexcept {
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"The template type argument of node::as() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>)
|
||||
return as_table();
|
||||
else if constexpr (std::is_same_v<type, array>)
|
||||
return as_array();
|
||||
else if constexpr (std::is_same_v<type, std::string>)
|
||||
return as_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>)
|
||||
return as_integer();
|
||||
else if constexpr (std::is_same_v<type, double>)
|
||||
return as_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>)
|
||||
return as_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>)
|
||||
return as_date();
|
||||
else if constexpr (std::is_same_v<type, time>)
|
||||
return as_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>)
|
||||
return as_date_time();
|
||||
}
|
||||
|
||||
/// \brief Gets a pointer to the node as a more specific node type (const
|
||||
/// overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(pure) const impl::wrap_node<T> *as() const noexcept {
|
||||
using type = impl::unwrap_node<T>;
|
||||
static_assert((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
|
||||
"The template type argument of node::as() must be one "
|
||||
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
if constexpr (std::is_same_v<type, table>)
|
||||
return as_table();
|
||||
else if constexpr (std::is_same_v<type, array>)
|
||||
return as_array();
|
||||
else if constexpr (std::is_same_v<type, std::string>)
|
||||
return as_string();
|
||||
else if constexpr (std::is_same_v<type, int64_t>)
|
||||
return as_integer();
|
||||
else if constexpr (std::is_same_v<type, double>)
|
||||
return as_floating_point();
|
||||
else if constexpr (std::is_same_v<type, bool>)
|
||||
return as_boolean();
|
||||
else if constexpr (std::is_same_v<type, date>)
|
||||
return as_date();
|
||||
else if constexpr (std::is_same_v<type, time>)
|
||||
return as_time();
|
||||
else if constexpr (std::is_same_v<type, date_time>)
|
||||
return as_date_time();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Value retrieval
|
||||
/// @{
|
||||
|
||||
/// \brief Gets the value contained by this node.
|
||||
///
|
||||
/// \detail This function has 'exact' retrieval semantics; the only return value
|
||||
/// types allowed are the TOML native value types, or types that can
|
||||
/// losslessly represent a native value type (e.g. std::wstring on
|
||||
/// Windows).
|
||||
///
|
||||
/// \tparam T One of the native TOML value types, or a type capable of
|
||||
/// losslessly representing one.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the
|
||||
/// matching type (or losslessly convertible to it), or an
|
||||
/// empty optional.
|
||||
///
|
||||
/// \see node::value()
|
||||
template <typename T> [[nodiscard]] optional<T> value_exact() const noexcept;
|
||||
|
||||
/// \brief Gets the value contained by this node.
|
||||
///
|
||||
/// \detail This function has 'permissive' retrieval semantics; some value types are
|
||||
/// allowed to convert to others (e.g. retrieving a boolean as an
|
||||
/// integer), and the
|
||||
/// specified return value type can be any type where a reasonable
|
||||
/// conversion from a native TOML value exists (e.g. std::wstring on
|
||||
/// Windows). If the source value
|
||||
/// cannot be represented by the destination type, an empty optional
|
||||
/// is returned.
|
||||
///
|
||||
/// \godbolt{zzG81K}
|
||||
///
|
||||
/// \cpp
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// int = -10
|
||||
/// flt = 25.0
|
||||
/// pi = 3.14159
|
||||
/// bool = false
|
||||
/// huge = 9223372036854775807
|
||||
/// str = "foo"
|
||||
/// )"sv);
|
||||
///
|
||||
/// const auto print_value_with_typename =
|
||||
/// [&](std::string_view key, std::string_view type_name, auto* dummy)
|
||||
/// {
|
||||
/// std::cout << "- " << std::setw(18) << std::left << type_name;
|
||||
/// using type = std::remove_pointer_t<decltype(dummy)>;
|
||||
/// if (std::optional<type> val = tbl.get(key)->value<type>())
|
||||
/// std::cout << *val << "\n";
|
||||
/// else
|
||||
/// std::cout << "n/a\n";
|
||||
/// };
|
||||
///
|
||||
/// #define print_value(key, T) print_value_with_typename(key, #T, (T*)nullptr)
|
||||
///
|
||||
/// for (auto key : { "int", "flt", "pi", "bool", "huge", "str" })
|
||||
/// {
|
||||
/// std::cout << tbl[key].type() << " value '" << key << "' as:\n";
|
||||
/// print_value(key, bool);
|
||||
/// print_value(key, int);
|
||||
/// print_value(key, unsigned int);
|
||||
/// print_value(key, long long);
|
||||
/// print_value(key, float);
|
||||
/// print_value(key, double);
|
||||
/// print_value(key, std::string);
|
||||
/// print_value(key, std::string_view);
|
||||
/// print_value(key, const char*);
|
||||
/// std::cout << "\n";
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// integer value 'int' as:
|
||||
/// - bool true
|
||||
/// - int -10
|
||||
/// - unsigned int n/a
|
||||
/// - long long -10
|
||||
/// - float -10
|
||||
/// - double -10
|
||||
/// - std::string n/a
|
||||
/// - std::string_view n/a
|
||||
/// - const char* n/a
|
||||
///
|
||||
/// floating-point value 'flt' as:
|
||||
/// - bool n/a
|
||||
/// - int 25
|
||||
/// - unsigned int 25
|
||||
/// - long long 25
|
||||
/// - float 25
|
||||
/// - double 25
|
||||
/// - std::string n/a
|
||||
/// - std::string_view n/a
|
||||
/// - const char* n/a
|
||||
///
|
||||
/// floating-point value 'pi' as:
|
||||
/// - bool n/a
|
||||
/// - int n/a
|
||||
/// - unsigned int n/a
|
||||
/// - long long n/a
|
||||
/// - float 3.14159
|
||||
/// - double 3.14159
|
||||
/// - std::string n/a
|
||||
/// - std::string_view n/a
|
||||
/// - const char* n/a
|
||||
///
|
||||
/// boolean value 'bool' as:
|
||||
/// - bool false
|
||||
/// - int 0
|
||||
/// - unsigned int 0
|
||||
/// - long long 0
|
||||
/// - float n/a
|
||||
/// - double n/a
|
||||
/// - std::string n/a
|
||||
/// - std::string_view n/a
|
||||
/// - const char* n/a
|
||||
///
|
||||
/// integer value 'huge' as:
|
||||
/// - bool true
|
||||
/// - int n/a
|
||||
/// - unsigned int n/a
|
||||
/// - long long 9223372036854775807
|
||||
/// - float n/a
|
||||
/// - double n/a
|
||||
/// - std::string n/a
|
||||
/// - std::string_view n/a
|
||||
/// - const char* n/a
|
||||
///
|
||||
/// string value 'str' as:
|
||||
/// - bool n/a
|
||||
/// - int n/a
|
||||
/// - unsigned int n/a
|
||||
/// - long long n/a
|
||||
/// - float n/a
|
||||
/// - double n/a
|
||||
/// - std::string foo
|
||||
/// - std::string_view foo
|
||||
/// - const char* foo
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam T One of the native TOML value types, or a type capable of
|
||||
/// converting to one.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching
|
||||
/// type (or convertible to it) and within the range of the
|
||||
/// output type, or an empty optional.
|
||||
///
|
||||
/// \note If you want strict value retrieval semantics that do not allow
|
||||
/// for any type conversions, use node::value_exact() instead.
|
||||
///
|
||||
/// \see node::value_exact()
|
||||
template <typename T> [[nodiscard]] optional<T> value() const noexcept;
|
||||
|
||||
/// \brief Gets the raw value contained by this node, or a default.
|
||||
///
|
||||
/// \tparam T Default value type. Must be one of the
|
||||
/// native TOML value types, or
|
||||
/// convertible to it. \param default_value The default value to return if
|
||||
/// the node wasn't a value, wasn't the
|
||||
/// correct type, or no conversion was possible.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching
|
||||
/// type (or convertible to it) and within the range of the
|
||||
/// output type, or the provided default.
|
||||
///
|
||||
/// \note This function has the same permissive retrieval semantics as
|
||||
/// node::value(). If you want strict value retrieval semantics that
|
||||
/// do not allow for any type conversions, use node::value_exact() instead.
|
||||
///
|
||||
/// \see
|
||||
/// - node::value()
|
||||
/// - node::value_exact()
|
||||
template <typename T> [[nodiscard]] auto value_or(T &&default_value) const noexcept;
|
||||
|
||||
// template <typename T>
|
||||
//[[nodiscard]]
|
||||
// std::vector<T> select_exact() const noexcept;
|
||||
|
||||
// template <typename T>
|
||||
//[[nodiscard]]
|
||||
// std::vector<T> select() const noexcept;
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data.
|
||||
///
|
||||
/// \warning This function is dangerous if used carelessly and **WILL** break your
|
||||
/// code if the
|
||||
/// chosen value type doesn't match the node's actual type. In
|
||||
/// debug builds an assertion will fire when invalid accesses
|
||||
/// are
|
||||
/// attempted:
|
||||
/// \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// min = 32
|
||||
/// max = 45
|
||||
/// )"sv);
|
||||
///
|
||||
/// int64_t& min_ref = tbl.get("min")->ref<int64_t>(); // matching type
|
||||
/// double& max_ref = tbl.get("max")->ref<double>(); // mismatched type, hits
|
||||
/// assert()
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam T One of the TOML value types.
|
||||
///
|
||||
/// \returns A reference to the underlying data.
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(pure) impl::unwrap_node<T> &ref() &noexcept {
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (rvalue
|
||||
/// overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(pure) impl::unwrap_node<T> &&ref() &&noexcept {
|
||||
return do_ref<T>(std::move(*this));
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to a value node's underlying data (const lvalue
|
||||
/// overload).
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(pure) const impl::unwrap_node<T> &ref() const &noexcept {
|
||||
return do_ref<T>(*this);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Metadata
|
||||
/// @{
|
||||
|
||||
/// \brief Returns the source region responsible for generating this node during
|
||||
/// parsing.
|
||||
[[nodiscard]] const source_region &source() const noexcept;
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/// \cond
|
||||
|
||||
template <typename Func, typename N, typename T>
|
||||
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool can_visit_any =
|
||||
can_visit<Func, N, table> || can_visit<Func, N, array> ||
|
||||
can_visit<Func, N, std::string> || can_visit<Func, N, int64_t> ||
|
||||
can_visit<Func, N, double> || can_visit<Func, N, bool> ||
|
||||
can_visit<Func, N, date> || can_visit<Func, N, time> ||
|
||||
can_visit<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool can_visit_all =
|
||||
can_visit<Func, N, table> &&can_visit<Func, N, array>
|
||||
&&can_visit<Func, N, std::string> &&can_visit<Func, N, int64_t> &&can_visit<
|
||||
Func, N, double> &&can_visit<Func, N, bool> &&can_visit<Func, N, date>
|
||||
&&can_visit<Func, N, time> &&can_visit<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N, typename T>
|
||||
static constexpr bool visit_is_nothrow_one =
|
||||
!can_visit<Func, N, T> ||
|
||||
std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
|
||||
|
||||
template <typename Func, typename N>
|
||||
static constexpr bool visit_is_nothrow = visit_is_nothrow_one<Func, N, table>
|
||||
&&visit_is_nothrow_one<Func, N, array> &&visit_is_nothrow_one<
|
||||
Func, N, std::string> &&visit_is_nothrow_one<Func, N, int64_t> &&
|
||||
visit_is_nothrow_one<Func, N, double> &&visit_is_nothrow_one<Func, N, bool>
|
||||
&&visit_is_nothrow_one<Func, N, date> &&visit_is_nothrow_one<
|
||||
Func, N, time> &&visit_is_nothrow_one<Func, N, date_time>;
|
||||
|
||||
template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
|
||||
struct visit_return_type final {
|
||||
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
|
||||
};
|
||||
template <typename Func, typename N, typename T>
|
||||
struct visit_return_type<Func, N, T, false> final {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
|
||||
|
||||
//# these functions are static helpers to preserve const and ref categories
|
||||
//# (otherwise I'd have to implement them thrice)
|
||||
//# ((propagation in C++: a modern horror story))
|
||||
|
||||
template <typename N, typename Func>
|
||||
static decltype(auto)
|
||||
do_visit(N &&n, Func &&visitor) noexcept(visit_is_nothrow<Func &&, N &&>) {
|
||||
static_assert(can_visit_any<Func &&, N &&>,
|
||||
"TOML node visitors must be invocable for at least one of the "
|
||||
"toml::node specializations:" TOML_SA_NODE_TYPE_LIST);
|
||||
|
||||
switch (n.type()) {
|
||||
case node_type::table:
|
||||
if constexpr (can_visit<Func &&, N &&, table>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<table>());
|
||||
break;
|
||||
|
||||
case node_type::array:
|
||||
if constexpr (can_visit<Func &&, N &&, array>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<array>());
|
||||
break;
|
||||
|
||||
case node_type::string:
|
||||
if constexpr (can_visit<Func &&, N &&, std::string>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<std::string>());
|
||||
break;
|
||||
|
||||
case node_type::integer:
|
||||
if constexpr (can_visit<Func &&, N &&, int64_t>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<int64_t>());
|
||||
break;
|
||||
|
||||
case node_type::floating_point:
|
||||
if constexpr (can_visit<Func &&, N &&, double>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<double>());
|
||||
break;
|
||||
|
||||
case node_type::boolean:
|
||||
if constexpr (can_visit<Func &&, N &&, bool>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<bool>());
|
||||
break;
|
||||
|
||||
case node_type::date:
|
||||
if constexpr (can_visit<Func &&, N &&, date>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<date>());
|
||||
break;
|
||||
|
||||
case node_type::time:
|
||||
if constexpr (can_visit<Func &&, N &&, time>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<time>());
|
||||
break;
|
||||
|
||||
case node_type::date_time:
|
||||
if constexpr (can_visit<Func &&, N &&, date_time>)
|
||||
return static_cast<Func &&>(visitor)(
|
||||
static_cast<N &&>(n).template ref_cast<date_time>());
|
||||
break;
|
||||
|
||||
case node_type::none:
|
||||
TOML_UNREACHABLE;
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
if constexpr (can_visit_all<Func &&, N &&>)
|
||||
TOML_UNREACHABLE;
|
||||
else {
|
||||
using return_type = nonvoid<
|
||||
typename visit_return_type<Func &&, N &&, table>::type,
|
||||
nonvoid<
|
||||
typename visit_return_type<Func &&, N &&, array>::type,
|
||||
nonvoid<
|
||||
typename visit_return_type<Func &&, N &&, std::string>::type,
|
||||
nonvoid<
|
||||
typename visit_return_type<Func &&, N &&, int64_t>::type,
|
||||
nonvoid<typename visit_return_type<Func &&, N &&, double>::type,
|
||||
nonvoid<typename visit_return_type<Func &&, N &&,
|
||||
bool>::type,
|
||||
nonvoid<typename visit_return_type<
|
||||
Func &&, N &&, date>::type,
|
||||
nonvoid<typename visit_return_type<
|
||||
Func &&, N &&, time>::type,
|
||||
typename visit_return_type<
|
||||
Func &&, N &&,
|
||||
date_time>::type>>>>>>>>;
|
||||
|
||||
if constexpr (!std::is_void_v<return_type>) {
|
||||
static_assert(std::is_default_constructible_v<return_type>,
|
||||
"Non-exhaustive visitors must return a default-constructible "
|
||||
"type, or void");
|
||||
return return_type{};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \name Visitation
|
||||
/// @{
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type.
|
||||
///
|
||||
/// \details Visitation is useful when you expect
|
||||
/// a node to be one of a set number of types and need
|
||||
/// to handle these types differently. Using `visit()` allows
|
||||
/// you to eliminate some of the casting/conversion boilerplate:
|
||||
/// \cpp
|
||||
///
|
||||
/// node.visit([](auto&& n)
|
||||
/// {
|
||||
/// if constexpr (toml::is_string<decltype(n)>)
|
||||
/// do_something_with_a_string(*n)); //n is a
|
||||
/// toml::value<std::string> else if constexpr
|
||||
/// (toml::is_integer<decltype(n)>)
|
||||
/// do_something_with_an_int(*n); //n is a
|
||||
/// toml::value<int64_t> else throw std::exception{
|
||||
/// "Expected string or integer" };
|
||||
/// });
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam Func A callable type invocable with one or more of the
|
||||
/// toml++ node types.
|
||||
///
|
||||
/// \param visitor The visitor object.
|
||||
///
|
||||
/// \returns The return value of the visitor.
|
||||
/// Can be void. Non-exhaustive visitors must return a
|
||||
/// default-constructible type.
|
||||
///
|
||||
/// \see https://en.wikipedia.org/wiki/Visitor_pattern
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func &&visitor) &noexcept(visit_is_nothrow<Func &&, node &>) {
|
||||
return do_visit(*this, static_cast<Func &&>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type (rvalue
|
||||
/// overload).
|
||||
template <typename Func>
|
||||
decltype(auto)
|
||||
visit(Func &&visitor) &&noexcept(visit_is_nothrow<Func &&, node &&>) {
|
||||
return do_visit(static_cast<node &&>(*this), static_cast<Func &&>(visitor));
|
||||
}
|
||||
|
||||
/// \brief Invokes a visitor on the node based on the node's concrete type (const
|
||||
/// lvalue overload).
|
||||
template <typename Func>
|
||||
decltype(auto)
|
||||
visit(Func &&visitor) const &noexcept(visit_is_nothrow<Func &&, const node &>) {
|
||||
return do_visit(*this, static_cast<Func &&>(visitor));
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Node views
|
||||
/// @{
|
||||
|
||||
/// \brief Creates a node_view pointing to this node.
|
||||
[[nodiscard]] explicit operator node_view<node>() noexcept;
|
||||
|
||||
/// \brief Creates a node_view pointing to this node (const overload).
|
||||
[[nodiscard]] explicit operator node_view<const node>() const noexcept;
|
||||
|
||||
/// @}
|
||||
};
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
|
@ -0,0 +1,102 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_node.h"
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node::node(const node& /*other*/) noexcept
|
||||
{
|
||||
// does not copy source information - this is not an error
|
||||
//
|
||||
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node::node(node && other) noexcept
|
||||
: source_{ std::move(other.source_) }
|
||||
{
|
||||
other.source_.begin = {};
|
||||
other.source_.end = {};
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node& node::operator= (const node& /*rhs*/) noexcept
|
||||
{
|
||||
// does not copy source information - this is not an error
|
||||
//
|
||||
// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
|
||||
|
||||
source_ = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node& node::operator= (node && rhs) noexcept
|
||||
{
|
||||
source_ = std::move(rhs.source_);
|
||||
rhs.source_.begin = {};
|
||||
rhs.source_.end = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) bool node::is_string() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_integer() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_floating_point() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_number() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_boolean() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_date() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_time() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_date_time() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool node::is_array_of_tables() const noexcept { return false; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) table* node::as_table() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) array* node::as_array() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<std::string>* node::as_string() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<int64_t>* node::as_integer() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<double>* node::as_floating_point() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<bool>* node::as_boolean() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<date>* node::as_date() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<time>* node::as_time() noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) value<date_time>* node::as_date_time() noexcept { return nullptr; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) const table* node::as_table() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const array* node::as_array() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<std::string>* node::as_string() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<int64_t>* node::as_integer() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<double>* node::as_floating_point() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<bool>* node::as_boolean() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<date>* node::as_date() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<time>* node::as_time() const noexcept { return nullptr; }
|
||||
TOML_MEMBER_ATTR(const) const value<date_time>* node::as_date_time() const noexcept { return nullptr; }
|
||||
|
||||
TOML_MEMBER_ATTR(const) const source_region& node::source() const noexcept { return source_; }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node::operator node_view<node>() noexcept
|
||||
{
|
||||
return node_view<node>(this);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node::operator node_view<const node>() const noexcept
|
||||
{
|
||||
return node_view<const node>(this);
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
|
@ -0,0 +1,710 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_array.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_value.h"
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A view of a node.
|
||||
///
|
||||
/// \detail A node_view is like a std::optional<toml::node&> (if such a construct were
|
||||
/// legal), with lots of
|
||||
/// toml-specific stuff built-in. It _may_ represent a node, and
|
||||
/// allows you to do many of the same operations that you'd do on
|
||||
/// nodes
|
||||
/// directly,
|
||||
/// as well as easily traversing the node tree by creating
|
||||
/// subviews (via node_view::operator[]). \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
///
|
||||
/// title = "my hardware store"
|
||||
///
|
||||
/// [[products]]
|
||||
/// name = "Hammer"
|
||||
/// sku = 738594937
|
||||
/// keywords = [ "hammer", "construction", "build" ]
|
||||
///
|
||||
/// [[products]]
|
||||
/// name = "Nail"
|
||||
/// sku = 284758393
|
||||
/// color = "gray"
|
||||
///
|
||||
/// )"sv);
|
||||
///
|
||||
/// std::cout << tbl["title"] << "\n";
|
||||
/// std::cout << tbl["products"][0]["name"] << "\n";
|
||||
/// std::cout << tbl["products"][0]["keywords"] << "\n";
|
||||
/// std::cout << tbl["products"][0]["keywords"][2] << "\n";
|
||||
///
|
||||
/// tbl["products"][0]["keywords"].as_array()->push_back("heavy");
|
||||
/// std::cout << tbl["products"][0]["keywords"] << "\n";
|
||||
/// std::cout << "has product[2]: "sv << !!tbl["products"][2] << "\n";
|
||||
/// std::cout << "product[2]: "sv << tbl["products"][2] << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// "my hardware store"
|
||||
/// "Hammer"
|
||||
/// [ "hammer", "construction", "build" ]
|
||||
/// "build"
|
||||
/// [ "hammer", "construction", "build", "heavy" ]
|
||||
/// has product[2]: false
|
||||
/// product[2]:
|
||||
/// \eout
|
||||
template <typename ViewedType> class TOML_API TOML_TRIVIAL_ABI node_view {
|
||||
static_assert(impl::is_one_of<ViewedType, toml::node, const toml::node>,
|
||||
"A toml::node_view<> must wrap toml::node or const toml::node.");
|
||||
|
||||
public:
|
||||
using viewed_type = ViewedType;
|
||||
|
||||
private:
|
||||
template <typename T> friend class TOML_NAMESPACE::node_view;
|
||||
|
||||
mutable viewed_type *node_ = nullptr;
|
||||
|
||||
template <typename Func>
|
||||
static constexpr bool visit_is_nothrow =
|
||||
noexcept(std::declval<viewed_type *>()->visit(std::declval<Func &&>()));
|
||||
|
||||
public:
|
||||
/// \brief Constructs an empty node view.
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view() noexcept = default;
|
||||
|
||||
/// \brief Constructs node_view of a specific node.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit node_view(viewed_type *node) noexcept : node_{node} {}
|
||||
|
||||
/// \brief Constructs node_view of a specific node.
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit node_view(viewed_type &node) noexcept : node_{&node} {}
|
||||
|
||||
///// \brief Copy constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(const node_view &) noexcept = default;
|
||||
|
||||
///// \brief Copy-assignment operator.
|
||||
node_view &operator=(const node_view &) &noexcept = default;
|
||||
|
||||
///// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
node_view(node_view &&) noexcept = default;
|
||||
|
||||
///// \brief Move-assignment operator.
|
||||
node_view &operator=(node_view &&) &noexcept = default;
|
||||
|
||||
/// \brief Returns true if the view references a node.
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
|
||||
/// \brief Returns the node that's being referenced by the view.
|
||||
[[nodiscard]] viewed_type *node() const noexcept { return node_; }
|
||||
|
||||
/// \name Type checks
|
||||
/// @{
|
||||
|
||||
/// \brief Returns the type identifier for the viewed node.
|
||||
[[nodiscard]] node_type type() const noexcept {
|
||||
return node_ ? node_->type() : node_type::none;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the viewed node is a toml::table.
|
||||
[[nodiscard]] bool is_table() const noexcept { return node_ && node_->is_table(); }
|
||||
/// \brief Returns true if the viewed node is a toml::array.
|
||||
[[nodiscard]] bool is_array() const noexcept { return node_ && node_->is_array(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<>.
|
||||
[[nodiscard]] bool is_value() const noexcept { return node_ && node_->is_value(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<string>.
|
||||
[[nodiscard]] bool is_string() const noexcept {
|
||||
return node_ && node_->is_string();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
|
||||
[[nodiscard]] bool is_integer() const noexcept {
|
||||
return node_ && node_->is_integer();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::value<double>.
|
||||
[[nodiscard]] bool is_floating_point() const noexcept {
|
||||
return node_ && node_->is_floating_point();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::value<int64_t> or
|
||||
/// toml::value<double>.
|
||||
[[nodiscard]] bool is_number() const noexcept {
|
||||
return node_ && node_->is_number();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::value<bool>.
|
||||
[[nodiscard]] bool is_boolean() const noexcept {
|
||||
return node_ && node_->is_boolean();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::value<date>.
|
||||
[[nodiscard]] bool is_date() const noexcept { return node_ && node_->is_date(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<time>.
|
||||
[[nodiscard]] bool is_time() const noexcept { return node_ && node_->is_time(); }
|
||||
/// \brief Returns true if the viewed node is a toml::value<date_time>.
|
||||
[[nodiscard]] bool is_date_time() const noexcept {
|
||||
return node_ && node_->is_date_time();
|
||||
}
|
||||
/// \brief Returns true if the viewed node is a toml::array that contains only
|
||||
/// tables.
|
||||
[[nodiscard]] bool is_array_of_tables() const noexcept {
|
||||
return node_ && node_->is_array_of_tables();
|
||||
}
|
||||
|
||||
/// \brief Checks if this view references a node of a specific type.
|
||||
///
|
||||
/// \tparam T A TOML node or value type.
|
||||
///
|
||||
/// \returns Returns true if the viewed node is an instance of the specified
|
||||
/// type.
|
||||
///
|
||||
/// \see toml::node::is()
|
||||
template <typename T> [[nodiscard]] bool is() const noexcept {
|
||||
return node_ ? node_->template is<T>() : false;
|
||||
}
|
||||
|
||||
/// \brief Checks if the viewed node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
|
||||
///
|
||||
/// toml::node* nonmatch{};
|
||||
/// if (cfg["arr"].is_homogeneous(toml::node_type::integer, nonmatch))
|
||||
/// std::cout << "array was homogeneous"sv << "\n";
|
||||
/// else
|
||||
/// std::cout << "array was not homogeneous!\n"
|
||||
/// << "first non-match was a "sv << nonmatch->type() << " at " <<
|
||||
/// nonmatch->source() << "\n"; \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// array was not homogeneous!
|
||||
/// first non-match was a floating-point at line 1, column 18
|
||||
/// \eout
|
||||
///
|
||||
/// \param ntype A TOML node type. <br>
|
||||
/// \conditional_return{toml::node_type::none} "is
|
||||
/// every element the same type?"
|
||||
/// \conditional_return{Anything else} "is every element one of these?"
|
||||
///
|
||||
/// \param first_nonmatch Reference to a pointer in which the address of the first
|
||||
/// non-matching element will be stored
|
||||
/// if the return value is false.
|
||||
///
|
||||
/// \returns True if the viewed node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` if the view does not reference a node, or
|
||||
/// if the viewed node is an empty table or array.
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype,
|
||||
viewed_type *&first_nonmatch) const noexcept {
|
||||
if (!node_) {
|
||||
first_nonmatch = {};
|
||||
return false;
|
||||
}
|
||||
return node_->is_homogeneous(ntype, first_nonmatch);
|
||||
}
|
||||
|
||||
/// \brief Checks if the viewed node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
|
||||
/// std::cout << "homogenous: "sv <<
|
||||
/// cfg["arr"].is_homogeneous(toml::node_type::none) << "\n"; std::cout << "all
|
||||
/// floats: "sv << cfg["arr"].is_homogeneous(toml::node_type::floating_point) <<
|
||||
/// "\n"; std::cout << "all arrays: "sv <<
|
||||
/// cfg["arr"].is_homogeneous(toml::node_type::array) << "\n"; std::cout << "all
|
||||
/// ints: "sv << cfg["arr"].is_homogeneous(toml::node_type::integer) << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// homogeneous: true
|
||||
/// all floats: false
|
||||
/// all arrays: false
|
||||
/// all ints: true
|
||||
/// \eout
|
||||
///
|
||||
/// \param ntype A TOML node type. <br>
|
||||
/// \conditional_return{toml::node_type::none} "is
|
||||
/// every element the same type?"
|
||||
/// \conditional_return{Anything else} "is every element one of these?"
|
||||
///
|
||||
/// \returns True if the viewed node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` if the view does not reference a node, or
|
||||
/// if the viewed node is an empty table or array.
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept {
|
||||
return node_ ? node_->is_homogeneous(ntype) : false;
|
||||
}
|
||||
|
||||
/// \brief Checks if the viewed node contains values/elements of only one type.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
|
||||
/// std::cout << "homogenous: "sv << cfg["arr"].is_homogeneous() << "\n";
|
||||
/// std::cout << "all doubles: "sv << cfg["arr"].is_homogeneous<double>() << "\n";
|
||||
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous<toml::array>() <<
|
||||
/// "\n"; std::cout << "all integers: "sv << cfg["arr"].is_homogeneous<int64_t>() <<
|
||||
/// "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// homogeneous: true
|
||||
/// all floats: false
|
||||
/// all arrays: false
|
||||
/// all ints: true
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam ElemType A TOML node or value type. <br>
|
||||
/// \conditional_return{Left as `void`} "is
|
||||
/// every element the same type?" <br>
|
||||
/// \conditional_return{Explicitly specified} "is every element a T?"
|
||||
///
|
||||
/// \returns True if the viewed node was homogeneous.
|
||||
///
|
||||
/// \remarks Always returns `false` if the view does not reference a node, or
|
||||
/// if the viewed node is an empty table or array.
|
||||
template <typename ElemType = void>
|
||||
[[nodiscard]] bool is_homogeneous() const noexcept {
|
||||
return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>()
|
||||
: false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Type casts
|
||||
/// @{
|
||||
|
||||
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
|
||||
[[nodiscard]] auto as_table() const noexcept { return as<table>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
|
||||
[[nodiscard]] auto as_array() const noexcept { return as<array>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_string() const noexcept { return as<std::string>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_integer() const noexcept { return as<int64_t>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_floating_point() const noexcept { return as<double>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_boolean() const noexcept { return as<bool>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_date() const noexcept { return as<date>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is
|
||||
/// one.
|
||||
[[nodiscard]] auto as_time() const noexcept { return as<time>(); }
|
||||
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it
|
||||
/// is one.
|
||||
[[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
|
||||
|
||||
/// \brief Gets a pointer to the viewed node as a more specific node type.
|
||||
///
|
||||
/// \tparam T The node type or TOML value type to cast to.
|
||||
///
|
||||
/// \returns A pointer to the node as the given type, or nullptr if it was a
|
||||
/// different type.
|
||||
///
|
||||
/// \see toml::node::as()
|
||||
template <typename T> [[nodiscard]] auto as() const noexcept {
|
||||
return node_ ? node_->template as<T>() : nullptr;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Value retrieval
|
||||
/// @{
|
||||
|
||||
/// \brief Gets the value contained by the referenced node.
|
||||
///
|
||||
/// \detail This function has 'exact' retrieval semantics; the only return value
|
||||
/// types allowed are the TOML native value types, or types that can
|
||||
/// losslessly represent a native value type (e.g. std::wstring on
|
||||
/// Windows).
|
||||
///
|
||||
/// \tparam T One of the native TOML value types, or a type capable of
|
||||
/// losslessly representing one.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the
|
||||
/// matching type (or losslessly convertible to it), or an
|
||||
/// empty optional.
|
||||
///
|
||||
/// \see node_view::value()
|
||||
template <typename T> [[nodiscard]] optional<T> value_exact() const noexcept {
|
||||
if (node_)
|
||||
return node_->template value_exact<T>();
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_INIT_WARNINGS;
|
||||
|
||||
/// \brief Gets the value contained by the referenced node.
|
||||
///
|
||||
/// \detail This function has 'permissive' retrieval semantics; some value types are
|
||||
/// allowed to convert to others (e.g. retrieving a boolean as an
|
||||
/// integer), and the
|
||||
/// specified return value type can be any type where a reasonable
|
||||
/// conversion from a native TOML value exists (e.g. std::wstring on
|
||||
/// Windows). If the source value
|
||||
/// cannot be represented by the destination type, an empty optional
|
||||
/// is returned. See node::value() for examples.
|
||||
///
|
||||
/// \tparam T One of the native TOML value types, or a type capable of
|
||||
/// convertible to one.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching
|
||||
/// type (or convertible to it) and within the range of the
|
||||
/// output type, or an empty optional.
|
||||
///
|
||||
/// \note If you want strict value retrieval semantics that do not allow for any
|
||||
/// type conversions, use node_view::value_exact() instead.
|
||||
///
|
||||
/// \see
|
||||
/// - node_view::value()
|
||||
/// - node_view::value_exact()
|
||||
template <typename T> [[nodiscard]] optional<T> value() const noexcept {
|
||||
if (node_)
|
||||
return node_->template value<T>();
|
||||
return {};
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS;
|
||||
|
||||
/// \brief Gets the raw value contained by the referenced node, or a default.
|
||||
///
|
||||
/// \tparam T Default value type. Must be one of the
|
||||
/// native TOML value types, or
|
||||
/// convertible to it. \param default_value The default value to return if
|
||||
/// the node wasn't a value, wasn't the
|
||||
/// correct type, or no conversion was possible.
|
||||
///
|
||||
/// \returns The underlying value if the node was a value of the matching
|
||||
/// type (or convertible to it) and within the range of the
|
||||
/// output type, or the provided default.
|
||||
///
|
||||
/// \note This function has the same permissive retrieval semantics as
|
||||
/// node::value(). If you want strict value retrieval semantics that
|
||||
/// do not allow for any type conversions, use node_view::value_exact()
|
||||
/// instead.
|
||||
///
|
||||
/// \see
|
||||
/// - node_view::value()
|
||||
/// - node_view::value_exact()
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(T &&default_value) const noexcept {
|
||||
using namespace ::toml::impl;
|
||||
|
||||
static_assert(!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
|
||||
|
||||
if constexpr (is_wide_string<T>) {
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
if (node_)
|
||||
return node_->value_or(static_cast<T &&>(default_value));
|
||||
return std::wstring{static_cast<T &&>(default_value)};
|
||||
|
||||
#else
|
||||
|
||||
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
|
||||
|
||||
#endif
|
||||
} else {
|
||||
using value_type =
|
||||
std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
|
||||
std::add_pointer_t<std::add_const_t<
|
||||
std::remove_pointer_t<std::decay_t<T>>>>,
|
||||
std::decay_t<T>>;
|
||||
|
||||
if (node_)
|
||||
return node_->value_or(static_cast<T &&>(default_value));
|
||||
if constexpr (std::is_pointer_v<value_type>)
|
||||
return value_type{default_value};
|
||||
else
|
||||
return static_cast<T &&>(default_value);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Gets a raw reference to the viewed node's underlying data.
|
||||
///
|
||||
/// \warning This function is dangerous if used carelessly and **WILL** break your
|
||||
/// code if the node_view didn't reference a node, or the chosen value
|
||||
/// type doesn't
|
||||
/// match the node's actual type. In debug builds an assertion will
|
||||
/// fire when invalid accesses are attempted: \cpp
|
||||
///
|
||||
/// auto tbl = toml::parse(R"(
|
||||
/// min = 32
|
||||
/// max = 45
|
||||
/// )"sv);
|
||||
///
|
||||
/// int64_t& min_ref = tbl["min"].ref<int64_t>(); // matching type
|
||||
/// double& max_ref = tbl["max"].ref<double>(); // mismatched type, hits assert()
|
||||
/// int64_t& foo_ref = tbl["foo"].ref<int64_t>(); // nonexistent key, hits assert()
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \tparam T One of the TOML value types.
|
||||
///
|
||||
/// \returns A reference to the underlying data.
|
||||
template <typename T> [[nodiscard]] decltype(auto) ref() const noexcept {
|
||||
TOML_ASSERT(
|
||||
node_ &&
|
||||
"toml::node_view::ref() called on a node_view that did not reference a node");
|
||||
return node_->template ref<impl::unwrap_node<T>>();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Visitation
|
||||
/// @{
|
||||
|
||||
/// \brief Invokes a visitor on the viewed node based on its concrete type.
|
||||
///
|
||||
/// \remarks Has no effect if the view does not reference a node.
|
||||
///
|
||||
/// \see node::visit()
|
||||
template <typename Func>
|
||||
decltype(auto) visit(Func &&visitor) const noexcept(visit_is_nothrow<Func &&>) {
|
||||
using return_type = decltype(node_->visit(static_cast<Func &&>(visitor)));
|
||||
if (node_)
|
||||
return node_->visit(static_cast<Func &&>(visitor));
|
||||
if constexpr (!std::is_void_v<return_type>)
|
||||
return return_type{};
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Equality
|
||||
/// @{
|
||||
|
||||
/// \brief Returns true if the viewed node is a table with the same contents as
|
||||
/// RHS.
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs,
|
||||
const table &rhs) noexcept {
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto tbl = lhs.as<table>();
|
||||
return tbl && *tbl == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view &, const table &, );
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as
|
||||
/// RHS.
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs,
|
||||
const array &rhs) noexcept {
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view &, const array &, );
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs,
|
||||
const toml::value<T> &rhs) noexcept {
|
||||
if (lhs.node_ == &rhs)
|
||||
return true;
|
||||
const auto val = lhs.as<T>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view &, const toml::value<T> &,
|
||||
template <typename T>
|
||||
);
|
||||
|
||||
/// \brief Returns true if the viewed node is a value with the same value as RHS.
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<impl::is_native<T> ||
|
||||
impl::is_losslessly_convertible_to_native<T>>>
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs, const T &rhs) noexcept {
|
||||
static_assert(!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Comparison with wide-character strings is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
|
||||
|
||||
if constexpr (impl::is_wide_string<T>) {
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return lhs == impl::narrow(rhs);
|
||||
#else
|
||||
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
} else {
|
||||
const auto val = lhs.as<impl::native_type_of<T>>();
|
||||
return val && *val == rhs;
|
||||
}
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(
|
||||
const node_view &, const T &,
|
||||
template <typename T, typename = std::enable_if_t < impl::is_native<T> ||
|
||||
impl::is_losslessly_convertible_to_native<T>>
|
||||
>);
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as
|
||||
/// the RHS initializer list.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs,
|
||||
const std::initializer_list<T> &rhs) noexcept {
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view &, const std::initializer_list<T> &,
|
||||
template <typename T>
|
||||
);
|
||||
|
||||
/// \brief Returns true if the viewed node is an array with the same contents as
|
||||
/// the RHS vector.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const node_view &lhs,
|
||||
const std::vector<T> &rhs) noexcept {
|
||||
const auto arr = lhs.as<array>();
|
||||
return arr && *arr == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view &, const std::vector<T> &,
|
||||
template <typename T>
|
||||
);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Subviews
|
||||
/// @{
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param key The key of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented a table and
|
||||
/// it contained a value at the given key, or an empty view.
|
||||
[[nodiscard]] node_view operator[](std::string_view key) const noexcept {
|
||||
if (auto tbl = this->as_table())
|
||||
return node_view{tbl->get(key)};
|
||||
return node_view{nullptr};
|
||||
}
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param key The key of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented a table and
|
||||
/// it contained a value at the given key, or an empty view.
|
||||
[[nodiscard]] node_view operator[](std::wstring_view key) const noexcept {
|
||||
if (auto tbl = this->as_table())
|
||||
return node_view{tbl->get(key)};
|
||||
return node_view{nullptr};
|
||||
}
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Returns a view of the selected subnode.
|
||||
///
|
||||
/// \param index The index of the node to retrieve
|
||||
///
|
||||
/// \returns A view of the selected node if this node represented an array
|
||||
/// and it contained a value at the given index, or an empty
|
||||
/// view.
|
||||
[[nodiscard]] node_view operator[](size_t index) const noexcept {
|
||||
if (auto arr = this->as_array())
|
||||
return node_view{arr->get(index)};
|
||||
return node_view{nullptr};
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
template <typename Char, typename T>
|
||||
friend std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &,
|
||||
const node_view<T> &);
|
||||
};
|
||||
template <typename T> node_view(const value<T> &) -> node_view<const node>;
|
||||
node_view(const table &)->node_view<const node>;
|
||||
node_view(const array &)->node_view<const node>;
|
||||
template <typename T> node_view(value<T> &) -> node_view<node>;
|
||||
node_view(table &)->node_view<node>;
|
||||
node_view(array &)->node_view<node>;
|
||||
template <typename T> node_view(const T *) -> node_view<const node>;
|
||||
template <typename T> node_view(T *) -> node_view<node>;
|
||||
|
||||
/// \brief Prints the viewed node out to a stream.
|
||||
template <typename Char, typename T>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os,
|
||||
const node_view<T> &nv) {
|
||||
if (nv.node_) {
|
||||
nv.node_->visit([&os](const auto &n) { os << n; });
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
|
||||
extern template class TOML_API node_view<node>;
|
||||
extern template class TOML_API node_view<const node>;
|
||||
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const node_view<node> &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const node_view<const node> &);
|
||||
|
||||
#define TOML_EXTERN(name, T) \
|
||||
extern template TOML_API optional<T> node_view<node>::name<T>() const noexcept; \
|
||||
extern template TOML_API optional<T> node_view<const node>::name<T>() const noexcept
|
||||
TOML_EXTERN(value_exact, std::string_view);
|
||||
TOML_EXTERN(value_exact, std::string);
|
||||
TOML_EXTERN(value_exact, const char *);
|
||||
TOML_EXTERN(value_exact, int64_t);
|
||||
TOML_EXTERN(value_exact, double);
|
||||
TOML_EXTERN(value_exact, date);
|
||||
TOML_EXTERN(value_exact, time);
|
||||
TOML_EXTERN(value_exact, date_time);
|
||||
TOML_EXTERN(value_exact, bool);
|
||||
TOML_EXTERN(value, std::string_view);
|
||||
TOML_EXTERN(value, std::string);
|
||||
TOML_EXTERN(value, const char *);
|
||||
TOML_EXTERN(value, signed char);
|
||||
TOML_EXTERN(value, signed short);
|
||||
TOML_EXTERN(value, signed int);
|
||||
TOML_EXTERN(value, signed long);
|
||||
TOML_EXTERN(value, signed long long);
|
||||
TOML_EXTERN(value, unsigned char);
|
||||
TOML_EXTERN(value, unsigned short);
|
||||
TOML_EXTERN(value, unsigned int);
|
||||
TOML_EXTERN(value, unsigned long);
|
||||
TOML_EXTERN(value, unsigned long long);
|
||||
TOML_EXTERN(value, double);
|
||||
TOML_EXTERN(value, float);
|
||||
TOML_EXTERN(value, date);
|
||||
TOML_EXTERN(value, time);
|
||||
TOML_EXTERN(value, date_time);
|
||||
TOML_EXTERN(value, bool);
|
||||
#if TOML_HAS_CHAR8
|
||||
TOML_EXTERN(value_exact, std::u8string_view);
|
||||
TOML_EXTERN(value_exact, std::u8string);
|
||||
TOML_EXTERN(value_exact, const char8_t *);
|
||||
TOML_EXTERN(value, std::u8string_view);
|
||||
TOML_EXTERN(value, std::u8string);
|
||||
TOML_EXTERN(value, const char8_t *);
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_EXTERN(value_exact, std::wstring);
|
||||
TOML_EXTERN(value, std::wstring);
|
||||
#endif
|
||||
#undef TOML_EXTERN
|
||||
|
||||
#endif // !TOML_HEADER_ONLY
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_ARITHMETIC_WARNINGS
|
|
@ -0,0 +1,133 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
TOML_DISABLE_WARNINGS;
|
||||
#if TOML_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
TOML_ENABLE_WARNINGS;
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_INIT_WARNINGS;
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
#if defined(DOXYGEN) || !TOML_EXCEPTIONS
|
||||
|
||||
/// \brief An error generated when parsing fails.
|
||||
///
|
||||
/// \remarks This class inherits from std::runtime_error when exceptions are enabled.
|
||||
/// The public interface is the same regardless of exception mode.
|
||||
class parse_error final {
|
||||
private:
|
||||
std::string description_;
|
||||
source_region source_;
|
||||
|
||||
public:
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string &&desc, source_region &&src) noexcept
|
||||
: description_{std::move(desc)}, source_{std::move(src)} {}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string &&desc, const source_region &src) noexcept
|
||||
: parse_error{std::move(desc), source_region{src}} {}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_error(std::string &&desc, const source_position &position,
|
||||
const source_path_ptr &path = {}) noexcept
|
||||
: parse_error{std::move(desc), source_region{position, position, path}} {}
|
||||
|
||||
/// \brief Returns a textual description of the error.
|
||||
/// \remark The backing string is guaranteed to be null-terminated.
|
||||
[[nodiscard]] std::string_view description() const noexcept { return description_; }
|
||||
|
||||
/// \brief Returns the region of the source document responsible for the error.
|
||||
[[nodiscard]] const source_region &source() const noexcept { return source_; }
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class parse_error final : public std::runtime_error {
|
||||
private:
|
||||
source_region source_;
|
||||
|
||||
public:
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char *desc, source_region &&src) noexcept
|
||||
: std::runtime_error{desc}, source_{std::move(src)} {}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char *desc, const source_region &src) noexcept
|
||||
: parse_error{desc, source_region{src}} {}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
TOML_ATTR(nonnull)
|
||||
parse_error(const char *desc, const source_position &position,
|
||||
const source_path_ptr &path = {}) noexcept
|
||||
: parse_error{desc, source_region{position, position, path}} {}
|
||||
|
||||
[[nodiscard]] std::string_view description() const noexcept {
|
||||
return std::string_view{what()};
|
||||
}
|
||||
|
||||
[[nodiscard]] const source_region &source() const noexcept { return source_; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
|
||||
/// \brief Prints a parse_error to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// try
|
||||
/// {
|
||||
/// auto tbl = toml::parse("enabled = trUe"sv);
|
||||
/// }
|
||||
/// catch (const toml::parse_error & err)
|
||||
/// {
|
||||
/// std::cerr << "Parsing failed:\n"sv << err << "\n";
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// Parsing failed:
|
||||
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
|
||||
/// (error occurred at line 1, column 13)
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in
|
||||
/// size. \param lhs The stream. \param rhs The parse_error.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const parse_error &rhs) {
|
||||
lhs << rhs.description();
|
||||
lhs << "\n\t(error occurred at "sv;
|
||||
lhs << rhs.source();
|
||||
lhs << ")"sv;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const parse_error &);
|
||||
#endif
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_INIT_WARNINGS
|
|
@ -0,0 +1,315 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
#include "toml_parse_error.h"
|
||||
#include "toml_table.h"
|
||||
|
||||
#if defined(DOXYGEN) || !TOML_EXCEPTIONS
|
||||
TOML_NAMESPACE_START {
|
||||
TOML_ABI_NAMESPACE_START(noex);
|
||||
|
||||
/// \brief The result of a parsing operation.
|
||||
///
|
||||
/// \detail A parse_result is effectively a discriminated union containing either a
|
||||
/// toml::table or a toml::parse_error. Most member functions assume a
|
||||
/// particular one of these two states, and calling them when in the
|
||||
/// wrong state will cause errors
|
||||
/// (e.g. attempting to access the error object when parsing was
|
||||
/// successful). \cpp parse_result result = toml::parse_file("config.toml"); if
|
||||
/// (result)
|
||||
/// do_stuff_with_a_table(result); //implicitly converts to table&
|
||||
/// else
|
||||
/// std::cerr << "Parse failed:\n"sv << result.error() << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// example output:
|
||||
///
|
||||
/// Parse failed:
|
||||
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
|
||||
/// (error occurred at line 1, column 13 of 'config.toml')
|
||||
/// \eout
|
||||
///
|
||||
/// Getting node_views (`operator[]`) and using the iterator accessor functions
|
||||
/// (`begin(), end()` etc.) are unconditionally safe; when parsing fails these just
|
||||
/// return 'empty' values. A ranged-for loop on a failed parse_result is also safe
|
||||
/// since `begin()` and `end()` return the same iterator and will not lead to any
|
||||
/// dereferences and iterations.
|
||||
///
|
||||
/// \availability <strong>This type only exists when exceptions are disabled.</strong>
|
||||
/// Otherwise parse_result is just an alias for toml::table: \cpp
|
||||
/// #if TOML_EXCEPTIONS
|
||||
/// using parse_result = table;
|
||||
/// #else
|
||||
/// class parse_result final { // ...
|
||||
/// #endif
|
||||
/// \ecpp
|
||||
class parse_result {
|
||||
private:
|
||||
struct storage_t {
|
||||
static constexpr size_t size_ =
|
||||
(sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error)
|
||||
: sizeof(toml::table));
|
||||
static constexpr size_t align_ =
|
||||
(alignof(toml::table) < alignof(parse_error) ? alignof(parse_error)
|
||||
: alignof(toml::table));
|
||||
|
||||
alignas(align_) unsigned char bytes[size_];
|
||||
};
|
||||
|
||||
mutable storage_t storage_;
|
||||
bool err_;
|
||||
|
||||
template <typename Type>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE static Type *get_as(storage_t &s) noexcept {
|
||||
return TOML_LAUNDER(reinterpret_cast<Type *>(s.bytes));
|
||||
}
|
||||
|
||||
void destroy() noexcept {
|
||||
if (err_)
|
||||
get_as<parse_error>(storage_)->~parse_error();
|
||||
else
|
||||
get_as<toml::table>(storage_)->~table();
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped
|
||||
/// toml::table.
|
||||
using iterator = table_iterator;
|
||||
|
||||
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a
|
||||
/// wrapped toml::table.
|
||||
using const_iterator = const_table_iterator;
|
||||
|
||||
/// \brief Returns true if parsing succeeeded.
|
||||
[[nodiscard]] bool succeeded() const noexcept { return !err_; }
|
||||
/// \brief Returns true if parsing failed.
|
||||
[[nodiscard]] bool failed() const noexcept { return err_; }
|
||||
/// \brief Returns true if parsing succeeded.
|
||||
[[nodiscard]] explicit operator bool() const noexcept { return !err_; }
|
||||
|
||||
/// \brief Returns the internal toml::table.
|
||||
[[nodiscard]] toml::table &table() &noexcept {
|
||||
TOML_ASSERT(!err_);
|
||||
return *get_as<toml::table>(storage_);
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::table (rvalue overload).
|
||||
[[nodiscard]] toml::table &&table() &&noexcept {
|
||||
TOML_ASSERT(!err_);
|
||||
return static_cast<toml::table &&>(*get_as<toml::table>(storage_));
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::table (const lvalue overload).
|
||||
[[nodiscard]] const toml::table &table() const &noexcept {
|
||||
TOML_ASSERT(!err_);
|
||||
return *get_as<const toml::table>(storage_);
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::parse_error.
|
||||
[[nodiscard]] parse_error &error() &noexcept {
|
||||
TOML_ASSERT(err_);
|
||||
return *get_as<parse_error>(storage_);
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::parse_error (rvalue overload).
|
||||
[[nodiscard]] parse_error &&error() &&noexcept {
|
||||
TOML_ASSERT(err_);
|
||||
return static_cast<parse_error &&>(*get_as<parse_error>(storage_));
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::parse_error (const lvalue overload).
|
||||
[[nodiscard]] const parse_error &error() const &noexcept {
|
||||
TOML_ASSERT(err_);
|
||||
return *get_as<const parse_error>(storage_);
|
||||
}
|
||||
|
||||
/// \brief Returns the internal toml::table.
|
||||
[[nodiscard]] operator toml::table &() noexcept { return table(); }
|
||||
/// \brief Returns the internal toml::table (rvalue overload).
|
||||
[[nodiscard]] operator toml::table &&() noexcept { return std::move(table()); }
|
||||
/// \brief Returns the internal toml::table (const lvalue overload).
|
||||
[[nodiscard]] operator const toml::table &() const noexcept { return table(); }
|
||||
|
||||
/// \brief Returns the internal toml::parse_error.
|
||||
[[nodiscard]] explicit operator parse_error &() noexcept { return error(); }
|
||||
/// \brief Returns the internal toml::parse_error (rvalue overload).
|
||||
[[nodiscard]] explicit operator parse_error &&() noexcept {
|
||||
return std::move(error());
|
||||
}
|
||||
/// \brief Returns the internal toml::parse_error (const lvalue overload).
|
||||
[[nodiscard]] explicit operator const parse_error &() const noexcept {
|
||||
return error();
|
||||
}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_result() noexcept : err_{true} {
|
||||
::new (static_cast<void *>(storage_.bytes))
|
||||
parse_error{std::string{}, source_region{}};
|
||||
}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit parse_result(toml::table &&tbl) noexcept : err_{false} {
|
||||
::new (static_cast<void *>(storage_.bytes)) toml::table{std::move(tbl)};
|
||||
}
|
||||
|
||||
TOML_NODISCARD_CTOR
|
||||
explicit parse_result(parse_error &&err) noexcept : err_{true} {
|
||||
::new (static_cast<void *>(storage_.bytes)) parse_error{std::move(err)};
|
||||
}
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
parse_result(parse_result &&res) noexcept : err_{res.err_} {
|
||||
if (err_)
|
||||
::new (static_cast<void *>(storage_.bytes)) parse_error{std::move(res).error()};
|
||||
else
|
||||
::new (static_cast<void *>(storage_.bytes)) toml::table{std::move(res).table()};
|
||||
}
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
parse_result &operator=(parse_result &&rhs) noexcept {
|
||||
if (err_ != rhs.err_) {
|
||||
destroy();
|
||||
err_ = rhs.err_;
|
||||
if (err_)
|
||||
::new (static_cast<void *>(storage_.bytes))
|
||||
parse_error{std::move(rhs).error()};
|
||||
else
|
||||
::new (static_cast<void *>(storage_.bytes))
|
||||
toml::table{std::move(rhs).table()};
|
||||
} else {
|
||||
if (err_)
|
||||
error() = std::move(rhs).error();
|
||||
else
|
||||
table() = std::move(rhs).table();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Destructor.
|
||||
~parse_result() noexcept { destroy(); }
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if parsing was successful
|
||||
/// and a matching key existed, or an empty node view.
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<node> operator[](string_view key) noexcept {
|
||||
return err_ ? node_view<node>{} : table()[key];
|
||||
}
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table
|
||||
/// (const overload).
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if parsing was successful
|
||||
/// and a matching key existed, or an empty node view.
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<const node> operator[](string_view key) const noexcept {
|
||||
return err_ ? node_view<const node>{} : table()[key];
|
||||
}
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if parsing was successful
|
||||
/// and a matching key existed, or an empty node view.
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<node> operator[](std::wstring_view key) noexcept {
|
||||
return err_ ? node_view<node>{} : table()[key];
|
||||
}
|
||||
|
||||
/// \brief Gets a node_view for the selected key-value pair in the wrapped table
|
||||
/// (const overload).
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param key The key used for the lookup.
|
||||
///
|
||||
/// \returns A view of the value at the given key if parsing was successful
|
||||
/// and a matching key existed, or an empty node view.
|
||||
///
|
||||
/// \see toml::node_view
|
||||
[[nodiscard]] node_view<const node>
|
||||
operator[](std::wstring_view key) const noexcept {
|
||||
return err_ ? node_view<const node>{} : table()[key];
|
||||
}
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] table_iterator begin() noexcept {
|
||||
return err_ ? table_iterator{} : table().begin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator begin() const noexcept {
|
||||
return err_ ? const_table_iterator{} : table().begin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
|
||||
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
|
||||
[[nodiscard]] const_table_iterator cbegin() const noexcept {
|
||||
return err_ ? const_table_iterator{} : table().cbegin();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped
|
||||
/// table. \remarks Returns a default-constructed 'nothing' iterator if the parsing
|
||||
/// failed.
|
||||
[[nodiscard]] table_iterator end() noexcept {
|
||||
return err_ ? table_iterator{} : table().end();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped
|
||||
/// table. \remarks Returns a default-constructed 'nothing' iterator if the parsing
|
||||
/// failed.
|
||||
[[nodiscard]] const_table_iterator end() const noexcept {
|
||||
return err_ ? const_table_iterator{} : table().end();
|
||||
}
|
||||
|
||||
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped
|
||||
/// table. \remarks Returns a default-constructed 'nothing' iterator if the parsing
|
||||
/// failed.
|
||||
[[nodiscard]] const_table_iterator cend() const noexcept {
|
||||
return err_ ? const_table_iterator{} : table().cend();
|
||||
}
|
||||
|
||||
/// \brief Prints the held error or table object out to a text stream.
|
||||
template <typename Char>
|
||||
friend std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os,
|
||||
const parse_result &result) {
|
||||
return result.err_ ? (os << result.error()) : (os << result.table());
|
||||
}
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END;
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
#endif // !TOML_EXCEPTIONS
|
|
@ -0,0 +1,455 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
#include "toml_parse_error.h"
|
||||
#include "toml_parse_result.h"
|
||||
#include "toml_table.h"
|
||||
#include "toml_utf8_streams.h"
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
[[nodiscard]] TOML_API parse_result do_parse(utf8_reader_interface &&) TOML_MAY_THROW;
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
/// \endcond
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
/// \brief Parses a TOML document from a string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("a = 3"sv);
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(
|
||||
std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
|
||||
|
||||
/// \brief Parses a TOML document from a string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("a = 3"sv, "foo.toml");
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(std::string_view doc,
|
||||
std::string && source_path) TOML_MAY_THROW;
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Parses a TOML document from a string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(
|
||||
std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
/// \brief Parses a TOML document from a char8_t string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse(u8"a = 3"sv);
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(
|
||||
std::u8string_view doc, std::string_view source_path = {}) TOML_MAY_THROW;
|
||||
|
||||
/// \brief Parses a TOML document from a char8_t string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(std::u8string_view doc,
|
||||
std::string && source_path) TOML_MAY_THROW;
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Parses a TOML document from a char8_t string view.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse(u8"a = 3"sv, L"foo.toml");
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse(
|
||||
std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
#endif // TOML_HAS_CHAR8
|
||||
|
||||
/// \brief Parses a TOML document from a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::stringstream ss;
|
||||
/// ss << "a = 3"sv;
|
||||
///
|
||||
/// auto tbl = toml::parse(ss);
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The stream's underlying character type. Must be
|
||||
/// 1 byte in size.
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
template <typename Char>
|
||||
[[nodiscard]] inline parse_result parse(std::basic_istream<Char> & doc,
|
||||
std::string_view source_path = {})
|
||||
TOML_MAY_THROW {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
|
||||
return impl::do_parse(impl::utf8_reader{doc, source_path});
|
||||
}
|
||||
|
||||
/// \brief Parses a TOML document from a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::stringstream ss;
|
||||
/// ss << "a = 3"sv;
|
||||
///
|
||||
/// auto tbl = toml::parse(ss, "foo.toml");
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The stream's underlying character type. Must be
|
||||
/// 1 byte in size.
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
template <typename Char>
|
||||
[[nodiscard]] inline parse_result parse(std::basic_istream<Char> & doc,
|
||||
std::string && source_path) TOML_MAY_THROW {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
|
||||
return impl::do_parse(impl::utf8_reader{doc, std::move(source_path)});
|
||||
}
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Parses a TOML document from a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// std::stringstream ss;
|
||||
/// ss << "a = 3"sv;
|
||||
///
|
||||
/// auto tbl = toml::parse(ss);
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \tparam Char The stream's underlying character type. Must be
|
||||
/// 1 byte in size.
|
||||
/// \param doc The TOML document to parse. Must be
|
||||
/// valid UTF-8. \param source_path The path used to initialize each
|
||||
/// node's
|
||||
/// `source().path`. If you don't have a path
|
||||
/// (or you have no intention of using paths in diagnostics) then this parameter can
|
||||
/// safely be left blank.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
template <typename Char>
|
||||
[[nodiscard]] inline parse_result parse(
|
||||
std::basic_istream<Char> & doc, std::wstring_view source_path) TOML_MAY_THROW {
|
||||
return parse(doc, impl::narrow(source_path));
|
||||
}
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API parse_result parse(std::istream &, std::string_view)
|
||||
TOML_MAY_THROW;
|
||||
extern template TOML_API parse_result parse(std::istream &, std::string &&)
|
||||
TOML_MAY_THROW;
|
||||
#endif
|
||||
|
||||
/// \brief Parses a TOML document from a file.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// toml::parse_result get_foo_toml()
|
||||
/// {
|
||||
/// return toml::parse_file("foo.toml");
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \param file_path The TOML document to parse. Must be valid UTF-8.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse_file(std::string_view file_path)
|
||||
TOML_MAY_THROW;
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
/// \brief Parses a TOML document from a file.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// toml::parse_result get_foo_toml()
|
||||
/// {
|
||||
/// return toml::parse_file(u8"foo.toml");
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \param file_path The TOML document to parse. Must be valid UTF-8.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse_file(std::u8string_view file_path)
|
||||
TOML_MAY_THROW;
|
||||
|
||||
#endif // TOML_HAS_CHAR8
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
/// \brief Parses a TOML document from a file.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// toml::parse_result get_foo_toml()
|
||||
/// {
|
||||
/// return toml::parse_file(L"foo.toml");
|
||||
/// }
|
||||
/// \ecpp
|
||||
///
|
||||
/// \availability This overload is only available when #TOML_WINDOWS_COMPAT is
|
||||
/// enabled.
|
||||
///
|
||||
/// \param file_path The TOML document to parse. Must be valid UTF-8.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result parse_file(std::wstring_view file_path)
|
||||
TOML_MAY_THROW;
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
|
||||
inline namespace literals {
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex);
|
||||
|
||||
/// \brief Parses TOML data from a string literal.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// using namespace toml::literals;
|
||||
///
|
||||
/// auto tbl = "a = 3"_toml;
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param str The string data. Must be valid UTF-8.
|
||||
/// \param len The string length.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result operator"" _toml(const char *str,
|
||||
size_t len) TOML_MAY_THROW;
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
/// \brief Parses TOML data from a UTF-8 string literal.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// using namespace toml::literals;
|
||||
///
|
||||
/// auto tbl = u8"a = 3"_toml;
|
||||
/// std::cout << tbl["a"] << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// 3
|
||||
/// \eout
|
||||
///
|
||||
/// \param str The string data. Must be valid UTF-8.
|
||||
/// \param len The string length.
|
||||
///
|
||||
/// \returns \conditional_return{With exceptions}
|
||||
/// A toml::table.
|
||||
/// \conditional_return{Without exceptions}
|
||||
/// A toml::parse_result.
|
||||
[[nodiscard]] TOML_API parse_result operator"" _toml(const char8_t *str,
|
||||
size_t len) TOML_MAY_THROW;
|
||||
|
||||
#endif // TOML_HAS_CHAR8
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
} // namespace literals
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,900 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#ifndef __cplusplus
|
||||
#error toml++ is a C++ library.
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# COMPILER DETECTION
|
||||
//#====================================================================================================================
|
||||
|
||||
#ifdef __INTELLISENSE__
|
||||
#define TOML_INTELLISENSE 1
|
||||
#else
|
||||
#define TOML_INTELLISENSE 0
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#define TOML_CLANG __clang_major__
|
||||
#else
|
||||
#define TOML_CLANG 0
|
||||
#endif
|
||||
#ifdef __INTEL_COMPILER
|
||||
#define TOML_ICC __INTEL_COMPILER
|
||||
#ifdef __ICL
|
||||
#define TOML_ICC_CL TOML_ICC
|
||||
#else
|
||||
#define TOML_ICC_CL 0
|
||||
#endif
|
||||
#else
|
||||
#define TOML_ICC 0
|
||||
#define TOML_ICC_CL 0
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !TOML_CLANG && !TOML_ICC
|
||||
#define TOML_MSVC _MSC_VER
|
||||
#else
|
||||
#define TOML_MSVC 0
|
||||
#endif
|
||||
#if defined(__GNUC__) && !TOML_CLANG && !TOML_ICC
|
||||
#define TOML_GCC __GNUC__
|
||||
#else
|
||||
#define TOML_GCC 0
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#define TOML_HAS_INCLUDE(header) __has_include(header)
|
||||
#else
|
||||
#define TOML_HAS_INCLUDE(header) 0
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# CLANG
|
||||
//#====================================================================================================================
|
||||
|
||||
#if TOML_CLANG
|
||||
|
||||
#define TOML_PUSH_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS \
|
||||
_Pragma("clang diagnostic ignored \"-Wswitch\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_INIT_WARNINGS \
|
||||
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_ARITHMETIC_WARNINGS \
|
||||
_Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wdouble-promotion\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wchar-subscripts\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wshift-sign-overflow\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS \
|
||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SPAM_WARNINGS \
|
||||
_Pragma("clang diagnostic ignored \"-Wweak-vtables\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wweak-template-vtables\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wpadded\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_POP_WARNINGS \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_WARNINGS \
|
||||
TOML_PUSH_WARNINGS; \
|
||||
_Pragma("clang diagnostic ignored \"-Weverything\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
|
||||
|
||||
#define TOML_ASSUME(cond) __builtin_assume(cond)
|
||||
#define TOML_UNREACHABLE __builtin_unreachable()
|
||||
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
|
||||
#if defined(_MSC_VER) // msvc compat mode
|
||||
#ifdef __has_declspec_attribute
|
||||
#if __has_declspec_attribute(novtable)
|
||||
#define TOML_ABSTRACT_BASE __declspec(novtable)
|
||||
#endif
|
||||
#if __has_declspec_attribute(empty_bases)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
#endif
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __forceinline
|
||||
#endif
|
||||
#if __has_declspec_attribute(noinline)
|
||||
#define TOML_NEVER_INLINE __declspec(noinline)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __has_attribute
|
||||
#if !defined(TOML_ALWAYS_INLINE) && __has_attribute(always_inline)
|
||||
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
|
||||
#endif
|
||||
#if !defined(TOML_NEVER_INLINE) && __has_attribute(noinline)
|
||||
#define TOML_NEVER_INLINE __attribute__((__noinline__))
|
||||
#endif
|
||||
#if !defined(TOML_TRIVIAL_ABI) && __has_attribute(trivial_abi)
|
||||
#define TOML_TRIVIAL_ABI __attribute__((__trivial_abi__))
|
||||
#endif
|
||||
#endif
|
||||
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
|
||||
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
|
||||
|
||||
#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1
|
||||
|
||||
#endif // clang
|
||||
|
||||
//#====================================================================================================================
|
||||
//# MSVC
|
||||
//#====================================================================================================================
|
||||
|
||||
#if TOML_MSVC || TOML_ICC_CL
|
||||
|
||||
#define TOML_CPP_VERSION _MSVC_LANG
|
||||
#if TOML_MSVC // !intel-cl
|
||||
|
||||
#define TOML_PUSH_WARNINGS \
|
||||
__pragma(warning(push)) \
|
||||
static_assert(true)
|
||||
|
||||
#if TOML_HAS_INCLUDE(<CodeAnalysis\Warnings.h>)
|
||||
#pragma warning(push, 0)
|
||||
#include <CodeAnalysis\Warnings.h>
|
||||
#pragma warning(pop)
|
||||
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \
|
||||
__pragma(warning(disable: ALL_CODE_ANALYSIS_WARNINGS)) \
|
||||
static_assert(true)
|
||||
#else
|
||||
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS
|
||||
static_assert(true)
|
||||
#endif
|
||||
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS \
|
||||
__pragma(warning(disable: 4061)) \
|
||||
__pragma(warning(disable: 4062)) \
|
||||
__pragma(warning(disable: 4063)) \
|
||||
__pragma(warning(disable: 26819)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SPAM_WARNINGS \
|
||||
__pragma(warning(disable: 4127)) /* conditional expr is constant */ \
|
||||
__pragma(warning(disable: 4324)) /* structure was padded due to alignment specifier */ \
|
||||
__pragma(warning(disable: 4348)) \
|
||||
__pragma(warning(disable: 4464)) /* relative include path contains '..' */ \
|
||||
__pragma(warning(disable: 4505)) /* unreferenced local function removed */ \
|
||||
__pragma(warning(disable: 4514)) /* unreferenced inline function has been removed */ \
|
||||
__pragma(warning(disable: 4582)) /* constructor is not implicitly called */ \
|
||||
__pragma(warning(disable: 4623)) /* default constructor was implicitly defined as deleted */ \
|
||||
__pragma(warning(disable: 4625)) /* copy constructor was implicitly defined as deleted */ \
|
||||
__pragma(warning(disable: 4626)) /* assignment operator was implicitly defined as deleted */ \
|
||||
__pragma(warning(disable: 4710)) /* function not inlined */ \
|
||||
__pragma(warning(disable: 4711)) /* function selected for automatic expansion */ \
|
||||
__pragma(warning(disable: 4820)) /* N bytes padding added */ \
|
||||
__pragma(warning(disable: 4946)) /* reinterpret_cast used between related classes */ \
|
||||
__pragma(warning(disable: 5026)) /* move constructor was implicitly defined as deleted */ \
|
||||
__pragma(warning(disable: 5027)) /* move assignment operator was implicitly defined as deleted */ \
|
||||
__pragma(warning(disable: 5039)) /* potentially throwing function passed to 'extern "C"' function */ \
|
||||
__pragma(warning(disable: 5045)) /* Compiler will insert Spectre mitigation */ \
|
||||
__pragma(warning(disable: 26451)) \
|
||||
__pragma(warning(disable: 26490)) \
|
||||
__pragma(warning(disable: 26495)) \
|
||||
__pragma(warning(disable: 26812)) \
|
||||
__pragma(warning(disable: 26819)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_ARITHMETIC_WARNINGS \
|
||||
__pragma(warning(disable: 4365)) /* argument signed/unsigned mismatch */ \
|
||||
__pragma(warning(disable: 4738)) /* storing 32-bit float result in memory */ \
|
||||
__pragma(warning(disable: 5219)) /* implicit conversion from integral to float */ \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_POP_WARNINGS \
|
||||
__pragma(warning(pop)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_WARNINGS \
|
||||
__pragma(warning(push, 0)) \
|
||||
__pragma(warning(disable: 4348)) \
|
||||
__pragma(warning(disable: 4668)) \
|
||||
__pragma(warning(disable: 5105)) \
|
||||
TOML_DISABLE_CODE_ANALYSIS_WARNINGS;\
|
||||
TOML_DISABLE_SWITCH_WARNINGS; \
|
||||
TOML_DISABLE_SPAM_WARNINGS; \
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS; \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
|
||||
|
||||
#endif
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __forceinline
|
||||
#endif
|
||||
#define TOML_NEVER_INLINE __declspec(noinline)
|
||||
#define TOML_ASSUME(cond) __assume(cond)
|
||||
#define TOML_UNREACHABLE __assume(0)
|
||||
#define TOML_ABSTRACT_BASE __declspec(novtable)
|
||||
#define TOML_EMPTY_BASES __declspec(empty_bases)
|
||||
#ifdef _CPPUNWIND
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#else
|
||||
#define TOML_COMPILER_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#endif // msvc
|
||||
|
||||
//#====================================================================================================================
|
||||
//# ICC
|
||||
//#====================================================================================================================
|
||||
|
||||
#if TOML_ICC
|
||||
|
||||
#define TOML_PUSH_WARNINGS \
|
||||
__pragma(warning(push)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SPAM_WARNINGS \
|
||||
__pragma(warning(disable: 82)) /* storage class is not first */ \
|
||||
__pragma(warning(disable: 111)) /* statement unreachable (false-positive) */ \
|
||||
__pragma(warning(disable: 869)) /* unreferenced parameter */ \
|
||||
__pragma(warning(disable: 1011)) /* missing return (false-positive) */ \
|
||||
__pragma(warning(disable: 2261)) /* assume expr side-effects discarded */ \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_POP_WARNINGS \
|
||||
__pragma(warning(pop)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_WARNINGS \
|
||||
__pragma(warning(push, 0)) \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_ENABLE_WARNINGS \
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
#endif // icc
|
||||
|
||||
//#====================================================================================================================
|
||||
//# GCC
|
||||
//#====================================================================================================================
|
||||
|
||||
#if TOML_GCC
|
||||
|
||||
#define TOML_PUSH_WARNINGS \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wswitch\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wswitch-enum\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_INIT_WARNINGS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_ARITHMETIC_WARNINGS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wchar-subscripts\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_SPAM_WARNINGS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wpadded\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcast-align\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wcomment\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wuseless-cast\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=pure\"") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_POP_WARNINGS \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
static_assert(true)
|
||||
|
||||
#define TOML_DISABLE_WARNINGS \
|
||||
TOML_PUSH_WARNINGS; \
|
||||
_Pragma("GCC diagnostic ignored \"-Wall\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wextra\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
|
||||
TOML_DISABLE_SWITCH_WARNINGS; \
|
||||
TOML_DISABLE_INIT_WARNINGS; \
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS; \
|
||||
TOML_DISABLE_SHADOW_WARNINGS; \
|
||||
TOML_DISABLE_SPAM_WARNINGS; \
|
||||
static_assert(true)
|
||||
|
||||
|
||||
#define TOML_ENABLE_WARNINGS \
|
||||
TOML_POP_WARNINGS
|
||||
|
||||
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE __attribute__((__always_inline__)) inline
|
||||
#endif
|
||||
#define TOML_NEVER_INLINE __attribute__((__noinline__))
|
||||
#define TOML_UNREACHABLE __builtin_unreachable()
|
||||
#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1) )
|
||||
#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0) )
|
||||
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# USER CONFIGURATION
|
||||
//#====================================================================================================================
|
||||
|
||||
#ifdef TOML_CONFIG_HEADER
|
||||
#include TOML_CONFIG_HEADER
|
||||
#endif
|
||||
|
||||
#ifdef DOXYGEN
|
||||
#define TOML_HEADER_ONLY 0
|
||||
#define TOML_WINDOWS_COMPAT 1
|
||||
#endif
|
||||
|
||||
#if defined(TOML_ALL_INLINE) && !defined(TOML_HEADER_ONLY)
|
||||
#define TOML_HEADER_ONLY TOML_ALL_INLINE
|
||||
#endif
|
||||
|
||||
#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE
|
||||
#undef TOML_HEADER_ONLY
|
||||
#define TOML_HEADER_ONLY 1
|
||||
#endif
|
||||
|
||||
#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY
|
||||
#undef TOML_IMPLEMENTATION
|
||||
#define TOML_IMPLEMENTATION 1
|
||||
#else
|
||||
#define TOML_IMPLEMENTATION 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_API
|
||||
#define TOML_API
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNRELEASED_FEATURES
|
||||
#define TOML_UNRELEASED_FEATURES 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_LARGE_FILES
|
||||
#define TOML_LARGE_FILES 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNDEF_MACROS
|
||||
#define TOML_UNDEF_MACROS 1
|
||||
#endif
|
||||
|
||||
#ifndef TOML_PARSER
|
||||
#define TOML_PARSER 1
|
||||
#endif
|
||||
|
||||
#ifndef TOML_MAX_NESTED_VALUES
|
||||
#define TOML_MAX_NESTED_VALUES 256
|
||||
// this refers to the depth of nested values, e.g. inline tables and arrays.
|
||||
// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job...
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#ifdef _WIN32
|
||||
#ifndef TOML_WINDOWS_COMPAT
|
||||
#define TOML_WINDOWS_COMPAT 1
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT && !defined(TOML_INCLUDE_WINDOWS_H)
|
||||
#define TOML_INCLUDE_WINDOWS_H 0
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(_WIN32) || !defined(TOML_WINDOWS_COMPAT)
|
||||
#undef TOML_WINDOWS_COMPAT
|
||||
#define TOML_WINDOWS_COMPAT 0
|
||||
#endif
|
||||
#if !TOML_WINDOWS_COMPAT
|
||||
#undef TOML_INCLUDE_WINDOWS_H
|
||||
#define TOML_INCLUDE_WINDOWS_H 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TOML_OPTIONAL_TYPE
|
||||
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
|
||||
#else
|
||||
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
|
||||
#endif
|
||||
|
||||
#ifdef TOML_CHAR_8_STRINGS
|
||||
#if TOML_CHAR_8_STRINGS
|
||||
#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; \
|
||||
all value setters and getters can now work with char8_t strings implicitly so changing the underlying string type \
|
||||
is no longer necessary.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# ATTRIBUTES, UTILITY MACROS ETC
|
||||
//#====================================================================================================================
|
||||
|
||||
#ifndef TOML_CPP_VERSION
|
||||
#define TOML_CPP_VERSION __cplusplus
|
||||
#endif
|
||||
#if TOML_CPP_VERSION < 201103L
|
||||
#error toml++ requires C++17 or higher. For a TOML library supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml
|
||||
#elif TOML_CPP_VERSION < 201703L
|
||||
#error toml++ requires C++17 or higher. For a TOML library supporting C++11 see https://github.com/ToruNiina/toml11
|
||||
#elif TOML_CPP_VERSION >= 202600L
|
||||
#define TOML_CPP 26
|
||||
#elif TOML_CPP_VERSION >= 202300L
|
||||
#define TOML_CPP 23
|
||||
#elif TOML_CPP_VERSION >= 202002L
|
||||
#define TOML_CPP 20
|
||||
#elif TOML_CPP_VERSION >= 201703L
|
||||
#define TOML_CPP 17
|
||||
#endif
|
||||
#undef TOML_CPP_VERSION
|
||||
|
||||
#ifndef TOML_COMPILER_EXCEPTIONS
|
||||
#if defined(__EXCEPTIONS) || defined(__cpp_exceptions)
|
||||
#define TOML_COMPILER_EXCEPTIONS 1
|
||||
#else
|
||||
#define TOML_COMPILER_EXCEPTIONS 0
|
||||
#endif
|
||||
#endif
|
||||
#if TOML_COMPILER_EXCEPTIONS
|
||||
#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
|
||||
#undef TOML_EXCEPTIONS
|
||||
#define TOML_EXCEPTIONS 1
|
||||
#endif
|
||||
#else
|
||||
#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS
|
||||
#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler.
|
||||
#endif
|
||||
#undef TOML_EXCEPTIONS
|
||||
#define TOML_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
#if defined(DOXYGEN) || TOML_EXCEPTIONS
|
||||
#define TOML_MAY_THROW
|
||||
#else
|
||||
#define TOML_MAY_THROW noexcept
|
||||
#endif
|
||||
|
||||
#if TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)
|
||||
// not supported by any version of GCC or Clang as of 26/11/2020
|
||||
// not supported by any version of ICC on Linux as of 11/01/2021
|
||||
#define TOML_FLOAT_CHARCONV 0
|
||||
#endif
|
||||
#if defined(__EMSCRIPTEN__) || defined(__APPLE__)
|
||||
// causes link errors on emscripten
|
||||
// causes Mac OS SDK version errors on some versions of Apple Clang
|
||||
#define TOML_INT_CHARCONV 0
|
||||
#endif
|
||||
#ifndef TOML_INT_CHARCONV
|
||||
#define TOML_INT_CHARCONV 1
|
||||
#endif
|
||||
#ifndef TOML_FLOAT_CHARCONV
|
||||
#define TOML_FLOAT_CHARCONV 1
|
||||
#endif
|
||||
#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE(<charconv>)
|
||||
#undef TOML_INT_CHARCONV
|
||||
#undef TOML_FLOAT_CHARCONV
|
||||
#define TOML_INT_CHARCONV 0
|
||||
#define TOML_FLOAT_CHARCONV 0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_PUSH_WARNINGS
|
||||
#define TOML_PUSH_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
|
||||
#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SWITCH_WARNINGS
|
||||
#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_INIT_WARNINGS
|
||||
#define TOML_DISABLE_INIT_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SPAM_WARNINGS
|
||||
#define TOML_DISABLE_SPAM_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS
|
||||
#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_SHADOW_WARNINGS
|
||||
#define TOML_DISABLE_SHADOW_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_POP_WARNINGS
|
||||
#define TOML_POP_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_DISABLE_WARNINGS
|
||||
#define TOML_DISABLE_WARNINGS static_assert(true)
|
||||
#endif
|
||||
#ifndef TOML_ENABLE_WARNINGS
|
||||
#define TOML_ENABLE_WARNINGS static_assert(true)
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ATTR
|
||||
#define TOML_ATTR(...)
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ABSTRACT_BASE
|
||||
#define TOML_ABSTRACT_BASE
|
||||
#endif
|
||||
|
||||
#ifndef TOML_EMPTY_BASES
|
||||
#define TOML_EMPTY_BASES
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ALWAYS_INLINE
|
||||
#define TOML_ALWAYS_INLINE inline
|
||||
#endif
|
||||
#ifndef TOML_NEVER_INLINE
|
||||
#define TOML_NEVER_INLINE
|
||||
#endif
|
||||
|
||||
#ifndef TOML_ASSUME
|
||||
#define TOML_ASSUME(cond) (void)0
|
||||
#endif
|
||||
|
||||
#ifndef TOML_UNREACHABLE
|
||||
#define TOML_UNREACHABLE TOML_ASSERT(false)
|
||||
#endif
|
||||
|
||||
#define TOML_NO_DEFAULT_CASE default: TOML_UNREACHABLE
|
||||
|
||||
#if defined(__cpp_consteval) && __cpp_consteval >= 201811 && !defined(_MSC_VER)
|
||||
// https://developercommunity.visualstudio.com/t/Erroneous-C7595-error-with-consteval-in/1404234
|
||||
#define TOML_CONSTEVAL consteval
|
||||
#else
|
||||
#define TOML_CONSTEVAL constexpr
|
||||
#endif
|
||||
|
||||
#ifdef __has_cpp_attribute
|
||||
#define TOML_HAS_ATTR(...) __has_cpp_attribute(__VA_ARGS__)
|
||||
#else
|
||||
#define TOML_HAS_ATTR(...) 0
|
||||
#endif
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_INTELLISENSE
|
||||
#if !defined(TOML_LIKELY) && TOML_HAS_ATTR(likely) >= 201803
|
||||
#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]]
|
||||
#endif
|
||||
#if !defined(TOML_UNLIKELY) && TOML_HAS_ATTR(unlikely) >= 201803
|
||||
#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
|
||||
#endif
|
||||
#if TOML_HAS_ATTR(nodiscard) >= 201907
|
||||
#define TOML_NODISCARD_CTOR [[nodiscard]]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TOML_LIKELY
|
||||
#define TOML_LIKELY(...) (__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef TOML_UNLIKELY
|
||||
#define TOML_UNLIKELY(...) (__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef TOML_NODISCARD_CTOR
|
||||
#define TOML_NODISCARD_CTOR
|
||||
#endif
|
||||
|
||||
#ifndef TOML_TRIVIAL_ABI
|
||||
#define TOML_TRIVIAL_ABI
|
||||
#endif
|
||||
|
||||
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator == (RHS rhs, LHS lhs) noexcept { return lhs == rhs; } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (LHS lhs, RHS rhs) noexcept { return !(lhs == rhs); } \
|
||||
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); } \
|
||||
static_assert(true)
|
||||
|
||||
#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
|
||||
#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0
|
||||
#endif
|
||||
|
||||
#define TOML_CONCAT_1(x, y) x##y
|
||||
#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
|
||||
|
||||
#define TOML_EVAL_BOOL_1(T, F) T
|
||||
#define TOML_EVAL_BOOL_0(T, F) F
|
||||
|
||||
#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \
|
||||
|| defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE)
|
||||
#define TOML_ARM 1
|
||||
#else
|
||||
#define TOML_ARM 0
|
||||
#endif
|
||||
|
||||
#define TOML_MAKE_FLAGS_(name, op) \
|
||||
[[nodiscard]] \
|
||||
TOML_ALWAYS_INLINE \
|
||||
TOML_ATTR(const) \
|
||||
constexpr name operator op(name lhs, name rhs) noexcept \
|
||||
{ \
|
||||
using under = std::underlying_type_t<name>; \
|
||||
return static_cast<name>(static_cast<under>(lhs) op static_cast<under>(rhs)); \
|
||||
} \
|
||||
constexpr name& operator TOML_CONCAT(op, =)(name & lhs, name rhs) noexcept \
|
||||
{ \
|
||||
return lhs = (lhs op rhs); \
|
||||
} \
|
||||
static_assert(true, "")
|
||||
|
||||
#define TOML_MAKE_FLAGS(name) \
|
||||
TOML_MAKE_FLAGS_(name, &); \
|
||||
TOML_MAKE_FLAGS_(name, |); \
|
||||
TOML_MAKE_FLAGS_(name, ^); \
|
||||
[[nodiscard]] \
|
||||
TOML_ALWAYS_INLINE \
|
||||
TOML_ATTR(const) \
|
||||
constexpr name operator~(name val) noexcept \
|
||||
{ \
|
||||
using under = std::underlying_type_t<name>; \
|
||||
return static_cast<name>(~static_cast<under>(val)); \
|
||||
} \
|
||||
[[nodiscard]] \
|
||||
TOML_ALWAYS_INLINE \
|
||||
TOML_ATTR(const) \
|
||||
constexpr bool operator!(name val) noexcept \
|
||||
{ \
|
||||
using under = std::underlying_type_t<name>; \
|
||||
return !static_cast<under>(val); \
|
||||
} \
|
||||
static_assert(true, "")
|
||||
|
||||
|
||||
#ifndef TOML_LIFETIME_HOOKS
|
||||
#define TOML_LIFETIME_HOOKS 0
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# EXTENDED INT AND FLOAT TYPES
|
||||
//#====================================================================================================================
|
||||
|
||||
#ifdef __FLT16_MANT_DIG__
|
||||
#if __FLT_RADIX__ == 2 \
|
||||
&& __FLT16_MANT_DIG__ == 11 \
|
||||
&& __FLT16_DIG__ == 3 \
|
||||
&& __FLT16_MIN_EXP__ == -13 \
|
||||
&& __FLT16_MIN_10_EXP__ == -4 \
|
||||
&& __FLT16_MAX_EXP__ == 16 \
|
||||
&& __FLT16_MAX_10_EXP__ == 4
|
||||
#if TOML_ARM && (TOML_GCC || TOML_CLANG)
|
||||
#define TOML_FP16 __fp16
|
||||
#endif
|
||||
#if TOML_ARM && TOML_CLANG // not present in g++
|
||||
#define TOML_FLOAT16 _Float16
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__SIZEOF_FLOAT128__) \
|
||||
&& defined(__FLT128_MANT_DIG__) \
|
||||
&& defined(__LDBL_MANT_DIG__) \
|
||||
&& __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__
|
||||
#define TOML_FLOAT128 __float128
|
||||
#endif
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
#define TOML_INT128 __int128_t
|
||||
#define TOML_UINT128 __uint128_t
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# VERSIONS AND NAMESPACES
|
||||
//#====================================================================================================================
|
||||
|
||||
#include "toml_version.h"
|
||||
|
||||
#define TOML_LIB_SINGLE_HEADER 0
|
||||
|
||||
#define TOML_MAKE_VERSION(maj, min, rev) \
|
||||
((maj) * 1000 + (min) * 25 + (rev))
|
||||
|
||||
#if TOML_UNRELEASED_FEATURES
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1)
|
||||
#else
|
||||
#define TOML_LANG_EFFECTIVE_VERSION \
|
||||
TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
#endif
|
||||
|
||||
#define TOML_LANG_HIGHER_THAN(maj, min, rev) \
|
||||
(TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(maj, min, rev))
|
||||
|
||||
#define TOML_LANG_AT_LEAST(maj, min, rev) \
|
||||
(TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(maj, min, rev))
|
||||
|
||||
#define TOML_LANG_UNRELEASED \
|
||||
TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
|
||||
|
||||
#ifndef TOML_ABI_NAMESPACES
|
||||
#ifdef DOXYGEN
|
||||
#define TOML_ABI_NAMESPACES 0
|
||||
#else
|
||||
#define TOML_ABI_NAMESPACES 1
|
||||
#endif
|
||||
#endif
|
||||
#if TOML_ABI_NAMESPACES
|
||||
#define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR)
|
||||
#define TOML_NAMESPACE_END } static_assert(true)
|
||||
#define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR)
|
||||
#define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true)
|
||||
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
|
||||
#define TOML_ABI_NAMESPACE_END } static_assert(true)
|
||||
#else
|
||||
#define TOML_NAMESPACE_START namespace toml
|
||||
#define TOML_NAMESPACE_END static_assert(true)
|
||||
#define TOML_NAMESPACE toml
|
||||
#define TOML_ABI_NAMESPACE_START(...) static_assert(true)
|
||||
#define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true)
|
||||
#define TOML_ABI_NAMESPACE_END static_assert(true)
|
||||
#endif
|
||||
#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl
|
||||
#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END
|
||||
#if TOML_HEADER_ONLY
|
||||
#define TOML_ANON_NAMESPACE_START TOML_IMPL_NAMESPACE_START
|
||||
#define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END
|
||||
#define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl
|
||||
#define TOML_USING_ANON_NAMESPACE using namespace TOML_ANON_NAMESPACE
|
||||
#define TOML_EXTERNAL_LINKAGE inline
|
||||
#define TOML_INTERNAL_LINKAGE inline
|
||||
#else
|
||||
#define TOML_ANON_NAMESPACE_START namespace
|
||||
#define TOML_ANON_NAMESPACE_END static_assert(true)
|
||||
#define TOML_ANON_NAMESPACE
|
||||
#define TOML_USING_ANON_NAMESPACE static_cast<void>(0)
|
||||
#define TOML_EXTERNAL_LINKAGE
|
||||
#define TOML_INTERNAL_LINKAGE static
|
||||
#endif
|
||||
|
||||
//#====================================================================================================================
|
||||
//# ASSERT
|
||||
//#====================================================================================================================
|
||||
|
||||
TOML_DISABLE_WARNINGS;
|
||||
#ifndef TOML_ASSERT
|
||||
#if defined(NDEBUG) || !defined(_DEBUG)
|
||||
#define TOML_ASSERT(expr) static_cast<void>(0)
|
||||
#else
|
||||
#ifndef assert
|
||||
#include <cassert>
|
||||
#endif
|
||||
#define TOML_ASSERT(expr) assert(expr)
|
||||
#endif
|
||||
#endif
|
||||
TOML_ENABLE_WARNINGS;
|
||||
|
||||
//#====================================================================================================================
|
||||
//# DOXYGEN SPAM
|
||||
//#====================================================================================================================
|
||||
|
||||
//# {{
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/// \addtogroup configuration Library Configuration
|
||||
/// \brief Preprocessor macros for configuring library functionality.
|
||||
/// \detail Define these before including toml++ to alter the way it functions.
|
||||
/// \remarks Some of these options have ABI implications; inline namespaces are used to prevent
|
||||
/// you from trying to link incompatible combinations together.
|
||||
/// @{
|
||||
|
||||
|
||||
/// \def TOML_HEADER_ONLY
|
||||
/// \brief Sets whether the library is entirely inline.
|
||||
/// \detail Defaults to `1`.
|
||||
/// \remark Disabling this means that you must define #TOML_IMPLEMENTATION in
|
||||
/// <strong><em>exactly one</em></strong> translation unit in your project:
|
||||
/// \cpp
|
||||
/// // global_header_that_includes_toml++.h
|
||||
/// #define TOML_HEADER_ONLY 0
|
||||
/// #include <toml.hpp>
|
||||
///
|
||||
/// // some_code_file.cpp
|
||||
/// #define TOML_IMPLEMENTATION
|
||||
/// #include "global_header_that_includes_toml++.h"
|
||||
/// \ecpp
|
||||
|
||||
|
||||
/// \def TOML_API
|
||||
/// \brief An annotation to add to public symbols.
|
||||
/// \detail Not defined by default.
|
||||
/// \remark You'd override this with `__declspec(dllexport)` if you were building the library
|
||||
/// into the public API of a DLL on Windows.
|
||||
|
||||
|
||||
/// \def TOML_ASSERT(expr)
|
||||
/// \brief Sets the assert function used by the library.
|
||||
/// \detail Defaults to the standard C `assert()`.
|
||||
|
||||
|
||||
#define TOML_CONFIG_HEADER
|
||||
/// \def TOML_CONFIG_HEADER
|
||||
/// \brief An additional header to include before any other toml++ header files.
|
||||
/// \detail Not defined by default.
|
||||
|
||||
|
||||
/// \def TOML_EXCEPTIONS
|
||||
/// \brief Sets whether the library uses exceptions to report parsing failures.
|
||||
/// \detail Defaults to `1` or `0` according to your compiler's exception mode.
|
||||
|
||||
|
||||
/// \def TOML_IMPLEMENTATION
|
||||
/// \brief Enables the library's implementation when #TOML_HEADER_ONLY is disabled.
|
||||
/// \detail Not defined by default. Meaningless when #TOML_HEADER_ONLY is enabled.
|
||||
|
||||
|
||||
/// \def TOML_LARGE_FILES
|
||||
/// \brief Sets whether line and column indices are 32-bit integers.
|
||||
/// \detail Defaults to `0`.
|
||||
/// \see toml::source_index
|
||||
|
||||
|
||||
#define TOML_OPTIONAL_TYPE
|
||||
/// \def TOML_OPTIONAL_TYPE
|
||||
/// \brief Overrides the `optional<T>` type used by the library.
|
||||
/// \detail Not defined by default (use std::optional).
|
||||
/// \warning The library uses optionals internally in a few places; if you choose to replace the optional type
|
||||
/// it must be with something that is still API-compatible with std::optional
|
||||
/// (e.g. [tl::optional](https://github.com/TartanLlama/optional)).
|
||||
|
||||
|
||||
/// \def TOML_PARSER
|
||||
/// \brief Sets whether the parser-related parts of the library are included.
|
||||
/// \detail Defaults to `1`.
|
||||
/// \remarks If you don't need to parse TOML data from any strings or files (e.g. you're only using the library to
|
||||
/// serialize data as TOML), setting `TOML_PARSER` to `0` can yield decent compilation speed improvements.
|
||||
|
||||
|
||||
#define TOML_SMALL_FLOAT_TYPE
|
||||
/// \def TOML_SMALL_FLOAT_TYPE
|
||||
/// \brief If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it.
|
||||
/// \detail Not defined by default.
|
||||
/// \remark If you're building for a platform that has a built-in half precision float (e.g. `_Float16`), you don't
|
||||
/// need to use this configuration option to make toml++ aware of it; the library comes with that built-in.
|
||||
|
||||
#define TOML_SMALL_INT_TYPE
|
||||
/// \def TOML_SMALL_INT_TYPE
|
||||
/// \brief If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it.
|
||||
/// \detail Not defined by default.
|
||||
|
||||
|
||||
/// \def TOML_UNRELEASED_FEATURES
|
||||
/// \brief Enables support for unreleased TOML language features not yet part of a
|
||||
/// [numbered version](https://github.com/toml-lang/toml/releases).
|
||||
/// \detail Defaults to `0`.
|
||||
/// \see [TOML Language Support](https://github.com/marzer/tomlplusplus/blob/master/README.md#toml-language-support)
|
||||
|
||||
|
||||
/// \def TOML_WINDOWS_COMPAT
|
||||
/// \brief Enables the use of wide strings (wchar_t, std::wstring) in various places throughout the library
|
||||
/// when building for Windows.
|
||||
/// \detail Defaults to `1` when building for Windows, `0` otherwise. Has no effect when building for anything other
|
||||
/// than Windows.
|
||||
/// \remark This <strong>does not</strong> change the underlying string type used to represent TOML keys and string
|
||||
/// values; that will still be std::string. This setting simply enables some narrow <=> wide string
|
||||
/// conversions when necessary at various interface boundaries.
|
||||
/// <br><br>
|
||||
/// If you're building for Windows and you have no need for Windows' "Pretends-to-be-unicode" wide strings,
|
||||
/// you can safely set this to `0`.
|
||||
|
||||
|
||||
/// @}
|
||||
#endif // DOXYGEN
|
||||
//# }}
|
||||
|
||||
// clang-format on
|
|
@ -0,0 +1,478 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_date_time.h"
|
||||
TOML_DISABLE_WARNINGS;
|
||||
#include <cmath>
|
||||
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
|
||||
#include <charconv>
|
||||
#endif
|
||||
#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
|
||||
#include <sstream>
|
||||
#endif
|
||||
#if !TOML_INT_CHARCONV
|
||||
#include <iomanip>
|
||||
#endif
|
||||
TOML_ENABLE_WARNINGS;
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
// Q: "why does print_to_stream() exist? why not just use ostream::write(),
|
||||
// ostream::put() etc?" A: - I'm supporting C++20's char8_t as well; wrapping streams
|
||||
// allows switching string modes transparently.
|
||||
// - I'm using <charconv> to format numerics. Faster and locale-independent.
|
||||
// - I can avoid forcing users to drag in <sstream> and <iomanip>.
|
||||
|
||||
// Q: "there's a bit of reinterpret_casting here, is any of it UB?"
|
||||
// A: - If the source string data is char and the output string is char8_t, then
|
||||
// technically yes,
|
||||
// but not in the other direction. I test in both modes on Clang, GCC and MSVC
|
||||
// and have yet to see it actually causing an issue, but in the event it does
|
||||
// present a problem it's not going to be a show-stopper since all it means is I
|
||||
// need to do duplicate some code.
|
||||
// - Strings in C++. Honestly.
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline void print_to_stream(std::basic_string_view<Char1> str,
|
||||
std::basic_ostream<Char2> & stream) {
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
stream.write(reinterpret_cast<const Char2 *>(str.data()),
|
||||
static_cast<std::streamsize>(str.length()));
|
||||
}
|
||||
|
||||
template <typename Char1, typename Char2>
|
||||
inline void print_to_stream(const std::basic_string<Char1> &str,
|
||||
std::basic_ostream<Char2> &stream) {
|
||||
static_assert(sizeof(Char1) == 1);
|
||||
static_assert(sizeof(Char2) == 1);
|
||||
stream.write(reinterpret_cast<const Char2 *>(str.data()),
|
||||
static_cast<std::streamsize>(str.length()));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(char character, std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
inline void print_to_stream(const char *str, size_t len,
|
||||
std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char *>(str),
|
||||
static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(char8_t character, std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.put(static_cast<Char>(character));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
TOML_ATTR(nonnull)
|
||||
inline void print_to_stream(const char8_t *str, size_t len,
|
||||
std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
stream.write(reinterpret_cast<const Char *>(str),
|
||||
static_cast<std::streamsize>(len));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T> inline constexpr size_t charconv_buffer_length = 0;
|
||||
template <> inline constexpr size_t charconv_buffer_length<double> = 60;
|
||||
template <> inline constexpr size_t charconv_buffer_length<float> = 40;
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<uint64_t> =
|
||||
20; // strlen("18446744073709551615")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<int64_t> =
|
||||
20; // strlen("-9223372036854775808")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
|
||||
template <>
|
||||
inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
|
||||
|
||||
template <typename T, typename Char>
|
||||
inline void print_integer_to_stream(T val, std::basic_ostream<Char> & stream,
|
||||
value_flags format = {}) {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
|
||||
if (!val) {
|
||||
print_to_stream('0', stream);
|
||||
return;
|
||||
}
|
||||
|
||||
int base = 10;
|
||||
if (format != value_flags::none && val >= T{}) {
|
||||
switch (format) {
|
||||
case value_flags::format_as_binary:
|
||||
base = 2;
|
||||
break;
|
||||
case value_flags::format_as_octal:
|
||||
base = 8;
|
||||
break;
|
||||
case value_flags::format_as_hexadecimal:
|
||||
base = 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TOML_INT_CHARCONV
|
||||
{
|
||||
char buf[(sizeof(T) * CHAR_BIT)];
|
||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
|
||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
||||
if (base == 16) {
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (buf[i] >= 'a')
|
||||
buf[i] -= 32;
|
||||
}
|
||||
print_to_stream(buf, len, stream);
|
||||
}
|
||||
#else
|
||||
{
|
||||
using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)),
|
||||
std::make_unsigned_t<T>, unsigned>;
|
||||
using cast_type =
|
||||
std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>,
|
||||
unsigned_type>;
|
||||
|
||||
if TOML_UNLIKELY (format == value_flags::format_as_binary) {
|
||||
bool found_one = false;
|
||||
const auto v = static_cast<unsigned_type>(val);
|
||||
unsigned_type mask = unsigned_type{1}
|
||||
<< (sizeof(unsigned_type) * CHAR_BIT - 1u);
|
||||
for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++) {
|
||||
if ((v & mask)) {
|
||||
print_to_stream('1', stream);
|
||||
found_one = true;
|
||||
} else if (found_one)
|
||||
print_to_stream('0', stream);
|
||||
mask >>= 1;
|
||||
}
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
ss << std::uppercase << std::setbase(base);
|
||||
ss << static_cast<cast_type>(val);
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
inline void print_to_stream(Type val, std::basic_ostream<Char> &stream, \
|
||||
value_flags format) { \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_integer_to_stream(val, stream, format); \
|
||||
}
|
||||
|
||||
TOML_P2S_OVERLOAD(int8_t)
|
||||
TOML_P2S_OVERLOAD(int16_t)
|
||||
TOML_P2S_OVERLOAD(int32_t)
|
||||
TOML_P2S_OVERLOAD(int64_t)
|
||||
TOML_P2S_OVERLOAD(uint8_t)
|
||||
TOML_P2S_OVERLOAD(uint16_t)
|
||||
TOML_P2S_OVERLOAD(uint32_t)
|
||||
TOML_P2S_OVERLOAD(uint64_t)
|
||||
|
||||
#undef TOML_P2S_OVERLOAD
|
||||
|
||||
template <typename T, typename Char>
|
||||
inline void print_floating_point_to_stream(T val, std::basic_ostream<Char> & stream,
|
||||
bool hexfloat = false) {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
|
||||
switch (impl::fpclassify(val)) {
|
||||
case fp_class::neg_inf:
|
||||
print_to_stream("-inf"sv, stream);
|
||||
break;
|
||||
|
||||
case fp_class::pos_inf:
|
||||
print_to_stream("inf"sv, stream);
|
||||
break;
|
||||
|
||||
case fp_class::nan:
|
||||
print_to_stream("nan"sv, stream);
|
||||
break;
|
||||
|
||||
case fp_class::ok: {
|
||||
static constexpr auto needs_decimal_point = [](auto &&s) noexcept {
|
||||
for (auto c : s)
|
||||
if (c == '.' || c == 'E' || c == 'e')
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
#if TOML_FLOAT_CHARCONV
|
||||
{
|
||||
char buf[charconv_buffer_length<T>];
|
||||
const auto res = hexfloat ? std::to_chars(buf, buf + sizeof(buf), val,
|
||||
std::chars_format::hex)
|
||||
: std::to_chars(buf, buf + sizeof(buf), val);
|
||||
const auto str = std::string_view{buf, static_cast<size_t>(res.ptr - buf)};
|
||||
print_to_stream(str, stream);
|
||||
if (!hexfloat && needs_decimal_point(str))
|
||||
print_to_stream(".0"sv, stream);
|
||||
}
|
||||
#else
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
ss.precision(std::numeric_limits<T>::digits10 + 1);
|
||||
if (hexfloat)
|
||||
ss << std::hexfloat;
|
||||
ss << val;
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
if (!hexfloat && needs_decimal_point(str))
|
||||
print_to_stream(".0"sv, stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API void print_floating_point_to_stream(double, std::ostream &,
|
||||
bool);
|
||||
#endif
|
||||
|
||||
#define TOML_P2S_OVERLOAD(Type) \
|
||||
template <typename Char> \
|
||||
inline void print_to_stream(Type val, std::basic_ostream<Char> &stream) { \
|
||||
static_assert(sizeof(Char) == 1); \
|
||||
print_floating_point_to_stream(val, stream); \
|
||||
}
|
||||
|
||||
TOML_P2S_OVERLOAD(double)
|
||||
|
||||
#undef TOML_P2S_OVERLOAD
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(bool val, std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val ? "true"sv : "false"sv, stream);
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
inline void print_to_stream(T val, std::basic_ostream<Char> & stream,
|
||||
size_t zero_pad_to_digits) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
#if TOML_INT_CHARCONV
|
||||
|
||||
char buf[charconv_buffer_length<T>];
|
||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
|
||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
||||
for (size_t i = len; i < zero_pad_to_digits; i++)
|
||||
print_to_stream('0', stream);
|
||||
print_to_stream(buf, static_cast<size_t>(res.ptr - buf), stream);
|
||||
|
||||
#else
|
||||
|
||||
std::ostringstream ss;
|
||||
ss.imbue(std::locale::classic());
|
||||
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
|
||||
ss << std::setfill('0') << std::setw(static_cast<int>(zero_pad_to_digits))
|
||||
<< static_cast<cast_type>(val);
|
||||
const auto str = std::move(ss).str();
|
||||
print_to_stream(str, stream);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::date &val, std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.year, stream, 4_sz);
|
||||
print_to_stream('-', stream);
|
||||
print_to_stream(val.month, stream, 2_sz);
|
||||
print_to_stream('-', stream);
|
||||
print_to_stream(val.day, stream, 2_sz);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::time &val, std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.hour, stream, 2_sz);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(val.minute, stream, 2_sz);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(val.second, stream, 2_sz);
|
||||
if (val.nanosecond && val.nanosecond <= 999999999u) {
|
||||
print_to_stream('.', stream);
|
||||
auto ns = val.nanosecond;
|
||||
size_t digits = 9_sz;
|
||||
while (ns % 10u == 0u) {
|
||||
ns /= 10u;
|
||||
digits--;
|
||||
}
|
||||
print_to_stream(ns, stream, digits);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(toml::time_offset val,
|
||||
std::basic_ostream<Char> & stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
if (!val.minutes)
|
||||
print_to_stream('Z', stream);
|
||||
else {
|
||||
auto mins = static_cast<int>(val.minutes);
|
||||
if (mins < 0) {
|
||||
print_to_stream('-', stream);
|
||||
mins = -mins;
|
||||
} else
|
||||
print_to_stream('+', stream);
|
||||
const auto hours = mins / 60;
|
||||
if (hours) {
|
||||
print_to_stream(static_cast<unsigned int>(hours), stream, 2_sz);
|
||||
mins -= hours * 60;
|
||||
} else
|
||||
print_to_stream("00"sv, stream);
|
||||
print_to_stream(':', stream);
|
||||
print_to_stream(static_cast<unsigned int>(mins), stream, 2_sz);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void print_to_stream(const toml::date_time &val,
|
||||
std::basic_ostream<Char> &stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
print_to_stream(val.date, stream);
|
||||
print_to_stream('T', stream);
|
||||
print_to_stream(val.time, stream);
|
||||
if (val.offset)
|
||||
print_to_stream(*val.offset, stream);
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
|
||||
template <typename T, typename Char>
|
||||
void print_to_stream_with_escapes(T && str, std::basic_ostream<Char> & stream) {
|
||||
static_assert(sizeof(Char) == 1);
|
||||
for (auto c : str) {
|
||||
if TOML_UNLIKELY (c >= '\x00' && c <= '\x1F')
|
||||
print_to_stream(low_character_escape_table[c], stream);
|
||||
else if TOML_UNLIKELY (c == '\x7F')
|
||||
print_to_stream("\\u007F"sv, stream);
|
||||
else if TOML_UNLIKELY (c == '"')
|
||||
print_to_stream("\\\""sv, stream);
|
||||
else if TOML_UNLIKELY (c == '\\')
|
||||
print_to_stream("\\\\"sv, stream);
|
||||
else
|
||||
print_to_stream(c, stream);
|
||||
}
|
||||
}
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_ARITHMETIC_WARNINGS
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief Prints a source_position to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("bar = 42"sv);
|
||||
///
|
||||
/// std::cout << "The value for 'bar' was found on "sv
|
||||
/// << tbl.get("bar")->source().begin()
|
||||
/// << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// The value for 'bar' was found on line 1, column 7
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in
|
||||
/// size. \param lhs The stream. \param rhs The source_position.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const source_position &rhs) {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
impl::print_to_stream("line "sv, lhs);
|
||||
impl::print_to_stream(rhs.line, lhs);
|
||||
impl::print_to_stream(", column "sv, lhs);
|
||||
impl::print_to_stream(rhs.column, lhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// \brief Prints a source_region to a stream.
|
||||
///
|
||||
/// \detail \cpp
|
||||
/// auto tbl = toml::parse("bar = 42", "config.toml");
|
||||
///
|
||||
/// std::cout << "The value for 'bar' was found on "sv
|
||||
/// << tbl.get("bar")->source()
|
||||
/// << "\n";
|
||||
///
|
||||
/// \ecpp
|
||||
///
|
||||
/// \out
|
||||
/// The value for 'bar' was found on line 1, column 7 of 'config.toml'
|
||||
/// \eout
|
||||
///
|
||||
/// \tparam Char The output stream's underlying character type. Must be 1 byte in
|
||||
/// size. \param lhs The stream. \param rhs The source_position.
|
||||
///
|
||||
/// \returns The input stream.
|
||||
template <typename Char>
|
||||
inline std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const source_region &rhs) {
|
||||
static_assert(sizeof(Char) == 1,
|
||||
"The stream's underlying character type must be 1 byte in size.");
|
||||
lhs << rhs.begin;
|
||||
if (rhs.path) {
|
||||
impl::print_to_stream(" of '"sv, lhs);
|
||||
impl::print_to_stream(*rhs.path, lhs);
|
||||
impl::print_to_stream('\'', lhs);
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const source_position &);
|
||||
extern template TOML_API std::ostream &operator<<(std::ostream &,
|
||||
const source_region &);
|
||||
#endif
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_SWITCH_WARNINGS
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,353 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_table.h"
|
||||
#include "toml_node_view.h"
|
||||
|
||||
TOML_NAMESPACE_START
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void table::lh_ctor() noexcept
|
||||
{
|
||||
TOML_TABLE_CREATED;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
void table::lh_dtor() noexcept
|
||||
{
|
||||
TOML_TABLE_DESTROYED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table() noexcept
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table(const table& other) noexcept
|
||||
: node( other ),
|
||||
inline_{ other.inline_ }
|
||||
{
|
||||
for (auto&& [k, v] : other)
|
||||
map.emplace_hint(map.end(), k, impl::make_node(v));
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table(table&& other) noexcept
|
||||
: node( std::move(other) ),
|
||||
map{ std::move(other.map) },
|
||||
inline_{ other.inline_ }
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table& table::operator= (const table& rhs) noexcept
|
||||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
node::operator=(rhs);
|
||||
map.clear();
|
||||
for (auto&& [k, v] : rhs)
|
||||
map.emplace_hint(map.end(), k, impl::make_node(v));
|
||||
inline_ = rhs.inline_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table& table::operator= (table&& rhs) noexcept
|
||||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
node::operator=(std::move(rhs));
|
||||
map = std::move(rhs.map);
|
||||
inline_ = rhs.inline_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::~table() noexcept
|
||||
{
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_dtor();
|
||||
#endif
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::table(impl::table_init_pair* pairs, size_t count) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
if (!pairs[i].value) // empty node_views
|
||||
continue;
|
||||
map.insert_or_assign(
|
||||
std::move(pairs[i].key),
|
||||
std::move(pairs[i].value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#define TOML_MEMBER_ATTR(attr) TOML_EXTERNAL_LINKAGE TOML_ATTR(attr)
|
||||
|
||||
TOML_MEMBER_ATTR(const) node_type table::type() const noexcept { return node_type::table; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_table() const noexcept { return true; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_array() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) bool table::is_value() const noexcept { return false; }
|
||||
TOML_MEMBER_ATTR(const) const table* table::as_table() const noexcept { return this; }
|
||||
TOML_MEMBER_ATTR(const) table* table::as_table() noexcept { return this; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) bool table::is_inline() const noexcept { return inline_; }
|
||||
TOML_EXTERNAL_LINKAGE void table::is_inline(bool val) noexcept { inline_ = val; }
|
||||
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { map.begin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { map.end() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { map.cbegin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { map.cend() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { map.begin() }; }
|
||||
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { map.end() }; }
|
||||
|
||||
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return map.empty(); }
|
||||
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return map.size(); }
|
||||
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { map.clear(); }
|
||||
|
||||
#undef TOML_MEMBER_ATTR
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::is_homogeneous(node_type ntype) const noexcept
|
||||
{
|
||||
if (map.empty())
|
||||
return false;
|
||||
|
||||
if (ntype == node_type::none)
|
||||
ntype = map.cbegin()->second->type();
|
||||
|
||||
for (const auto& [k, v] : map)
|
||||
{
|
||||
(void)k;
|
||||
if (v->type() != ntype)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace impl
|
||||
{
|
||||
template <typename T, typename U>
|
||||
TOML_INTERNAL_LINKAGE
|
||||
bool table_is_homogeneous(T& map, node_type ntype, U& first_nonmatch) noexcept
|
||||
{
|
||||
if (map.empty())
|
||||
{
|
||||
first_nonmatch = {};
|
||||
return false;
|
||||
}
|
||||
if (ntype == node_type::none)
|
||||
ntype = map.cbegin()->second->type();
|
||||
for (const auto& [k, v] : map)
|
||||
{
|
||||
(void)k;
|
||||
if (v->type() != ntype)
|
||||
{
|
||||
first_nonmatch = v.get();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
|
||||
{
|
||||
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
|
||||
{
|
||||
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<node> table::operator[] (std::string_view key) noexcept
|
||||
{
|
||||
return node_view<node>{ this->get(key) };
|
||||
}
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<const node> table::operator[] (std::string_view key) const noexcept
|
||||
{
|
||||
return node_view<const node>{ this->get(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(iterator pos) noexcept
|
||||
{
|
||||
return { map.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(const_iterator pos) noexcept
|
||||
{
|
||||
return { map.erase(pos.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::erase(const_iterator first, const_iterator last) noexcept
|
||||
{
|
||||
return { map.erase(first.raw_, last.raw_) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::erase(std::string_view key) noexcept
|
||||
{
|
||||
if (auto it = map.find(key); it != map.end())
|
||||
{
|
||||
map.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node* table::get(std::string_view key) noexcept
|
||||
{
|
||||
return do_get(map, key);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const node* table::get(std::string_view key) const noexcept
|
||||
{
|
||||
return do_get(map, key);
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::find(std::string_view key) noexcept
|
||||
{
|
||||
return { map.find(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::const_iterator table::find(std::string_view key) const noexcept
|
||||
{
|
||||
return { map.find(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::contains(std::string_view key) const noexcept
|
||||
{
|
||||
return do_contains(map, key);
|
||||
}
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<node> table::operator[] (std::wstring_view key) noexcept
|
||||
{
|
||||
return node_view<node>{ this->get(key) };
|
||||
}
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node_view<const node> table::operator[] (std::wstring_view key) const noexcept
|
||||
{
|
||||
return node_view<const node>{ this->get(key) };
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::erase(std::wstring_view key) noexcept
|
||||
{
|
||||
return erase(impl::narrow(key));
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
node* table::get(std::wstring_view key) noexcept
|
||||
{
|
||||
return get(impl::narrow(key));
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const node* table::get(std::wstring_view key) const noexcept
|
||||
{
|
||||
return get(impl::narrow(key));
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::iterator table::find(std::wstring_view key) noexcept
|
||||
{
|
||||
return find(impl::narrow(key));
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
table::const_iterator table::find(std::wstring_view key) const noexcept
|
||||
{
|
||||
return find(impl::narrow(key));
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool table::contains(std::wstring_view key) const noexcept
|
||||
{
|
||||
return contains(impl::narrow(key));
|
||||
}
|
||||
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator == (const table& lhs, const table& rhs) noexcept
|
||||
{
|
||||
if (&lhs == &rhs)
|
||||
return true;
|
||||
if (lhs.map.size() != rhs.map.size())
|
||||
return false;
|
||||
|
||||
for (auto l = lhs.map.begin(), r = rhs.map.begin(), e = lhs.map.end(); l != e; l++, r++)
|
||||
{
|
||||
if (l->first != r->first)
|
||||
return false;
|
||||
|
||||
const auto lhs_type = l->second->type();
|
||||
const node& rhs_ = *r->second;
|
||||
const auto rhs_type = rhs_.type();
|
||||
if (lhs_type != rhs_type)
|
||||
return false;
|
||||
|
||||
const bool equal = l->second->visit([&](const auto& lhs_) noexcept
|
||||
{
|
||||
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
|
||||
});
|
||||
if (!equal)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool operator != (const table& lhs, const table& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,332 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
#include "toml_parse_error.h"
|
||||
#include "toml_utf8.h"
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
template <typename T> class utf8_byte_stream;
|
||||
|
||||
inline constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
|
||||
|
||||
template <typename Char>
|
||||
class TOML_API utf8_byte_stream<std::basic_string_view<Char>> final {
|
||||
static_assert(sizeof(Char) == 1_sz);
|
||||
|
||||
private:
|
||||
std::basic_string_view<Char> source;
|
||||
size_t position = {};
|
||||
|
||||
public:
|
||||
explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept
|
||||
: source{sv} {
|
||||
// trim trailing nulls
|
||||
const size_t initial_len = source.length();
|
||||
size_t actual_len = initial_len;
|
||||
for (size_t i = actual_len; i-- > 0_sz;) {
|
||||
if (source[i] != Char{}) // not '\0'
|
||||
{
|
||||
actual_len = i + 1_sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (initial_len != actual_len)
|
||||
source = source.substr(0_sz, actual_len);
|
||||
|
||||
// skip bom
|
||||
if (actual_len >= 3_sz &&
|
||||
memcmp(utf8_byte_order_mark.data(), source.data(), 3_sz) == 0)
|
||||
position += 3_sz;
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE constexpr bool eof() const noexcept {
|
||||
return position >= source.length();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE constexpr bool peek_eof() const noexcept {
|
||||
return eof();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE constexpr bool error() const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr unsigned int operator()() noexcept {
|
||||
if (position >= source.length())
|
||||
return 0xFFFFFFFFu;
|
||||
return static_cast<unsigned int>(static_cast<uint8_t>(source[position++]));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
class TOML_API utf8_byte_stream<std::basic_istream<Char>> final {
|
||||
static_assert(sizeof(Char) == 1_sz);
|
||||
|
||||
private:
|
||||
std::basic_istream<Char> *source;
|
||||
|
||||
public:
|
||||
explicit utf8_byte_stream(std::basic_istream<Char> &stream) : source{&stream} {
|
||||
if (!source->good()) // eof, fail, bad
|
||||
return;
|
||||
|
||||
const auto initial_pos = source->tellg();
|
||||
Char bom[3];
|
||||
source->read(bom, 3);
|
||||
if (source->bad() || (source->gcount() == 3 &&
|
||||
memcmp(utf8_byte_order_mark.data(), bom, 3_sz) == 0))
|
||||
return;
|
||||
|
||||
source->clear();
|
||||
source->seekg(initial_pos, std::basic_istream<Char>::beg);
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE bool eof() const noexcept { return source->eof(); }
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE bool peek_eof() const {
|
||||
using stream_traits =
|
||||
typename std::remove_pointer_t<decltype(source)>::traits_type;
|
||||
return eof() || source->peek() == stream_traits::eof();
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE bool error() const noexcept { return !(*source); }
|
||||
|
||||
[[nodiscard]] unsigned int operator()() {
|
||||
auto val = source->get();
|
||||
if (val == std::basic_istream<Char>::traits_type::eof())
|
||||
return 0xFFFFFFFFu;
|
||||
return static_cast<unsigned int>(val);
|
||||
}
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf);
|
||||
|
||||
struct utf8_codepoint final {
|
||||
char32_t value;
|
||||
char bytes[4];
|
||||
source_position position;
|
||||
|
||||
[[nodiscard]] std::string_view as_view() const noexcept {
|
||||
return bytes[3] ? std::string_view{bytes, 4_sz} : std::string_view{bytes};
|
||||
}
|
||||
|
||||
[[nodiscard]] TOML_ATTR(pure) constexpr operator char32_t &() noexcept {
|
||||
return value;
|
||||
}
|
||||
[[nodiscard]] TOML_ATTR(pure) constexpr operator const char32_t &() const noexcept {
|
||||
return value;
|
||||
}
|
||||
[[nodiscard]] TOML_ATTR(pure) constexpr const char32_t &operator*() const noexcept {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_trivial_v<utf8_codepoint>);
|
||||
static_assert(std::is_standard_layout_v<utf8_codepoint>);
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_LARGE_FILES
|
||||
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
#if TOML_EXCEPTIONS
|
||||
#define TOML_ERROR_CHECK (void)0
|
||||
#define TOML_ERROR throw parse_error
|
||||
#else
|
||||
#define TOML_ERROR_CHECK \
|
||||
if (err) \
|
||||
return nullptr
|
||||
#define TOML_ERROR err.emplace
|
||||
#endif
|
||||
|
||||
struct TOML_ABSTRACT_BASE utf8_reader_interface {
|
||||
[[nodiscard]] virtual const source_path_ptr &source_path() const noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual const utf8_codepoint *read_next() = 0;
|
||||
|
||||
[[nodiscard]] virtual bool peek_eof() const = 0;
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
|
||||
[[nodiscard]] virtual optional<parse_error> &&error() noexcept = 0;
|
||||
|
||||
#endif
|
||||
|
||||
virtual ~utf8_reader_interface() noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TOML_EMPTY_BASES TOML_API utf8_reader final : public utf8_reader_interface {
|
||||
private:
|
||||
utf8_byte_stream<T> stream;
|
||||
utf8_decoder decoder;
|
||||
utf8_codepoint codepoints[2];
|
||||
size_t cp_idx = 1;
|
||||
uint8_t current_byte_count{};
|
||||
source_path_ptr source_path_;
|
||||
#if !TOML_EXCEPTIONS
|
||||
optional<parse_error> err;
|
||||
#endif
|
||||
|
||||
public:
|
||||
template <typename U, typename String = std::string_view>
|
||||
explicit utf8_reader(U &&source, String &&source_path = {}) noexcept(
|
||||
std::is_nothrow_constructible_v<utf8_byte_stream<T>, U &&>)
|
||||
: stream{static_cast<U &&>(source)} {
|
||||
std::memset(codepoints, 0, sizeof(codepoints));
|
||||
codepoints[0].position = {1, 1};
|
||||
codepoints[1].position = {1, 1};
|
||||
|
||||
if (!source_path.empty())
|
||||
source_path_ =
|
||||
std::make_shared<const std::string>(static_cast<String &&>(source_path));
|
||||
}
|
||||
|
||||
[[nodiscard]] const source_path_ptr &source_path() const noexcept override {
|
||||
return source_path_;
|
||||
}
|
||||
|
||||
[[nodiscard]] const utf8_codepoint *read_next() override {
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
auto &prev = codepoints[(cp_idx - 1_sz) % 2_sz];
|
||||
|
||||
if (stream.eof())
|
||||
return nullptr;
|
||||
else if (stream.error())
|
||||
TOML_ERROR("An error occurred while reading from the underlying stream",
|
||||
prev.position, source_path_);
|
||||
else if (decoder.error())
|
||||
TOML_ERROR("Encountered invalid utf-8 sequence", prev.position, source_path_);
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
while (true) {
|
||||
uint8_t next_byte;
|
||||
{
|
||||
unsigned int next_byte_raw{0xFFFFFFFFu};
|
||||
if constexpr (noexcept(stream()) || !TOML_EXCEPTIONS) {
|
||||
next_byte_raw = stream();
|
||||
}
|
||||
#if TOML_EXCEPTIONS
|
||||
else {
|
||||
try {
|
||||
next_byte_raw = stream();
|
||||
} catch (const std::exception &exc) {
|
||||
throw parse_error{exc.what(), prev.position, source_path_};
|
||||
} catch (...) {
|
||||
throw parse_error{"An unspecified error occurred", prev.position,
|
||||
source_path_};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (next_byte_raw >= 256u) {
|
||||
if (stream.eof()) {
|
||||
if (decoder.needs_more_input())
|
||||
TOML_ERROR(
|
||||
"Encountered EOF during incomplete utf-8 code point sequence",
|
||||
prev.position, source_path_);
|
||||
return nullptr;
|
||||
} else
|
||||
TOML_ERROR("An error occurred while reading from the underlying stream",
|
||||
prev.position, source_path_);
|
||||
}
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
next_byte = static_cast<uint8_t>(next_byte_raw);
|
||||
}
|
||||
|
||||
decoder(next_byte);
|
||||
if (decoder.error())
|
||||
TOML_ERROR("Encountered invalid utf-8 sequence", prev.position, source_path_);
|
||||
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
auto ¤t = codepoints[cp_idx % 2_sz];
|
||||
current.bytes[current_byte_count++] = static_cast<char>(next_byte);
|
||||
if (decoder.has_code_point()) {
|
||||
// store codepoint
|
||||
current.value = decoder.codepoint;
|
||||
|
||||
// reset prev (will be the next 'current')
|
||||
std::memset(prev.bytes, 0, sizeof(prev.bytes));
|
||||
current_byte_count = {};
|
||||
if (is_line_break<false>(current.value))
|
||||
prev.position = {static_cast<source_index>(current.position.line + 1), 1};
|
||||
else
|
||||
prev.position = {current.position.line,
|
||||
static_cast<source_index>(current.position.column + 1)};
|
||||
cp_idx++;
|
||||
return ¤t;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool peek_eof() const override { return stream.peek_eof(); }
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
|
||||
[[nodiscard]] optional<parse_error> &&error() noexcept override {
|
||||
return std::move(err);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_string_view<Char>, std::string_view)
|
||||
-> utf8_reader<std::basic_string_view<Char>>;
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_string_view<Char>, std::string &&)
|
||||
-> utf8_reader<std::basic_string_view<Char>>;
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_istream<Char> &, std::string_view)
|
||||
-> utf8_reader<std::basic_istream<Char>>;
|
||||
template <typename Char>
|
||||
utf8_reader(std::basic_istream<Char> &, std::string &&)
|
||||
-> utf8_reader<std::basic_istream<Char>>;
|
||||
|
||||
class TOML_EMPTY_BASES TOML_API utf8_buffered_reader final
|
||||
: public utf8_reader_interface {
|
||||
public:
|
||||
static constexpr size_t max_history_length = 72;
|
||||
|
||||
private:
|
||||
static constexpr size_t history_buffer_size =
|
||||
max_history_length - 1; //'head' is stored in the reader
|
||||
utf8_reader_interface &reader;
|
||||
struct {
|
||||
|
||||
utf8_codepoint buffer[history_buffer_size];
|
||||
size_t count, first;
|
||||
} history = {};
|
||||
const utf8_codepoint *head = {};
|
||||
size_t negative_offset = {};
|
||||
|
||||
public:
|
||||
explicit utf8_buffered_reader(utf8_reader_interface &reader_) noexcept;
|
||||
const source_path_ptr &source_path() const noexcept override;
|
||||
const utf8_codepoint *read_next() override;
|
||||
const utf8_codepoint *step_back(size_t count) noexcept;
|
||||
bool peek_eof() const override;
|
||||
#if !TOML_EXCEPTIONS
|
||||
optional<parse_error> &&error() noexcept override;
|
||||
#endif
|
||||
};
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
|
@ -0,0 +1,110 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
//# {{
|
||||
#include "toml_preprocessor.h"
|
||||
#if !TOML_IMPLEMENTATION
|
||||
#error This is an implementation-only header.
|
||||
#endif
|
||||
#if !TOML_PARSER
|
||||
#error This header cannot not be included when TOML_PARSER is disabled.
|
||||
#endif
|
||||
//# }}
|
||||
|
||||
#include "toml_utf8_streams.h"
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
#undef TOML_ERROR_CHECK
|
||||
#define TOML_ERROR_CHECK if (reader.error()) return nullptr
|
||||
#endif
|
||||
|
||||
TOML_IMPL_NAMESPACE_START
|
||||
{
|
||||
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
utf8_buffered_reader::utf8_buffered_reader(utf8_reader_interface& reader_) noexcept
|
||||
: reader{ reader_ }
|
||||
{}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const source_path_ptr& utf8_buffered_reader::source_path() const noexcept
|
||||
{
|
||||
return reader.source_path();
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const utf8_codepoint* utf8_buffered_reader::read_next()
|
||||
{
|
||||
TOML_ERROR_CHECK;
|
||||
|
||||
if (negative_offset)
|
||||
{
|
||||
negative_offset--;
|
||||
|
||||
// an entry negative offset of 1 just means "replay the current head"
|
||||
if (!negative_offset)
|
||||
return head;
|
||||
|
||||
// otherwise step back into the history buffer
|
||||
else
|
||||
return history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first character read from stream
|
||||
if TOML_UNLIKELY(!history.count && !head)
|
||||
head = reader.read_next();
|
||||
|
||||
// subsequent characters and not eof
|
||||
else if (head)
|
||||
{
|
||||
if TOML_UNLIKELY(history.count < history_buffer_size)
|
||||
history.buffer[history.count++] = *head;
|
||||
else
|
||||
history.buffer[(history.first++ + history_buffer_size) % history_buffer_size] = *head;
|
||||
|
||||
head = reader.read_next();
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
const utf8_codepoint* utf8_buffered_reader::step_back(size_t count) noexcept
|
||||
{
|
||||
TOML_ERROR_CHECK;
|
||||
TOML_ASSERT(history.count);
|
||||
TOML_ASSERT(negative_offset + count <= history.count);
|
||||
|
||||
negative_offset += count;
|
||||
|
||||
return negative_offset
|
||||
? history.buffer + ((history.first + history.count - negative_offset) % history_buffer_size)
|
||||
: head;
|
||||
}
|
||||
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
bool utf8_buffered_reader::peek_eof() const
|
||||
{
|
||||
return reader.peek_eof();
|
||||
}
|
||||
|
||||
#if !TOML_EXCEPTIONS
|
||||
TOML_EXTERNAL_LINKAGE
|
||||
optional<parse_error>&& utf8_buffered_reader::error() noexcept
|
||||
{
|
||||
return reader.error();
|
||||
}
|
||||
#endif
|
||||
|
||||
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
|
||||
#undef TOML_ERROR_CHECK
|
||||
#undef TOML_ERROR
|
|
@ -0,0 +1,940 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include "toml_node.h"
|
||||
#include "toml_print_to_stream.h"
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
#define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
|
||||
#else
|
||||
#define TOML_SA_VALUE_MESSAGE_WSTRING
|
||||
#endif
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
|
||||
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
|
||||
#else
|
||||
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
|
||||
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
|
||||
#endif
|
||||
|
||||
#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
|
||||
"The " type_arg " must be one of:" TOML_SA_LIST_NEW \
|
||||
"A native TOML value type" TOML_SA_NATIVE_VALUE_TYPE_LIST \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native " \
|
||||
"TOML value type" TOML_SA_LIST_BEG \
|
||||
"std::string" TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP \
|
||||
"any signed integer type >= 64 bits" TOML_SA_LIST_SEP \
|
||||
"any floating-point type >= 64 bits" TOML_SA_LIST_END \
|
||||
\
|
||||
TOML_SA_LIST_NXT \
|
||||
"An immutable view type not requiring additional temporary storage" TOML_SA_LIST_BEG \
|
||||
"std::string_view" TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP \
|
||||
"const char*" TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_END
|
||||
|
||||
#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
|
||||
"The " type_arg " must be one of:" TOML_SA_LIST_NEW \
|
||||
"A native TOML value type" TOML_SA_NATIVE_VALUE_TYPE_LIST \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native " \
|
||||
"TOML value type" TOML_SA_LIST_BEG \
|
||||
"std::string" TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP \
|
||||
"any signed integer type >= 64 bits" TOML_SA_LIST_SEP \
|
||||
"any floating-point type >= 64 bits" TOML_SA_LIST_END \
|
||||
\
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a " \
|
||||
"native TOML value type" TOML_SA_LIST_BEG "any other integer type" TOML_SA_LIST_SEP \
|
||||
"any floating-point type >= 32 bits" TOML_SA_LIST_END \
|
||||
\
|
||||
TOML_SA_LIST_NXT \
|
||||
"An immutable view type not requiring additional temporary storage" TOML_SA_LIST_BEG \
|
||||
"std::string_view" TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP \
|
||||
"const char*" TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_END
|
||||
#endif // !DOXYGEN
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||
|
||||
/// \cond
|
||||
TOML_IMPL_NAMESPACE_START {
|
||||
template <typename T, typename...> struct native_value_maker {
|
||||
template <typename... Args>
|
||||
[[nodiscard]] static T
|
||||
make(Args &&...args) noexcept(std::is_nothrow_constructible_v<T, Args &&...>) {
|
||||
return T(static_cast<Args &&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct native_value_maker<T, T> {
|
||||
template <typename U>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE static U &&make(U &&val) noexcept {
|
||||
return static_cast<U &&>(val);
|
||||
}
|
||||
};
|
||||
|
||||
#if TOML_HAS_CHAR8 || TOML_WINDOWS_COMPAT
|
||||
|
||||
struct string_maker {
|
||||
template <typename T> [[nodiscard]] static std::string make(T &&arg) noexcept {
|
||||
#if TOML_HAS_CHAR8
|
||||
if constexpr (is_one_of<std::decay_t<T>, char8_t *, const char8_t *>)
|
||||
return std::string(
|
||||
reinterpret_cast<const char *>(static_cast<const char8_t *>(arg)));
|
||||
else if constexpr (is_one_of<remove_cvref_t<T>, std::u8string,
|
||||
std::u8string_view>)
|
||||
return std::string(
|
||||
reinterpret_cast<const char *>(static_cast<const char8_t *>(arg.data())),
|
||||
arg.length());
|
||||
#endif // TOML_HAS_CHAR8
|
||||
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
if constexpr (is_wide_string<T>)
|
||||
return narrow(static_cast<T &&>(arg));
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
}
|
||||
};
|
||||
#if TOML_HAS_CHAR8
|
||||
template <> struct native_value_maker<std::string, char8_t *> : string_maker {};
|
||||
template <> struct native_value_maker<std::string, const char8_t *> : string_maker {};
|
||||
template <> struct native_value_maker<std::string, std::u8string> : string_maker {};
|
||||
template <>
|
||||
struct native_value_maker<std::string, std::u8string_view> : string_maker {};
|
||||
#endif // TOML_HAS_CHAR8
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
template <> struct native_value_maker<std::string, wchar_t *> : string_maker {};
|
||||
template <> struct native_value_maker<std::string, const wchar_t *> : string_maker {};
|
||||
template <> struct native_value_maker<std::string, std::wstring> : string_maker {};
|
||||
template <>
|
||||
struct native_value_maker<std::string, std::wstring_view> : string_maker {};
|
||||
#endif // TOML_WINDOWS_COMPAT
|
||||
|
||||
#endif // TOML_HAS_CHAR8 || TOML_WINDOWS_COMPAT
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] TOML_ATTR(const) inline optional<T> node_integer_cast(
|
||||
int64_t val) noexcept {
|
||||
static_assert(node_type_of<T> == node_type::integer);
|
||||
static_assert(!is_cvref<T>);
|
||||
|
||||
using traits = value_traits<T>;
|
||||
if constexpr (!traits::is_signed) {
|
||||
if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
|
||||
{
|
||||
using common_t = decltype(int64_t{} + T{});
|
||||
if (val < int64_t{} ||
|
||||
static_cast<common_t>(val) > static_cast<common_t>(traits::max))
|
||||
return {};
|
||||
} else {
|
||||
if (val < int64_t{})
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
if (val < traits::min || val > traits::max)
|
||||
return {};
|
||||
}
|
||||
return {static_cast<T>(val)};
|
||||
}
|
||||
}
|
||||
TOML_IMPL_NAMESPACE_END;
|
||||
/// \endcond
|
||||
|
||||
TOML_NAMESPACE_START {
|
||||
/// \brief A TOML value.
|
||||
///
|
||||
/// \tparam ValueType The value's native TOML data type. Can be one of:
|
||||
/// - std::string
|
||||
/// - toml::date
|
||||
/// - toml::time
|
||||
/// - toml::date_time
|
||||
/// - int64_t
|
||||
/// - double
|
||||
/// - bool
|
||||
template <typename ValueType> class TOML_API value final : public node {
|
||||
static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
|
||||
"A toml::value<> must model one of the native TOML value "
|
||||
"types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
|
||||
|
||||
private:
|
||||
friend class TOML_PARSER_TYPENAME;
|
||||
|
||||
/// \cond
|
||||
|
||||
template <typename T, typename U>
|
||||
[[nodiscard]] TOML_ALWAYS_INLINE
|
||||
TOML_ATTR(const) static auto as_value([[maybe_unused]] U *ptr) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return ptr;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ValueType val_;
|
||||
value_flags flags_ = value_flags::none;
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
void lh_ctor() noexcept { TOML_VALUE_CREATED; }
|
||||
|
||||
void lh_dtor() noexcept { TOML_VALUE_DESTROYED; }
|
||||
#endif
|
||||
|
||||
/// \endcond
|
||||
|
||||
public:
|
||||
/// \brief The value's underlying data type.
|
||||
using value_type = ValueType;
|
||||
|
||||
/// \brief A type alias for 'value arguments'.
|
||||
/// \details This differs according to the value's type argument:
|
||||
/// - ints, floats, booleans: `value_type`
|
||||
/// - strings: `string_view`
|
||||
/// - everything else: `const value_type&`
|
||||
using value_arg = std::conditional_t<
|
||||
std::is_same_v<value_type, std::string>, std::string_view,
|
||||
std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>,
|
||||
value_type, const value_type &>>;
|
||||
|
||||
/// \brief Constructs a toml value.
|
||||
///
|
||||
/// \tparam Args Constructor argument types.
|
||||
/// \param args Arguments to forward to the internal value's constructor.
|
||||
template <typename... Args>
|
||||
TOML_NODISCARD_CTOR explicit value(Args &&...args) noexcept(noexcept(
|
||||
value_type(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
|
||||
static_cast<Args &&>(args)...))))
|
||||
: val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
|
||||
static_cast<Args &&>(args)...)) {
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief Copy constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
value(const value &other) noexcept
|
||||
: node(other), val_{other.val_}, flags_{other.flags_} {
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief Move constructor.
|
||||
TOML_NODISCARD_CTOR
|
||||
value(value &&other) noexcept
|
||||
: node(std::move(other)), val_{std::move(other.val_)}, flags_{other.flags_} {
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
lh_ctor();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief Copy-assignment operator.
|
||||
value &operator=(const value &rhs) noexcept {
|
||||
node::operator=(rhs);
|
||||
val_ = rhs.val_;
|
||||
flags_ = rhs.flags_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Move-assignment operator.
|
||||
value &operator=(value &&rhs) noexcept {
|
||||
if (&rhs != this) {
|
||||
node::operator=(std::move(rhs));
|
||||
val_ = std::move(rhs.val_);
|
||||
flags_ = rhs.flags_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if TOML_LIFETIME_HOOKS
|
||||
~value() noexcept override { lh_dtor(); }
|
||||
#endif
|
||||
|
||||
/// \name Type checks
|
||||
/// @{
|
||||
|
||||
/// \brief Returns the value's node type identifier.
|
||||
///
|
||||
/// \returns One of:
|
||||
/// - node_type::string
|
||||
/// - node_type::integer
|
||||
/// - node_type::floating_point
|
||||
/// - node_type::boolean
|
||||
/// - node_type::date
|
||||
/// - node_type::time
|
||||
/// - node_type::date_time
|
||||
[[nodiscard]] node_type type() const noexcept override {
|
||||
return impl::node_type_of<value_type>;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_table() const noexcept override { return false; }
|
||||
[[nodiscard]] bool is_array() const noexcept override { return false; }
|
||||
[[nodiscard]] bool is_value() const noexcept override { return true; }
|
||||
|
||||
[[nodiscard]] bool is_string() const noexcept override {
|
||||
return std::is_same_v<value_type, std::string>;
|
||||
}
|
||||
[[nodiscard]] bool is_integer() const noexcept override {
|
||||
return std::is_same_v<value_type, int64_t>;
|
||||
}
|
||||
[[nodiscard]] bool is_floating_point() const noexcept override {
|
||||
return std::is_same_v<value_type, double>;
|
||||
}
|
||||
[[nodiscard]] bool is_number() const noexcept override {
|
||||
return impl::is_one_of<value_type, int64_t, double>;
|
||||
}
|
||||
[[nodiscard]] bool is_boolean() const noexcept override {
|
||||
return std::is_same_v<value_type, bool>;
|
||||
}
|
||||
[[nodiscard]] bool is_date() const noexcept override {
|
||||
return std::is_same_v<value_type, date>;
|
||||
}
|
||||
[[nodiscard]] bool is_time() const noexcept override {
|
||||
return std::is_same_v<value_type, time>;
|
||||
}
|
||||
[[nodiscard]] bool is_date_time() const noexcept override {
|
||||
return std::is_same_v<value_type, date_time>;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override {
|
||||
return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
|
||||
}
|
||||
[[nodiscard]] bool is_homogeneous(node_type ntype,
|
||||
toml::node *&first_nonmatch) noexcept override {
|
||||
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
|
||||
first_nonmatch = this;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[[nodiscard]] bool
|
||||
is_homogeneous(node_type ntype,
|
||||
const toml::node *&first_nonmatch) const noexcept override {
|
||||
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
|
||||
first_nonmatch = this;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename ElemType = void>
|
||||
[[nodiscard]] bool is_homogeneous() const noexcept {
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
static_assert(std::is_void_v<type> ||
|
||||
((impl::is_native<type> ||
|
||||
impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
|
||||
"The template type argument of value::is_homogeneous() must be "
|
||||
"void or one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
|
||||
|
||||
using type = impl::unwrap_node<ElemType>;
|
||||
if constexpr (std::is_void_v<type>)
|
||||
return true;
|
||||
else
|
||||
return impl::node_type_of<type> == impl::node_type_of<value_type>;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Type casts
|
||||
/// @{
|
||||
|
||||
[[nodiscard]] value<std::string> *as_string() noexcept override {
|
||||
return as_value<std::string>(this);
|
||||
}
|
||||
[[nodiscard]] value<int64_t> *as_integer() noexcept override {
|
||||
return as_value<int64_t>(this);
|
||||
}
|
||||
[[nodiscard]] value<double> *as_floating_point() noexcept override {
|
||||
return as_value<double>(this);
|
||||
}
|
||||
[[nodiscard]] value<bool> *as_boolean() noexcept override {
|
||||
return as_value<bool>(this);
|
||||
}
|
||||
[[nodiscard]] value<date> *as_date() noexcept override {
|
||||
return as_value<date>(this);
|
||||
}
|
||||
[[nodiscard]] value<time> *as_time() noexcept override {
|
||||
return as_value<time>(this);
|
||||
}
|
||||
[[nodiscard]] value<date_time> *as_date_time() noexcept override {
|
||||
return as_value<date_time>(this);
|
||||
}
|
||||
|
||||
[[nodiscard]] const value<std::string> *as_string() const noexcept override {
|
||||
return as_value<std::string>(this);
|
||||
}
|
||||
[[nodiscard]] const value<int64_t> *as_integer() const noexcept override {
|
||||
return as_value<int64_t>(this);
|
||||
}
|
||||
[[nodiscard]] const value<double> *as_floating_point() const noexcept override {
|
||||
return as_value<double>(this);
|
||||
}
|
||||
[[nodiscard]] const value<bool> *as_boolean() const noexcept override {
|
||||
return as_value<bool>(this);
|
||||
}
|
||||
[[nodiscard]] const value<date> *as_date() const noexcept override {
|
||||
return as_value<date>(this);
|
||||
}
|
||||
[[nodiscard]] const value<time> *as_time() const noexcept override {
|
||||
return as_value<time>(this);
|
||||
}
|
||||
[[nodiscard]] const value<date_time> *as_date_time() const noexcept override {
|
||||
return as_value<date_time>(this);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Value retrieval
|
||||
/// @{
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] value_type &get() &noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] value_type &&get() &&noexcept {
|
||||
return static_cast<value_type &&>(val_);
|
||||
}
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] const value_type &get() const &noexcept { return val_; }
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] value_type &operator*() &noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] value_type &&operator*() &&noexcept {
|
||||
return static_cast<value_type &&>(val_);
|
||||
}
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] const value_type &operator*() const &noexcept { return val_; }
|
||||
|
||||
/// \brief Returns a reference to the underlying value.
|
||||
[[nodiscard]] explicit operator value_type &() &noexcept { return val_; }
|
||||
/// \brief Returns a reference to the underlying value (rvalue overload).
|
||||
[[nodiscard]] explicit operator value_type &&() &&noexcept {
|
||||
return static_cast<value_type &&>(val_);
|
||||
}
|
||||
/// \brief Returns a reference to the underlying value (const overload).
|
||||
[[nodiscard]] explicit operator const value_type &() const &noexcept {
|
||||
return val_;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Metadata
|
||||
/// @{
|
||||
|
||||
/// \brief Returns the metadata flags associated with this value.
|
||||
[[nodiscard]] value_flags flags() const noexcept { return flags_; }
|
||||
|
||||
/// \brief Sets the metadata flags associated with this value.
|
||||
/// \returns A reference to the value object.
|
||||
value &flags(value_flags new_flags) noexcept {
|
||||
flags_ = new_flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Prints the value out to a stream as formatted TOML.
|
||||
template <typename Char, typename T>
|
||||
friend std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &lhs,
|
||||
const value<T> &rhs);
|
||||
// implemented in toml_default_formatter.h
|
||||
|
||||
/// \brief Value-assignment operator.
|
||||
value &operator=(value_arg rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, std::string>)
|
||||
val_.assign(rhs);
|
||||
else
|
||||
val_ = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T = value_type,
|
||||
typename = std::enable_if_t<std::is_same_v<T, std::string>>>
|
||||
value &operator=(std::string &&rhs) noexcept {
|
||||
val_ = std::move(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \name Equality
|
||||
/// @{
|
||||
|
||||
/// \brief Value equality operator.
|
||||
[[nodiscard]] friend bool operator==(const value &lhs, value_arg rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, double>) {
|
||||
const auto lhs_class = impl::fpclassify(lhs.val_);
|
||||
const auto rhs_class = impl::fpclassify(rhs);
|
||||
if (lhs_class == impl::fp_class::nan && rhs_class == impl::fp_class::nan)
|
||||
return true;
|
||||
if ((lhs_class == impl::fp_class::nan) != (rhs_class == impl::fp_class::nan))
|
||||
return false;
|
||||
}
|
||||
return lhs.val_ == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value &, value_arg, );
|
||||
|
||||
/// \brief Value less-than operator.
|
||||
[[nodiscard]] friend bool operator<(const value &lhs, value_arg rhs) noexcept {
|
||||
return lhs.val_ < rhs;
|
||||
}
|
||||
/// \brief Value less-than operator.
|
||||
[[nodiscard]] friend bool operator<(value_arg lhs, const value &rhs) noexcept {
|
||||
return lhs < rhs.val_;
|
||||
}
|
||||
/// \brief Value less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator<=(const value &lhs, value_arg rhs) noexcept {
|
||||
return lhs.val_ <= rhs;
|
||||
}
|
||||
/// \brief Value less-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator<=(value_arg lhs, const value &rhs) noexcept {
|
||||
return lhs <= rhs.val_;
|
||||
}
|
||||
|
||||
/// \brief Value greater-than operator.
|
||||
[[nodiscard]] friend bool operator>(const value &lhs, value_arg rhs) noexcept {
|
||||
return lhs.val_ > rhs;
|
||||
}
|
||||
/// \brief Value greater-than operator.
|
||||
[[nodiscard]] friend bool operator>(value_arg lhs, const value &rhs) noexcept {
|
||||
return lhs > rhs.val_;
|
||||
}
|
||||
/// \brief Value greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator>=(const value &lhs, value_arg rhs) noexcept {
|
||||
return lhs.val_ >= rhs;
|
||||
}
|
||||
/// \brief Value greater-than-or-equal-to operator.
|
||||
[[nodiscard]] friend bool operator>=(value_arg lhs, const value &rhs) noexcept {
|
||||
return lhs >= rhs.val_;
|
||||
}
|
||||
|
||||
/// \brief Equality operator.
|
||||
///
|
||||
/// \param lhs The LHS value.
|
||||
/// \param rhs The RHS value.
|
||||
///
|
||||
/// \returns True if the values were of the same type and contained the same
|
||||
/// value.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator==(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return lhs ==
|
||||
rhs.val_; // calls asymmetrical value-equality operator defined above
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Inequality operator.
|
||||
///
|
||||
/// \param lhs The LHS value.
|
||||
/// \param rhs The RHS value.
|
||||
///
|
||||
/// \returns True if the values were not of the same type, or did not contain
|
||||
/// the same value.
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator!=(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/// \brief Less-than operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns \conditional_return{Same value types}
|
||||
/// `lhs.get() < rhs.get()`
|
||||
/// \conditional_return{Different value types}
|
||||
/// `lhs.type() < rhs.type()`
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator<(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return lhs.val_ < rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<value_type> < impl::node_type_of<T>;
|
||||
}
|
||||
|
||||
/// \brief Less-than-or-equal-to operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns \conditional_return{Same value types}
|
||||
/// `lhs.get() <= rhs.get()`
|
||||
/// \conditional_return{Different value types}
|
||||
/// `lhs.type() <= rhs.type()`
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator<=(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return lhs.val_ <= rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<value_type> <= impl::node_type_of<T>;
|
||||
}
|
||||
|
||||
/// \brief Greater-than operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns \conditional_return{Same value types}
|
||||
/// `lhs.get() > rhs.get()`
|
||||
/// \conditional_return{Different value types}
|
||||
/// `lhs.type() > rhs.type()`
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator>(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return lhs.val_ > rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<value_type> > impl::node_type_of<T>;
|
||||
}
|
||||
|
||||
/// \brief Greater-than-or-equal-to operator.
|
||||
///
|
||||
/// \param lhs The LHS toml::value.
|
||||
/// \param rhs The RHS toml::value.
|
||||
///
|
||||
/// \returns \conditional_return{Same value types}
|
||||
/// `lhs.get() >= rhs.get()`
|
||||
/// \conditional_return{Different value types}
|
||||
/// `lhs.type() >= rhs.type()`
|
||||
template <typename T>
|
||||
[[nodiscard]] friend bool operator>=(const value &lhs,
|
||||
const value<T> &rhs) noexcept {
|
||||
if constexpr (std::is_same_v<value_type, T>)
|
||||
return lhs.val_ >= rhs.val_;
|
||||
else
|
||||
return impl::node_type_of<value_type> >= impl::node_type_of<T>;
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// \cond
|
||||
template <typename T>
|
||||
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
|
||||
|
||||
TOML_PUSH_WARNINGS;
|
||||
TOML_DISABLE_INIT_WARNINGS;
|
||||
TOML_DISABLE_SWITCH_WARNINGS;
|
||||
|
||||
#if !TOML_HEADER_ONLY
|
||||
extern template class TOML_API value<std::string>;
|
||||
extern template class TOML_API value<int64_t>;
|
||||
extern template class TOML_API value<double>;
|
||||
extern template class TOML_API value<bool>;
|
||||
extern template class TOML_API value<date>;
|
||||
extern template class TOML_API value<time>;
|
||||
extern template class TOML_API value<date_time>;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline decltype(auto) node::get_value_exact() const noexcept {
|
||||
using namespace impl;
|
||||
|
||||
static_assert(node_type_of<T> != node_type::none);
|
||||
static_assert(node_type_of<T> != node_type::table);
|
||||
static_assert(node_type_of<T> != node_type::array);
|
||||
static_assert(is_native<T> || can_represent_native<T>);
|
||||
static_assert(!is_cvref<T>);
|
||||
TOML_ASSERT(this->type() == node_type_of<T>);
|
||||
|
||||
if constexpr (node_type_of<T> == node_type::string) {
|
||||
const auto &str = *ref_cast<std::string>();
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
return str;
|
||||
else if constexpr (std::is_same_v<T, std::string_view>)
|
||||
return T{str};
|
||||
else if constexpr (std::is_same_v<T, const char *>)
|
||||
return str.c_str();
|
||||
|
||||
else if constexpr (std::is_same_v<T, std::wstring>) {
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
return widen(str);
|
||||
#else
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TOML_HAS_CHAR8
|
||||
|
||||
// char -> char8_t (potentially unsafe - the feature is 'experimental'!)
|
||||
else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
|
||||
return T(reinterpret_cast<const char8_t *>(str.c_str()), str.length());
|
||||
else if constexpr (std::is_same_v<T, const char8_t *>)
|
||||
return reinterpret_cast<const char8_t *>(str.c_str());
|
||||
else
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
|
||||
#endif
|
||||
} else
|
||||
return static_cast<T>(*ref_cast<native_type_of<T>>());
|
||||
}
|
||||
|
||||
template <typename T> inline optional<T> node::value_exact() const noexcept {
|
||||
using namespace impl;
|
||||
|
||||
static_assert(
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value_exact() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
|
||||
|
||||
static_assert(
|
||||
(is_native<T> || can_represent_native<T>)&&!is_cvref<T>,
|
||||
TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
|
||||
|
||||
// prevent additional compiler error spam when the static_assert fails by gating
|
||||
// behind if constexpr
|
||||
if constexpr ((is_native<T> || can_represent_native<T>)&&!is_cvref<T>) {
|
||||
if (type() == node_type_of<T>)
|
||||
return {this->get_value_exact<T>()};
|
||||
else
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> inline optional<T> node::value() const noexcept {
|
||||
using namespace impl;
|
||||
|
||||
static_assert(
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
|
||||
static_assert((is_native<T> || can_represent_native<T> ||
|
||||
can_partially_represent_native<T>)&&!is_cvref<T>,
|
||||
TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
|
||||
|
||||
// when asking for strings, dates, times and date_times there's no 'fuzzy'
|
||||
// conversion semantics to be mindful of so the exact retrieval is enough.
|
||||
if constexpr (is_natively_one_of<T, std::string, time, date, date_time>) {
|
||||
if (type() == node_type_of<T>)
|
||||
return {this->get_value_exact<T>()};
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// everything else requires a bit of logicking.
|
||||
else {
|
||||
switch (type()) {
|
||||
// int -> *
|
||||
case node_type::integer: {
|
||||
// int -> int
|
||||
if constexpr (is_natively_one_of<T, int64_t>) {
|
||||
if constexpr (is_native<T> || can_represent_native<T>)
|
||||
return static_cast<T>(*ref_cast<int64_t>());
|
||||
else
|
||||
return node_integer_cast<T>(*ref_cast<int64_t>());
|
||||
}
|
||||
|
||||
// int -> float
|
||||
else if constexpr (is_natively_one_of<T, double>) {
|
||||
const int64_t val = *ref_cast<int64_t>();
|
||||
if constexpr (std::numeric_limits<T>::digits < 64) {
|
||||
constexpr auto largest_whole_float =
|
||||
(int64_t{1} << std::numeric_limits<T>::digits);
|
||||
if (val < -largest_whole_float || val > largest_whole_float)
|
||||
return {};
|
||||
}
|
||||
return static_cast<T>(val);
|
||||
}
|
||||
|
||||
// int -> bool
|
||||
else if constexpr (is_natively_one_of<T, bool>)
|
||||
return static_cast<bool>(*ref_cast<int64_t>());
|
||||
|
||||
// int -> anything else
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// float -> *
|
||||
case node_type::floating_point: {
|
||||
// float -> float
|
||||
if constexpr (is_natively_one_of<T, double>) {
|
||||
if constexpr (is_native<T> || can_represent_native<T>)
|
||||
return {static_cast<T>(*ref_cast<double>())};
|
||||
else {
|
||||
const double val = *ref_cast<double>();
|
||||
if (impl::fpclassify(val) == fp_class::ok &&
|
||||
(val < (std::numeric_limits<T>::lowest)() ||
|
||||
val > (std::numeric_limits<T>::max)()))
|
||||
return {};
|
||||
return {static_cast<T>(val)};
|
||||
}
|
||||
}
|
||||
|
||||
// float -> int
|
||||
else if constexpr (is_natively_one_of<T, int64_t>) {
|
||||
const double val = *ref_cast<double>();
|
||||
if (impl::fpclassify(val) == fp_class::ok &&
|
||||
static_cast<double>(static_cast<int64_t>(val)) == val)
|
||||
return node_integer_cast<T>(static_cast<int64_t>(val));
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// float -> anything else
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
// bool -> *
|
||||
case node_type::boolean: {
|
||||
// bool -> bool
|
||||
if constexpr (is_natively_one_of<T, bool>)
|
||||
return {*ref_cast<bool>()};
|
||||
|
||||
// bool -> int
|
||||
else if constexpr (is_natively_one_of<T, int64_t>)
|
||||
return {static_cast<T>(*ref_cast<bool>())};
|
||||
|
||||
// bool -> anything else
|
||||
else
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// non-values, or 'exact' types covered above
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> inline auto node::value_or(T && default_value) const noexcept {
|
||||
using namespace impl;
|
||||
|
||||
static_assert(
|
||||
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
||||
"Retrieving values as wide-character strings with node::value_or() is only "
|
||||
"supported on Windows with TOML_WINDOWS_COMPAT enabled.");
|
||||
|
||||
if constexpr (is_wide_string<T>) {
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
|
||||
if (type() == node_type::string)
|
||||
return widen(*ref_cast<std::string>());
|
||||
return std::wstring{static_cast<T &&>(default_value)};
|
||||
|
||||
#else
|
||||
|
||||
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
||||
|
||||
#endif
|
||||
} else {
|
||||
using value_type = std::conditional_t<
|
||||
std::is_pointer_v<std::decay_t<T>>,
|
||||
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
|
||||
std::decay_t<T>>;
|
||||
using traits = value_traits<value_type>;
|
||||
|
||||
static_assert(
|
||||
traits::is_native || traits::can_represent_native ||
|
||||
traits::can_partially_represent_native,
|
||||
"The default value type of node::value_or() must be one of:" TOML_SA_LIST_NEW
|
||||
"A native TOML value type" TOML_SA_NATIVE_VALUE_TYPE_LIST
|
||||
|
||||
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a "
|
||||
"native TOML value type" TOML_SA_LIST_BEG "std::string"
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_SA_LIST_SEP "std::wstring"
|
||||
#endif
|
||||
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" TOML_SA_LIST_SEP
|
||||
"any floating-point type >= 64 bits" TOML_SA_LIST_END
|
||||
|
||||
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a "
|
||||
"native TOML value type" TOML_SA_LIST_BEG
|
||||
"any other integer type" TOML_SA_LIST_SEP
|
||||
"any floating-point type >= 32 bits" TOML_SA_LIST_END
|
||||
|
||||
TOML_SA_LIST_NXT "A compatible view type" TOML_SA_LIST_BEG
|
||||
"std::string_view"
|
||||
#if TOML_HAS_CHAR8
|
||||
TOML_SA_LIST_SEP "std::u8string_view"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_SA_LIST_SEP "std::wstring_view"
|
||||
#endif
|
||||
TOML_SA_LIST_SEP "const char*"
|
||||
#if TOML_HAS_CHAR8
|
||||
TOML_SA_LIST_SEP "const char8_t*"
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_SA_LIST_SEP "const wchar_t*"
|
||||
#endif
|
||||
TOML_SA_LIST_END);
|
||||
|
||||
// prevent additional compiler error spam when the static_assert fails by gating
|
||||
// behind if constexpr
|
||||
if constexpr (traits::is_native || traits::can_represent_native ||
|
||||
traits::can_partially_represent_native) {
|
||||
if constexpr (traits::is_native) {
|
||||
if (type() == node_type_of<value_type>)
|
||||
return *ref_cast<typename traits::native_type>();
|
||||
}
|
||||
if (auto val = this->value<value_type>())
|
||||
return *val;
|
||||
if constexpr (std::is_pointer_v<value_type>)
|
||||
return value_type{default_value};
|
||||
else
|
||||
return static_cast<T &&>(default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !TOML_HEADER_ONLY
|
||||
|
||||
#define TOML_EXTERN(name, T) \
|
||||
extern template TOML_API optional<T> node::name<T>() const noexcept
|
||||
TOML_EXTERN(value_exact, std::string_view);
|
||||
TOML_EXTERN(value_exact, std::string);
|
||||
TOML_EXTERN(value_exact, const char *);
|
||||
TOML_EXTERN(value_exact, int64_t);
|
||||
TOML_EXTERN(value_exact, double);
|
||||
TOML_EXTERN(value_exact, date);
|
||||
TOML_EXTERN(value_exact, time);
|
||||
TOML_EXTERN(value_exact, date_time);
|
||||
TOML_EXTERN(value_exact, bool);
|
||||
TOML_EXTERN(value, std::string_view);
|
||||
TOML_EXTERN(value, std::string);
|
||||
TOML_EXTERN(value, const char *);
|
||||
TOML_EXTERN(value, signed char);
|
||||
TOML_EXTERN(value, signed short);
|
||||
TOML_EXTERN(value, signed int);
|
||||
TOML_EXTERN(value, signed long);
|
||||
TOML_EXTERN(value, signed long long);
|
||||
TOML_EXTERN(value, unsigned char);
|
||||
TOML_EXTERN(value, unsigned short);
|
||||
TOML_EXTERN(value, unsigned int);
|
||||
TOML_EXTERN(value, unsigned long);
|
||||
TOML_EXTERN(value, unsigned long long);
|
||||
TOML_EXTERN(value, double);
|
||||
TOML_EXTERN(value, float);
|
||||
TOML_EXTERN(value, date);
|
||||
TOML_EXTERN(value, time);
|
||||
TOML_EXTERN(value, date_time);
|
||||
TOML_EXTERN(value, bool);
|
||||
#if TOML_HAS_CHAR8
|
||||
TOML_EXTERN(value_exact, std::u8string_view);
|
||||
TOML_EXTERN(value_exact, std::u8string);
|
||||
TOML_EXTERN(value_exact, const char8_t *);
|
||||
TOML_EXTERN(value, std::u8string_view);
|
||||
TOML_EXTERN(value, std::u8string);
|
||||
TOML_EXTERN(value, const char8_t *);
|
||||
#endif
|
||||
#if TOML_WINDOWS_COMPAT
|
||||
TOML_EXTERN(value_exact, std::wstring);
|
||||
TOML_EXTERN(value, std::wstring);
|
||||
#endif
|
||||
#undef TOML_EXTERN
|
||||
|
||||
#endif // !TOML_HEADER_ONLY
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_INIT_WARNINGS, TOML_DISABLE_SWITCH_WARNINGS
|
||||
/// \endcond
|
||||
}
|
||||
TOML_NAMESPACE_END;
|
||||
|
||||
TOML_POP_WARNINGS; // TOML_DISABLE_ARITHMETIC_WARNINGS
|
|
@ -0,0 +1,15 @@
|
|||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license
|
||||
// text.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TOML_LIB_MAJOR 2
|
||||
#define TOML_LIB_MINOR 5
|
||||
#define TOML_LIB_PATCH 0
|
||||
|
||||
#define TOML_LANG_MAJOR 1
|
||||
#define TOML_LANG_MINOR 0
|
||||
#define TOML_LANG_PATCH 0
|
Loading…
Reference in New Issue