mirror of
https://github.com/build-cpp/cmkr
synced 2026-06-08 13:22:55 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 25f015bc83 | |||
| fc674b4c6b | |||
| 433dbb0500 | |||
| 4772a2b683 | |||
| fb4931df1f | |||
| e96cd30217 | |||
| 2db8d1ee1d | |||
| 645737afd4 | |||
| 98c2e962c0 | |||
| 438feccf0f | |||
| 80cc29b8e1 | |||
| 1a62034a8a | |||
| c12472cd8f | |||
| 228553d43a | |||
| ffe08ae60c |
Generated
+1
-1
@@ -22,7 +22,7 @@ project(cmkr
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
0.2.45
|
||||
0.2.46
|
||||
DESCRIPTION
|
||||
"CMakeLists generator from TOML"
|
||||
)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ cmkr-include = false
|
||||
|
||||
[project]
|
||||
name = "cmkr"
|
||||
version = "0.2.45"
|
||||
version = "0.2.46"
|
||||
description = "CMakeLists generator from TOML"
|
||||
languages = ["CXX"]
|
||||
include-after = [
|
||||
|
||||
+8
-1
@@ -2,7 +2,7 @@ include_guard()
|
||||
|
||||
# Change these defaults to point to your infrastructure if desired
|
||||
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
|
||||
set(CMKR_TAG "v0.2.45" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_TAG "v0.2.46" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
|
||||
|
||||
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
|
||||
@@ -61,6 +61,13 @@ endif()
|
||||
if(DEFINED ENV{CMKR_CACHE})
|
||||
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
|
||||
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||
if(CMKR_DIRECTORY_PREFIX MATCHES "^~")
|
||||
if(WIN32)
|
||||
string(REGEX REPLACE "^~" "$ENV{USERPROFILE}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||
elseif(UNIX)
|
||||
string(REGEX REPLACE "^~" "$ENV{HOME}" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
|
||||
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
# Automatically generated from tests/objective-c/cmake.toml - DO NOT EDIT
|
||||
layout: default
|
||||
title: Objective-C
|
||||
permalink: /examples/objective-c
|
||||
parent: Examples
|
||||
nav_order: 11
|
||||
---
|
||||
|
||||
# Objective-C
|
||||
|
||||
Add Objective-C sources on Apple platforms:
|
||||
|
||||
```toml
|
||||
[project]
|
||||
name = "objective-c"
|
||||
description = "Objective-C"
|
||||
languages = ["C"]
|
||||
apple.languages = ["OBJC"]
|
||||
|
||||
[target.hello]
|
||||
type = "executable"
|
||||
sources = ["src/main.c"]
|
||||
apple.sources = ["src/apple.m"]
|
||||
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
|
||||
```
|
||||
|
||||
|
||||
|
||||
<sup><sub>This page was automatically generated from [tests/objective-c/cmake.toml](https://github.com/build-cpp/cmkr/tree/main/tests/objective-c/cmake.toml).</sub></sup>
|
||||
@@ -20,11 +20,11 @@ description = "Target templates"
|
||||
type = "executable"
|
||||
sources = ["src/templates.cpp"]
|
||||
compile-definitions = ["IS_APP"]
|
||||
|
||||
# Unlike interface targets you can also inherit properties
|
||||
[template.app.properties]
|
||||
CXX_STANDARD = "11"
|
||||
CXX_STANDARD_REQUIRED = true
|
||||
properties = {
|
||||
CXX_STANDARD = "11",
|
||||
CXX_STANDARD_REQUIRED = true,
|
||||
}
|
||||
|
||||
[target.app-a]
|
||||
type = "app"
|
||||
|
||||
@@ -105,6 +105,8 @@ struct Target {
|
||||
ConditionVector precompile_headers;
|
||||
ConditionVector private_precompile_headers;
|
||||
|
||||
ConditionVector dependencies;
|
||||
|
||||
std::string condition;
|
||||
std::string alias;
|
||||
Condition<tsl::ordered_map<std::string, std::string>> properties;
|
||||
@@ -192,7 +194,7 @@ struct Project {
|
||||
std::string project_name;
|
||||
std::string project_version;
|
||||
std::string project_description;
|
||||
std::vector<std::string> project_languages;
|
||||
ConditionVector project_languages;
|
||||
bool project_allow_unknown_languages = false;
|
||||
MsvcRuntimeType project_msvc_runtime = msvc_last;
|
||||
Condition<std::string> cmake_before;
|
||||
|
||||
+66
-43
@@ -54,6 +54,18 @@ static std::string format(const char *format, const tsl::ordered_map<std::string
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string quoted(const std::string &str) {
|
||||
return "\"" + str + "\"";
|
||||
}
|
||||
|
||||
static std::string space_error_check(const std::string &str) {
|
||||
auto pos = str.find_last_of(' ');
|
||||
if (pos != std::string::npos)
|
||||
return quoted(str) + " <------ !space(s)";
|
||||
else
|
||||
return quoted(str);
|
||||
}
|
||||
|
||||
static std::vector<fs::path> expand_cmake_path(const fs::path &source_path, const fs::path &toml_dir, bool is_root_project) {
|
||||
auto is_subdir = [](fs::path p, const fs::path &root) {
|
||||
while (true) {
|
||||
@@ -713,16 +725,41 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
|
||||
parser::Project project(parent_project, path, false);
|
||||
|
||||
for (const auto &lang : project.project_languages) {
|
||||
if (known_languages.find(lang) == known_languages.end()) {
|
||||
if (project.project_allow_unknown_languages) {
|
||||
printf("[warning] Unknown language '%s' specified\n", lang.c_str());
|
||||
} else {
|
||||
throw std::runtime_error("Unknown language '" + lang + "' specified");
|
||||
}
|
||||
tsl::ordered_set<std::string> flat_project_languages;
|
||||
for (const auto &itr : project.project_languages) {
|
||||
for (const auto &language : itr.second) {
|
||||
flat_project_languages.insert(language);
|
||||
}
|
||||
}
|
||||
|
||||
// Reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24340#note_1304703
|
||||
flat_project_languages.insert("RC");
|
||||
|
||||
// All acceptable extensions based off our given languages.
|
||||
tsl::ordered_set<std::string> project_extensions;
|
||||
for (const auto &language : flat_project_languages) {
|
||||
auto itr = known_languages.find(language);
|
||||
if (itr == known_languages.end()) {
|
||||
if (project.project_allow_unknown_languages) {
|
||||
printf("[warning] Unknown language '%s' specified\n", language.c_str());
|
||||
} else {
|
||||
throw std::runtime_error("Unknown language '" + language + "' specified");
|
||||
}
|
||||
} else {
|
||||
project_extensions.insert(itr->second.begin(), itr->second.end());
|
||||
}
|
||||
}
|
||||
|
||||
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
|
||||
for (const auto &source : sources) {
|
||||
auto extension = fs::path(source).extension().string();
|
||||
if (project_extensions.count(extension) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Generator gen(project, path);
|
||||
|
||||
// Helper lambdas for more convenient CMake generation
|
||||
@@ -900,17 +937,29 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
gen.conditional_cmake(project.cmake_before);
|
||||
|
||||
if (!project.project_name.empty()) {
|
||||
auto languages = std::make_pair("LANGUAGES", project.project_languages);
|
||||
auto languages = std::make_pair("LANGUAGES", project.project_languages[""]);
|
||||
auto version = std::make_pair("VERSION", project.project_version);
|
||||
auto description = std::make_pair("DESCRIPTION", project.project_description);
|
||||
cmd("project")(project.project_name, languages, version, description).endl();
|
||||
cmd("project")(project.project_name, languages, version, description);
|
||||
|
||||
for (const auto &language : project.project_languages) {
|
||||
for (const auto &language : project.project_languages[""]) {
|
||||
if (language == "CSharp") {
|
||||
cmd("include")("CSharpUtilities").endl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gen.handle_condition(project.project_languages, [&cmd](const std::string &condition, const std::vector<std::string> &languages) {
|
||||
if (!condition.empty()) {
|
||||
cmd("enable_language")(languages).endl();
|
||||
for (const auto &language : languages) {
|
||||
if (language == "CSharp") {
|
||||
cmd("include")("CSharpUtilities").endl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
gen.conditional_includes(project.include_after);
|
||||
@@ -1126,34 +1175,6 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
gen.conditional_cmake(subdir.cmake_after);
|
||||
}
|
||||
|
||||
// The implicit default is ["C", "CXX"], so make sure this list isn't
|
||||
// empty or projects without languages explicitly defined will error.
|
||||
auto project_languages = project.project_languages;
|
||||
if (project_languages.empty())
|
||||
project_languages = {"C", "CXX"};
|
||||
|
||||
// Reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24340#note_1304703
|
||||
project_languages.push_back("RC");
|
||||
|
||||
// All acceptable extensions based off our given languages.
|
||||
tsl::ordered_set<std::string> project_extensions;
|
||||
for (const auto &language : project_languages) {
|
||||
auto itr = known_languages.find(language);
|
||||
if (itr != known_languages.end()) {
|
||||
project_extensions.insert(itr->second.begin(), itr->second.end());
|
||||
}
|
||||
}
|
||||
|
||||
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
|
||||
for (const auto &source : sources) {
|
||||
auto extension = fs::path(source).extension().string();
|
||||
if (project_extensions.count(extension) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!project.targets.empty()) {
|
||||
auto project_root = project.root();
|
||||
for (size_t i = 0; i < project.targets.size(); i++) {
|
||||
@@ -1294,7 +1315,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
continue;
|
||||
const auto &source_path = fs::path(path) / source;
|
||||
if (!fs::exists(source_path)) {
|
||||
throw_target_error("Source file not found: " + source);
|
||||
throw_target_error("Source file not found: " + space_error_check(source));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1404,7 +1425,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
});
|
||||
};
|
||||
|
||||
auto link_libraries = [&](const parser::ConditionVector &cargs, const std::string &scope) {
|
||||
auto link_cmd = [&](const char *command, const parser::ConditionVector &cargs, const std::string &scope) {
|
||||
gen.handle_condition(cargs, [&](const std::string &, const std::vector<std::string> &args) {
|
||||
std::vector<std::string> targs;
|
||||
for (const std::string &arg : args) {
|
||||
@@ -1420,7 +1441,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
targs.push_back(arg);
|
||||
}
|
||||
}
|
||||
cmd("target_link_libraries")(target.name, scope, targs);
|
||||
cmd(command)(target.name, scope, targs);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1440,14 +1461,16 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
|
||||
target_cmd("target_link_directories", t.link_directories, target_scope);
|
||||
target_cmd("target_link_directories", t.private_link_directories, "PRIVATE");
|
||||
|
||||
link_libraries(t.link_libraries, target_scope);
|
||||
link_libraries(t.private_link_libraries, "PRIVATE");
|
||||
link_cmd("target_link_libraries", t.link_libraries, target_scope);
|
||||
link_cmd("target_link_libraries", t.private_link_libraries, "PRIVATE");
|
||||
|
||||
target_cmd("target_link_options", t.link_options, target_scope);
|
||||
target_cmd("target_link_options", t.private_link_options, "PRIVATE");
|
||||
|
||||
target_cmd("target_precompile_headers", t.precompile_headers, target_scope);
|
||||
target_cmd("target_precompile_headers", t.private_precompile_headers, "PRIVATE");
|
||||
|
||||
link_cmd("add_dependencies", t.dependencies, "");
|
||||
};
|
||||
|
||||
if (tmplate != nullptr) {
|
||||
|
||||
@@ -301,6 +301,11 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
|
||||
project.required("name", project_name);
|
||||
project.optional("version", project_version);
|
||||
project.optional("description", project_description);
|
||||
|
||||
// The implicit default is ["C", "CXX"], so make sure this list isn't
|
||||
// empty or projects without languages explicitly defined will error.
|
||||
project_languages[""] = {"C", "CXX"};
|
||||
|
||||
project.optional("languages", project_languages);
|
||||
project.optional("allow-unknown-languages", project_allow_unknown_languages);
|
||||
project.optional("cmake-before", cmake_before);
|
||||
@@ -690,6 +695,8 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
|
||||
t.optional("precompile-headers", target.precompile_headers);
|
||||
t.optional("private-precompile-headers", target.private_precompile_headers);
|
||||
|
||||
t.optional("dependencies", target.dependencies);
|
||||
|
||||
Condition<std::string> msvc_runtime;
|
||||
t.optional("msvc-runtime", msvc_runtime);
|
||||
for (const auto &cond_itr : msvc_runtime) {
|
||||
|
||||
Generated
+9
@@ -122,3 +122,12 @@ if(WIN32) # windows
|
||||
)
|
||||
|
||||
endif()
|
||||
add_test(
|
||||
NAME
|
||||
objective-c
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/objective-c"
|
||||
COMMAND
|
||||
"$<TARGET_FILE:cmkr>"
|
||||
build
|
||||
)
|
||||
|
||||
@@ -65,3 +65,9 @@ name = "relative-paths"
|
||||
working-directory = "relative-paths"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
arguments = ["build"]
|
||||
|
||||
[[test]]
|
||||
name = "objective-c"
|
||||
working-directory = "objective-c"
|
||||
command = "$<TARGET_FILE:cmkr>"
|
||||
arguments = ["build"]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Add Objective-C sources on Apple platforms:
|
||||
|
||||
[project]
|
||||
name = "objective-c"
|
||||
description = "Objective-C"
|
||||
languages = ["C"]
|
||||
apple.languages = ["OBJC"]
|
||||
|
||||
[target.hello]
|
||||
type = "executable"
|
||||
sources = ["src/main.c"]
|
||||
apple.sources = ["src/apple.m"]
|
||||
apple.link-libraries = ["$<LINK_LIBRARY:FRAMEWORK,Foundation>"]
|
||||
@@ -0,0 +1,7 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
void platform_specific() {
|
||||
NSFileHandle *stdout = [NSFileHandle fileHandleWithStandardOutput];
|
||||
NSString *message = @"Hello from Objective-C!\n";
|
||||
[stdout writeData:[message dataUsingEncoding:NSUTF8StringEncoding] error:nil];
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
void platform_specific();
|
||||
#else
|
||||
void platform_specific() {
|
||||
puts("This is not an Apple platform.");
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
platform_specific();
|
||||
return 0;
|
||||
}
|
||||
@@ -8,11 +8,11 @@ description = "Target templates"
|
||||
type = "executable"
|
||||
sources = ["src/templates.cpp"]
|
||||
compile-definitions = ["IS_APP"]
|
||||
|
||||
# Unlike interface targets you can also inherit properties
|
||||
[template.app.properties]
|
||||
CXX_STANDARD = "11"
|
||||
CXX_STANDARD_REQUIRED = true
|
||||
properties = {
|
||||
CXX_STANDARD = "11",
|
||||
CXX_STANDARD_REQUIRED = true,
|
||||
}
|
||||
|
||||
[target.app-a]
|
||||
type = "app"
|
||||
|
||||
+4
-3
@@ -9,9 +9,10 @@ add_library(ordered_map INTERFACE)
|
||||
target_include_directories(ordered_map INTERFACE ordered-map-1.0.0/include)
|
||||
target_compile_definitions(ordered_map INTERFACE NOMINMAX)
|
||||
|
||||
# https://github.com/ToruNiina/toml11 (MIT)
|
||||
add_library(toml11 INTERFACE)
|
||||
target_include_directories(toml11 INTERFACE toml11-3.6.0)
|
||||
# https://github.com/ToruNiina/toml11 (MIT)
|
||||
add_library(toml11 INTERFACE)
|
||||
target_include_directories(toml11 INTERFACE toml11-3.8.1)
|
||||
target_compile_definitions(toml11 INTERFACE TOML11_USE_UNRELEASED_TOML_FEATURES)
|
||||
|
||||
# https://github.com/mpark/variant (BSL-1.0)
|
||||
add_library(mpark_variant INTERFACE)
|
||||
|
||||
@@ -25,21 +25,14 @@
|
||||
#ifndef TOML_FOR_MODERN_CPP
|
||||
#define TOML_FOR_MODERN_CPP
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
#endif
|
||||
|
||||
#if __cplusplus < 201103L && _MSC_VER < 1900
|
||||
# error "toml11 requires C++11 or later."
|
||||
#endif
|
||||
|
||||
#define TOML11_VERSION_MAJOR 3
|
||||
#define TOML11_VERSION_MINOR 5
|
||||
#define TOML11_VERSION_PATCH 0
|
||||
#define TOML11_VERSION_MINOR 8
|
||||
#define TOML11_VERSION_PATCH 1
|
||||
|
||||
#include "toml/parser.hpp"
|
||||
#include "toml/literal.hpp"
|
||||
#include "toml/serializer.hpp"
|
||||
#include "toml/get.hpp"
|
||||
#include "toml/macros.hpp"
|
||||
|
||||
#endif// TOML_FOR_MODERN_CPP
|
||||
+45
@@ -17,11 +17,41 @@ namespace color_ansi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline int colorize_index()
|
||||
{
|
||||
static const int index = std::ios_base::xalloc();
|
||||
return index;
|
||||
}
|
||||
|
||||
// Control color mode globally
|
||||
class color_mode
|
||||
{
|
||||
public:
|
||||
inline void enable()
|
||||
{
|
||||
should_color_ = true;
|
||||
}
|
||||
inline void disable()
|
||||
{
|
||||
should_color_ = false;
|
||||
}
|
||||
|
||||
inline bool should_color() const
|
||||
{
|
||||
return should_color_;
|
||||
}
|
||||
|
||||
static color_mode& status()
|
||||
{
|
||||
static color_mode status_;
|
||||
return status_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool should_color_ = false;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
inline std::ostream& colorize(std::ostream& os)
|
||||
@@ -55,6 +85,21 @@ inline std::ostream& cyan (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
||||
inline std::ostream& white (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
||||
|
||||
inline void enable()
|
||||
{
|
||||
return detail::color_mode::status().enable();
|
||||
}
|
||||
inline void disable()
|
||||
{
|
||||
return detail::color_mode::status().disable();
|
||||
}
|
||||
|
||||
inline bool should_color()
|
||||
{
|
||||
return detail::color_mode::status().should_color();
|
||||
}
|
||||
|
||||
} // color_ansi
|
||||
|
||||
// ANSI escape sequence is the only and default colorization method currently
|
||||
Vendored
+2
-2
@@ -29,7 +29,7 @@ namespace detail
|
||||
// to output character as an error message.
|
||||
inline std::string show_char(const char c)
|
||||
{
|
||||
// It supress an error that occurs only in Debug mode of MSVC++ on Windows.
|
||||
// It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
|
||||
// I'm not completely sure but they check the value of char to be in the
|
||||
// range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
|
||||
// has negative value (if char has sign). So here it re-interprets c as
|
||||
@@ -154,7 +154,7 @@ struct sequence<Head, Tail...>
|
||||
invoke(location& loc)
|
||||
{
|
||||
const auto first = loc.iter();
|
||||
const auto rslt = Head::invoke(loc);
|
||||
auto rslt = Head::invoke(loc);
|
||||
if(rslt.is_err())
|
||||
{
|
||||
loc.reset(first);
|
||||
+26
-7
@@ -4,11 +4,18 @@
|
||||
#define TOML11_COMMENTS_HPP
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
|
||||
#else
|
||||
# define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
|
||||
#endif
|
||||
|
||||
// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
|
||||
// Those two are a container that have the same interface as `std::vector<std::string>`
|
||||
// but bahaves in the opposite way. `preserve_comments` is just the same as
|
||||
@@ -339,7 +346,7 @@ operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::differ
|
||||
//
|
||||
// Why this is chose as the default type is because the last version (2.x.y)
|
||||
// does not contain any comments in a value. To minimize the impact on the
|
||||
// efficiency, this is choosed as a default.
|
||||
// efficiency, this is chosen as a default.
|
||||
//
|
||||
// To reduce the memory footprint, later we can try empty base optimization (EBO).
|
||||
struct discard_comments
|
||||
@@ -418,14 +425,14 @@ struct discard_comments
|
||||
// empty, so accessing through operator[], front/back, data causes address
|
||||
// error.
|
||||
|
||||
reference operator[](const size_type) noexcept {return *data();}
|
||||
const_reference operator[](const size_type) const noexcept {return *data();}
|
||||
reference operator[](const size_type) noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
|
||||
reference at(const size_type) {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
|
||||
reference front() noexcept {return *data();}
|
||||
const_reference front() const noexcept {return *data();}
|
||||
reference back() noexcept {return *data();}
|
||||
const_reference back() const noexcept {return *data();}
|
||||
reference front() noexcept {never_call("toml::discard_comment::front");}
|
||||
const_reference front() const noexcept {never_call("toml::discard_comment::front");}
|
||||
reference back() noexcept {never_call("toml::discard_comment::back");}
|
||||
const_reference back() const noexcept {never_call("toml::discard_comment::back");}
|
||||
|
||||
pointer data() noexcept {return nullptr;}
|
||||
const_pointer data() const noexcept {return nullptr;}
|
||||
@@ -443,6 +450,18 @@ struct discard_comments
|
||||
const_reverse_iterator rend() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
|
||||
const_reverse_iterator crend() const noexcept {return const_iterator{};}
|
||||
|
||||
private:
|
||||
|
||||
[[noreturn]] static void never_call(const char *const this_function)
|
||||
{
|
||||
#ifdef __has_builtin
|
||||
# if __has_builtin(__builtin_unreachable)
|
||||
__builtin_unreachable();
|
||||
# endif
|
||||
#endif
|
||||
throw std::logic_error{this_function};
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
|
||||
+32
-32
@@ -21,22 +21,7 @@ namespace toml
|
||||
namespace detail
|
||||
{
|
||||
// TODO: find more sophisticated way to handle this
|
||||
#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::localtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_MSC_VER)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
@@ -51,6 +36,21 @@ inline std::tm gmtime_s(const std::time_t* src)
|
||||
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::localtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#else // fallback. not threadsafe
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
@@ -85,9 +85,9 @@ enum class month_t : std::uint8_t
|
||||
|
||||
struct local_date
|
||||
{
|
||||
std::int16_t year; // A.D. (like, 2018)
|
||||
std::uint8_t month; // [0, 11]
|
||||
std::uint8_t day; // [1, 31]
|
||||
std::int16_t year{}; // A.D. (like, 2018)
|
||||
std::uint8_t month{}; // [0, 11]
|
||||
std::uint8_t day{}; // [1, 31]
|
||||
|
||||
local_date(int y, month_t m, int d)
|
||||
: year (static_cast<std::int16_t>(y)),
|
||||
@@ -181,12 +181,12 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
|
||||
|
||||
struct local_time
|
||||
{
|
||||
std::uint8_t hour; // [0, 23]
|
||||
std::uint8_t minute; // [0, 59]
|
||||
std::uint8_t second; // [0, 60]
|
||||
std::uint16_t millisecond; // [0, 999]
|
||||
std::uint16_t microsecond; // [0, 999]
|
||||
std::uint16_t nanosecond; // [0, 999]
|
||||
std::uint8_t hour{}; // [0, 23]
|
||||
std::uint8_t minute{}; // [0, 59]
|
||||
std::uint8_t second{}; // [0, 60]
|
||||
std::uint16_t millisecond{}; // [0, 999]
|
||||
std::uint16_t microsecond{}; // [0, 999]
|
||||
std::uint16_t nanosecond{}; // [0, 999]
|
||||
|
||||
local_time(int h, int m, int s,
|
||||
int ms = 0, int us = 0, int ns = 0)
|
||||
@@ -297,8 +297,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
|
||||
|
||||
struct time_offset
|
||||
{
|
||||
std::int8_t hour; // [-12, 12]
|
||||
std::int8_t minute; // [-59, 59]
|
||||
std::int8_t hour{}; // [-12, 12]
|
||||
std::int8_t minute{}; // [-59, 59]
|
||||
|
||||
time_offset(int h, int m)
|
||||
: hour (static_cast<std::int8_t>(h)),
|
||||
@@ -364,8 +364,8 @@ operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
|
||||
|
||||
struct local_datetime
|
||||
{
|
||||
local_date date;
|
||||
local_time time;
|
||||
local_date date{};
|
||||
local_time time{};
|
||||
|
||||
local_datetime(local_date d, local_time t): date(d), time(t) {}
|
||||
|
||||
@@ -478,9 +478,9 @@ operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
|
||||
|
||||
struct offset_datetime
|
||||
{
|
||||
local_date date;
|
||||
local_time time;
|
||||
time_offset offset;
|
||||
local_date date{};
|
||||
local_time time{};
|
||||
time_offset offset{};
|
||||
|
||||
offset_datetime(local_date d, local_time t, time_offset o)
|
||||
: date(d), time(t), offset(o)
|
||||
+19
-1
@@ -2,14 +2,32 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_EXCEPTION_HPP
|
||||
#define TOML11_EXCEPTION_HPP
|
||||
#include <stdexcept>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "source_location.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
struct file_io_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
file_io_error(int errnum, const std::string& msg, const std::string& fname)
|
||||
: std::runtime_error(msg + " \"" + fname + "\": errno = " + std::to_string(errnum)),
|
||||
errno_(errnum)
|
||||
{}
|
||||
|
||||
int get_errno() const noexcept {return errno_;}
|
||||
|
||||
private:
|
||||
int errno_;
|
||||
};
|
||||
|
||||
struct exception : public std::exception
|
||||
{
|
||||
public:
|
||||
-1
@@ -2,7 +2,6 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_FROM_HPP
|
||||
#define TOML11_FROM_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
+101
-13
@@ -140,7 +140,7 @@ get(basic_value<C, M, V>&& v)
|
||||
// ============================================================================
|
||||
// std::string_view
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
|
||||
@@ -215,6 +215,7 @@ template<typename T, typename C,
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
||||
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||
detail::negation< // not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
@@ -255,19 +256,37 @@ get(const basic_value<C, M, V>&);
|
||||
|
||||
// toml::from<T>::from_toml(v)
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
std::size_t S = sizeof(::toml::from<T>)>
|
||||
T get(const basic_value<C, M, V>&);
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(const basic_value<C, M, V>&);
|
||||
|
||||
// T(const toml::value&) and T is not toml::basic_value
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(basic_value<C, M, V>&);
|
||||
|
||||
// T(const toml::value&) and T is not toml::basic_value,
|
||||
// and it does not have `from<T>` nor `from_toml`.
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::negation<detail::is_basic_value<T>>,
|
||||
std::is_constructible<T, const basic_value<C, M, V>&>
|
||||
std::is_constructible<T, const basic_value<C, M, V>&>,
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||
detail::negation<detail::has_specialized_from<T>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>&);
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::negation<detail::is_basic_value<T>>,
|
||||
std::is_constructible<T, basic_value<C, M, V>&>,
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>,
|
||||
detail::negation<detail::has_specialized_from<T>>
|
||||
>::value, T>
|
||||
get(basic_value<C, M, V>&);
|
||||
|
||||
// ============================================================================
|
||||
// array-like types; most likely STL container, like std::vector, etc.
|
||||
|
||||
@@ -321,6 +340,7 @@ template<typename T, typename C,
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
||||
detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
|
||||
detail::negation< // T is not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
@@ -338,8 +358,10 @@ get(const basic_value<C, M, V>& v)
|
||||
{v.location(), "here"}
|
||||
}));
|
||||
}
|
||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
||||
[](const value& x){return ::toml::get<value_type>(x);});
|
||||
for(std::size_t i=0; i<ar.size(); ++i)
|
||||
{
|
||||
container[i] = ::toml::get<value_type>(ar[i]);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -438,9 +460,16 @@ get(const basic_value<C, M, V>& v)
|
||||
return ud;
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V,
|
||||
std::size_t>
|
||||
T get(const basic_value<C, M, V>& v)
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
return ::toml::from<T>::from_toml(v);
|
||||
}
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::has_specialized_from<T>::value, T>
|
||||
get(basic_value<C, M, V>& v)
|
||||
{
|
||||
return ::toml::from<T>::from_toml(v);
|
||||
}
|
||||
@@ -448,14 +477,29 @@ T get(const basic_value<C, M, V>& v)
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::negation<detail::is_basic_value<T>>,
|
||||
std::is_constructible<T, const basic_value<C, M, V>&>
|
||||
detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
||||
std::is_constructible<T, const basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
return T(v);
|
||||
}
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::negation<detail::is_basic_value<T>>, // T is not a toml::value
|
||||
std::is_constructible<T, basic_value<C, M, V>&>, // T is constructible from toml::value
|
||||
detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
|
||||
detail::negation<detail::has_specialized_from<T>> // and T does not have toml::from<T>{};
|
||||
>::value, T>
|
||||
get(basic_value<C, M, V>& v)
|
||||
{
|
||||
return T(v);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// find
|
||||
|
||||
@@ -1031,6 +1075,50 @@ find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
|
||||
return get_or(tab.at(ky), std::forward<T>(opt));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// recursive find-or with type deduction (find_or(value, keys, opt))
|
||||
|
||||
template<typename Value, typename ... Ks,
|
||||
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||
// here we need to add SFINAE in the template parameter to avoid
|
||||
// infinite recursion in type deduction on gcc
|
||||
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||
-> decltype(find_or(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||
{
|
||||
if(!v.is_table())
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
auto&& tab = std::forward<Value>(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// recursive find_or with explicit type specialization, find_or<int>(value, keys...)
|
||||
|
||||
template<typename T, typename Value, typename ... Ks,
|
||||
typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
|
||||
// here we need to add SFINAE in the template parameter to avoid
|
||||
// infinite recursion in type deduction on gcc
|
||||
auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
|
||||
-> decltype(find_or<T>(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
|
||||
{
|
||||
if(!v.is_table())
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
auto&& tab = std::forward<Value>(v).as_table();
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
return detail::last_one(std::forward<Ks>(keys)...);
|
||||
}
|
||||
return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// expect
|
||||
|
||||
-1
@@ -2,7 +2,6 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_INTO_HPP
|
||||
#define TOML11_INTO_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
+39
-15
@@ -5,7 +5,6 @@
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
|
||||
#include "combinator.hpp"
|
||||
|
||||
@@ -119,8 +118,8 @@ using lex_local_time = lex_partial_time;
|
||||
// ===========================================================================
|
||||
|
||||
using lex_quotation_mark = character<'"'>;
|
||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab)
|
||||
in_range<0x0a, 0x1F>, // is allowed
|
||||
using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x22>, character<0x5C>,
|
||||
character<0x7F>>>;
|
||||
|
||||
@@ -133,6 +132,9 @@ using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
|
||||
character<'b'>, character<'f'>,
|
||||
character<'n'>, character<'r'>,
|
||||
character<'t'>,
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
character<'e'>, // ESC (0x1B)
|
||||
#endif
|
||||
lex_escape_unicode_short,
|
||||
lex_escape_unicode_long
|
||||
>;
|
||||
@@ -166,7 +168,7 @@ using lex_basic_string = sequence<lex_quotation_mark,
|
||||
// | ^- expected newline, but got '"'.
|
||||
// ```
|
||||
// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
|
||||
// splitted into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
|
||||
// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
|
||||
// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
|
||||
// In parse_ml_basic_string() function, the trailing `"`s will be attached to
|
||||
// the string body.
|
||||
@@ -178,8 +180,8 @@ using lex_ml_basic_string_close = sequence<
|
||||
maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
|
||||
>;
|
||||
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09
|
||||
in_range<0x0a, 0x1F>, // is tab
|
||||
using lex_ml_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 is tab
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x5C>, // backslash
|
||||
character<0x7F>, // DEL
|
||||
lex_ml_basic_string_delim>>;
|
||||
@@ -196,8 +198,8 @@ using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
|
||||
lex_ml_basic_body,
|
||||
lex_ml_basic_string_close>;
|
||||
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x19>, character<0x27>>>;
|
||||
using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
|
||||
character<0x7F>, character<0x27>>>;
|
||||
using lex_apostrophe = character<'\''>;
|
||||
using lex_literal_string = sequence<lex_apostrophe,
|
||||
repeat<lex_literal_char, unlimited>,
|
||||
@@ -212,7 +214,7 @@ using lex_ml_literal_string_close = sequence<
|
||||
>;
|
||||
|
||||
using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
|
||||
in_range<0x10, 0x1F>,
|
||||
in_range<0x0A, 0x1F>,
|
||||
character<0x7F>,
|
||||
lex_ml_literal_string_delim>>;
|
||||
using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
|
||||
@@ -225,12 +227,6 @@ using lex_string = either<lex_ml_basic_string, lex_basic_string,
|
||||
lex_ml_literal_string, lex_literal_string>;
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
using lex_comment_start_symbol = character<'#'>;
|
||||
using lex_non_eol = either<character<'\t'>, exclude<in_range<0x00, 0x19>>>;
|
||||
using lex_comment = sequence<lex_comment_start_symbol,
|
||||
repeat<lex_non_eol, unlimited>>;
|
||||
|
||||
using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
|
||||
|
||||
using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
|
||||
@@ -265,6 +261,34 @@ using lex_array_table = sequence<lex_array_table_open,
|
||||
maybe<lex_ws>,
|
||||
lex_array_table_close>;
|
||||
|
||||
using lex_utf8_1byte = in_range<0x00, 0x7F>;
|
||||
using lex_utf8_2byte = sequence<
|
||||
in_range<'\xC2', '\xDF'>,
|
||||
in_range<'\x80', '\xBF'>
|
||||
>;
|
||||
using lex_utf8_3byte = sequence<either<
|
||||
sequence<character<'\xE0'>, in_range<'\xA0', '\xBF'>>,
|
||||
sequence<in_range<'\xE1', '\xEC'>, in_range<'\x80', '\xBF'>>,
|
||||
sequence<character<'\xED'>, in_range<'\x80', '\x9F'>>,
|
||||
sequence<in_range<'\xEE', '\xEF'>, in_range<'\x80', '\xBF'>>
|
||||
>, in_range<'\x80', '\xBF'>>;
|
||||
using lex_utf8_4byte = sequence<either<
|
||||
sequence<character<'\xF0'>, in_range<'\x90', '\xBF'>>,
|
||||
sequence<in_range<'\xF1', '\xF3'>, in_range<'\x80', '\xBF'>>,
|
||||
sequence<character<'\xF4'>, in_range<'\x80', '\x8F'>>
|
||||
>, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>;
|
||||
using lex_utf8_code = either<
|
||||
lex_utf8_1byte,
|
||||
lex_utf8_2byte,
|
||||
lex_utf8_3byte,
|
||||
lex_utf8_4byte
|
||||
>;
|
||||
|
||||
using lex_comment_start_symbol = character<'#'>;
|
||||
using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
|
||||
using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
|
||||
lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
#endif // TOML_LEXER_HPP
|
||||
+11
-5
@@ -12,8 +12,11 @@ inline namespace toml_literals
|
||||
{
|
||||
|
||||
// implementation
|
||||
inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
||||
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
literal_internal_impl(::toml::detail::location loc)
|
||||
{
|
||||
using value_type = ::toml::basic_value<
|
||||
TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
|
||||
// if there are some comments or empty lines, skip them.
|
||||
using skip_line = ::toml::detail::repeat<toml::detail::sequence<
|
||||
::toml::detail::maybe<::toml::detail::lex_ws>,
|
||||
@@ -50,7 +53,7 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
||||
// If it is neither a table-key or a array-of-table-key, it may be a value.
|
||||
if(!is_table_key && !is_aots_key)
|
||||
{
|
||||
if(auto data = ::toml::detail::parse_value<::toml::value>(loc))
|
||||
if(auto data = ::toml::detail::parse_value<value_type>(loc, 0))
|
||||
{
|
||||
return data.unwrap();
|
||||
}
|
||||
@@ -67,7 +70,7 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
||||
// It is a valid toml file.
|
||||
// It should be parsed as if we parse a file with this content.
|
||||
|
||||
if(auto data = ::toml::detail::parse_toml_file<::toml::value>(loc))
|
||||
if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
|
||||
{
|
||||
return data.unwrap();
|
||||
}
|
||||
@@ -78,11 +81,13 @@ inline ::toml::value literal_internal_impl(::toml::detail::location loc)
|
||||
|
||||
}
|
||||
|
||||
inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
operator"" _toml(const char* str, std::size_t len)
|
||||
{
|
||||
::toml::detail::location loc(
|
||||
std::string("TOML literal encoded in a C++ code"),
|
||||
std::vector<char>(str, str + len));
|
||||
// literal length does not include the null character at the end.
|
||||
return literal_internal_impl(std::move(loc));
|
||||
}
|
||||
|
||||
@@ -91,7 +96,8 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
// value of u8"" literal has been changed from char to char8_t and char8_t is
|
||||
// NOT compatible to char
|
||||
inline ::toml::value operator"" _toml(const char8_t* str, std::size_t len)
|
||||
inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
|
||||
operator"" _toml(const char8_t* str, std::size_t len)
|
||||
{
|
||||
::toml::detail::location loc(
|
||||
std::string("TOML literal encoded in a C++ code"),
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
#ifndef TOML11_MACROS_HPP
|
||||
#define TOML11_MACROS_HPP
|
||||
|
||||
#define TOML11_STRINGIZE_AUX(x) #x
|
||||
#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x)
|
||||
|
||||
#define TOML11_CONCATENATE_AUX(x, y) x##y
|
||||
#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y)
|
||||
|
||||
// ============================================================================
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||
|
||||
#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_ARGS_SIZE
|
||||
|
||||
#define TOML11_INDEX_RSEQ() \
|
||||
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
|
||||
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define TOML11_ARGS_SIZE_IMPL(\
|
||||
ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, ARG10, \
|
||||
ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
|
||||
ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
|
||||
ARG31, ARG32, N, ...) N
|
||||
#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
|
||||
#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_FOR_EACH_VA_ARGS
|
||||
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1 ) FUNCTOR(ARG1)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
|
||||
#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
|
||||
|
||||
#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
|
||||
TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
|
||||
|
||||
// use it in the following way.
|
||||
// ```cpp
|
||||
// namespace foo
|
||||
// {
|
||||
// struct Foo
|
||||
// {
|
||||
// std::string s;
|
||||
// double d;
|
||||
// int i;
|
||||
// };
|
||||
// } // foo
|
||||
//
|
||||
// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
|
||||
// ```
|
||||
// And then you can use `toml::find<foo::Foo>(file, "foo");`
|
||||
//
|
||||
#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
|
||||
obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
|
||||
|
||||
#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
|
||||
v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
|
||||
|
||||
#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
|
||||
namespace toml { \
|
||||
template<> \
|
||||
struct from<NAME> \
|
||||
{ \
|
||||
template<typename C, template<typename ...> class T, \
|
||||
template<typename ...> class A> \
|
||||
static NAME from_toml(const basic_value<C, T, A>& v) \
|
||||
{ \
|
||||
NAME obj; \
|
||||
TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
|
||||
return obj; \
|
||||
} \
|
||||
}; \
|
||||
template<> \
|
||||
struct into<NAME> \
|
||||
{ \
|
||||
static value into_toml(const NAME& obj) \
|
||||
{ \
|
||||
::toml::value v = ::toml::table{}; \
|
||||
TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
|
||||
return v; \
|
||||
} \
|
||||
}; \
|
||||
} /* toml */
|
||||
|
||||
#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
|
||||
|
||||
#endif// TOML11_MACROS_HPP
|
||||
+624
-117
File diff suppressed because it is too large
Load Diff
+13
-14
@@ -70,16 +70,16 @@ struct region_base
|
||||
struct location final : public region_base
|
||||
{
|
||||
using const_iterator = typename std::vector<char>::const_iterator;
|
||||
using difference_type = typename const_iterator::difference_type;
|
||||
using difference_type = typename std::iterator_traits<const_iterator>::difference_type;
|
||||
using source_ptr = std::shared_ptr<const std::vector<char>>;
|
||||
|
||||
location(std::string name, std::vector<char> cont)
|
||||
location(std::string source_name, std::vector<char> cont)
|
||||
: source_(std::make_shared<std::vector<char>>(std::move(cont))),
|
||||
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
||||
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||
{}
|
||||
location(std::string name, const std::string& cont)
|
||||
location(std::string source_name, const std::string& cont)
|
||||
: source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
|
||||
line_number_(1), source_name_(std::move(name)), iter_(source_->cbegin())
|
||||
line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
|
||||
{}
|
||||
|
||||
location(const location&) = default;
|
||||
@@ -92,7 +92,7 @@ struct location final : public region_base
|
||||
char front() const noexcept override {return *iter_;}
|
||||
|
||||
// this const prohibits codes like `++(loc.iter())`.
|
||||
const const_iterator iter() const noexcept {return iter_;}
|
||||
std::add_const<const_iterator>::type iter() const noexcept {return iter_;}
|
||||
|
||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||
const_iterator end() const noexcept {return source_->cend();}
|
||||
@@ -227,8 +227,7 @@ struct region final : public region_base
|
||||
region& operator+=(const region& other)
|
||||
{
|
||||
// different regions cannot be concatenated
|
||||
assert(this->begin() == other.begin() && this->end() == other.end() &&
|
||||
this->last_ == other.first_);
|
||||
assert(this->source_ == other.source_ && this->last_ == other.first_);
|
||||
|
||||
this->last_ = other.last_;
|
||||
return *this;
|
||||
@@ -343,9 +342,9 @@ struct region final : public region_base
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), iter);
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
auto s = make_string(std::next(comment_found), iter);
|
||||
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||
com.push_back(std::move(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -396,9 +395,9 @@ struct region final : public region_base
|
||||
}))
|
||||
{
|
||||
// unwrap the first '#' by std::next.
|
||||
auto str = make_string(std::next(comment_found), this->line_end());
|
||||
if(str.back() == '\r') {str.pop_back();}
|
||||
com.push_back(std::move(str));
|
||||
auto s = make_string(std::next(comment_found), this->line_end());
|
||||
if(!s.empty() && s.back() == '\r') {s.pop_back();}
|
||||
com.push_back(std::move(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+342
-136
@@ -2,10 +2,19 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_SERIALIZER_HPP
|
||||
#define TOML11_SERIALIZER_HPP
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <locale.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <xlocale.h>
|
||||
#elif defined(__linux__)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "lexer.hpp"
|
||||
#include "value.hpp"
|
||||
|
||||
@@ -26,19 +35,24 @@ namespace toml
|
||||
// a `"` and escaping some special character is boring.
|
||||
template<typename charT, typename traits, typename Alloc>
|
||||
std::basic_string<charT, traits, Alloc>
|
||||
format_key(const std::basic_string<charT, traits, Alloc>& key)
|
||||
format_key(const std::basic_string<charT, traits, Alloc>& k)
|
||||
{
|
||||
if(k.empty())
|
||||
{
|
||||
return std::string("\"\"");
|
||||
}
|
||||
|
||||
// check the key can be a bare (unquoted) key
|
||||
detail::location loc(key, std::vector<char>(key.begin(), key.end()));
|
||||
detail::location loc(k, std::vector<char>(k.begin(), k.end()));
|
||||
detail::lex_unquoted_key::invoke(loc);
|
||||
if(loc.iter() == loc.end())
|
||||
{
|
||||
return key; // all the tokens are consumed. the key is unquoted-key.
|
||||
return k; // all the tokens are consumed. the key is unquoted-key.
|
||||
}
|
||||
|
||||
//if it includes special characters, then format it in a "quoted" key.
|
||||
std::basic_string<charT, traits, Alloc> serialized("\"");
|
||||
for(const char c : key)
|
||||
for(const char c : k)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
@@ -49,7 +63,19 @@ format_key(const std::basic_string<charT, traits, Alloc>& key)
|
||||
case '\f': {serialized += "\\f"; break;}
|
||||
case '\n': {serialized += "\\n"; break;}
|
||||
case '\r': {serialized += "\\r"; break;}
|
||||
default : {serialized += c; break;}
|
||||
default: {
|
||||
if (c >= 0x00 && c < 0x20)
|
||||
{
|
||||
std::array<char, 7> buf;
|
||||
std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast<int>(c));
|
||||
serialized += buf.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
serialized += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
serialized += "\"";
|
||||
@@ -60,9 +86,12 @@ template<typename charT, typename traits, typename Alloc>
|
||||
std::basic_string<charT, traits, Alloc>
|
||||
format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
|
||||
{
|
||||
std::basic_string<charT, traits, Alloc> serialized;
|
||||
if(keys.empty()) {return serialized;}
|
||||
if(keys.empty())
|
||||
{
|
||||
return std::string("\"\"");
|
||||
}
|
||||
|
||||
std::basic_string<charT, traits, Alloc> serialized;
|
||||
for(const auto& ky : keys)
|
||||
{
|
||||
serialized += format_key(ky);
|
||||
@@ -97,8 +126,10 @@ struct serializer
|
||||
const int float_prec = std::numeric_limits<toml::floating>::max_digits10,
|
||||
const bool can_be_inlined = false,
|
||||
const bool no_comment = false,
|
||||
std::vector<toml::key> ks = {})
|
||||
std::vector<toml::key> ks = {},
|
||||
const bool value_has_comment = false)
|
||||
: can_be_inlined_(can_be_inlined), no_comment_(no_comment),
|
||||
value_has_comment_(value_has_comment && !no_comment),
|
||||
float_prec_(float_prec), width_(w), keys_(std::move(ks))
|
||||
{}
|
||||
~serializer() = default;
|
||||
@@ -109,18 +140,93 @@ struct serializer
|
||||
}
|
||||
std::string operator()(const integer_type i) const
|
||||
{
|
||||
return std::to_string(i);
|
||||
#if defined(_WIN32)
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||
locale_t original_locale(0);
|
||||
if(c_locale != locale_t(0))
|
||||
{
|
||||
original_locale = uselocale(c_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto str = std::to_string(i);
|
||||
|
||||
#if defined(_WIN32)
|
||||
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
if(original_locale != locale_t(0))
|
||||
{
|
||||
uselocale(original_locale);
|
||||
}
|
||||
#endif
|
||||
return str;
|
||||
}
|
||||
std::string operator()(const floating_type f) const
|
||||
{
|
||||
if(std::isnan(f))
|
||||
{
|
||||
if(std::signbit(f))
|
||||
{
|
||||
return std::string("-nan");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("nan");
|
||||
}
|
||||
}
|
||||
else if(!std::isfinite(f))
|
||||
{
|
||||
if(std::signbit(f))
|
||||
{
|
||||
return std::string("-inf");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string("inf");
|
||||
}
|
||||
}
|
||||
|
||||
// set locale to "C".
|
||||
// To make it thread-local, we use OS-specific features.
|
||||
// If we set process-global locale, it can break other thread that also
|
||||
// outputs something simultaneously.
|
||||
#if defined(_WIN32)
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
|
||||
locale_t original_locale(0);
|
||||
if(c_locale != locale_t(0))
|
||||
{
|
||||
original_locale = uselocale(c_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto fmt = "%.*g";
|
||||
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
|
||||
// +1 for null character(\0)
|
||||
std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
|
||||
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
|
||||
|
||||
// restore the original locale
|
||||
#if defined(_WIN32)
|
||||
setlocale(LC_NUMERIC, original_locale.c_str());
|
||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
|
||||
if(original_locale != locale_t(0))
|
||||
{
|
||||
uselocale(original_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string token(buf.begin(), std::prev(buf.end()));
|
||||
if(token.back() == '.') // 1. => 1.0
|
||||
if(!token.empty() && token.back() == '.') // 1. => 1.0
|
||||
{
|
||||
token += '0';
|
||||
}
|
||||
@@ -144,8 +250,9 @@ struct serializer
|
||||
{
|
||||
if(s.kind == string_t::basic)
|
||||
{
|
||||
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend())
|
||||
if((std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
||||
std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend()) &&
|
||||
this->width_ != (std::numeric_limits<std::size_t>::max)())
|
||||
{
|
||||
// if linefeed or double-quote is contained,
|
||||
// make it multiline basic string.
|
||||
@@ -244,92 +351,18 @@ struct serializer
|
||||
|
||||
std::string operator()(const array_type& v) const
|
||||
{
|
||||
if(!v.empty() && v.front().is_table())// v is an array of tables
|
||||
{
|
||||
// if it's not inlined, we need to add `[[table.key]]`.
|
||||
// but if it can be inlined,
|
||||
// ```
|
||||
// table.key = [
|
||||
// {...},
|
||||
// # comment
|
||||
// {...},
|
||||
// ]
|
||||
// ```
|
||||
if(this->can_be_inlined_)
|
||||
{
|
||||
std::string token;
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += format_key(keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
bool failed = false;
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
// if an element of the table has a comment, the table
|
||||
// cannot be inlined.
|
||||
if(this->has_comment_inside(item.as_table()))
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
if(!no_comment_)
|
||||
{
|
||||
for(const auto& c : item.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
const auto t = this->make_inline_table(item.as_table());
|
||||
|
||||
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
||||
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
token += t;
|
||||
token += ",\n";
|
||||
}
|
||||
if(!failed)
|
||||
{
|
||||
token += "]\n";
|
||||
return token;
|
||||
}
|
||||
// if failed, serialize them as [[array.of.tables]].
|
||||
}
|
||||
|
||||
std::string token;
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(!no_comment_)
|
||||
{
|
||||
for(const auto& c : item.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
token += "[[";
|
||||
token += format_keys(keys_);
|
||||
token += "]]\n";
|
||||
token += this->make_multiline_table(item.as_table());
|
||||
}
|
||||
return token;
|
||||
}
|
||||
if(v.empty())
|
||||
{
|
||||
return std::string("[]");
|
||||
}
|
||||
if(this->is_array_of_tables(v))
|
||||
{
|
||||
return make_array_of_tables(v);
|
||||
}
|
||||
|
||||
// not an array of tables. normal array.
|
||||
// first, try to make it inline if none of the elements have a comment.
|
||||
if(!this->has_comment_inside(v))
|
||||
if( ! this->has_comment_inside(v))
|
||||
{
|
||||
const auto inl = this->make_inline_array(v);
|
||||
if(inl.size() < this->width_ &&
|
||||
@@ -350,7 +383,7 @@ struct serializer
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(!item.comments().empty() && !no_comment_)
|
||||
if( ! item.comments().empty() && !no_comment_)
|
||||
{
|
||||
// if comment exists, the element must be the only element in the line.
|
||||
// e.g. the following is not allowed.
|
||||
@@ -376,15 +409,25 @@ struct serializer
|
||||
token += '\n';
|
||||
}
|
||||
token += toml::visit(*this, item);
|
||||
if(token.back() == '\n') {token.pop_back();}
|
||||
if(!token.empty() && token.back() == '\n') {token.pop_back();}
|
||||
token += ",\n";
|
||||
continue;
|
||||
}
|
||||
std::string next_elem;
|
||||
next_elem += toml::visit(*this, item);
|
||||
if(item.is_table())
|
||||
{
|
||||
serializer ser(*this);
|
||||
ser.can_be_inlined_ = true;
|
||||
ser.width_ = (std::numeric_limits<std::size_t>::max)();
|
||||
next_elem += toml::visit(ser, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
next_elem += toml::visit(*this, item);
|
||||
}
|
||||
|
||||
// comma before newline.
|
||||
if(next_elem.back() == '\n') {next_elem.pop_back();}
|
||||
if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();}
|
||||
|
||||
// if current line does not exceeds the width limit, continue.
|
||||
if(current_line.size() + next_elem.size() + 1 < this->width_)
|
||||
@@ -411,7 +454,10 @@ struct serializer
|
||||
}
|
||||
if(!current_line.empty())
|
||||
{
|
||||
if(current_line.back() != '\n') {current_line += '\n';}
|
||||
if(!current_line.empty() && current_line.back() != '\n')
|
||||
{
|
||||
current_line += '\n';
|
||||
}
|
||||
token += current_line;
|
||||
}
|
||||
token += "]\n";
|
||||
@@ -467,7 +513,19 @@ struct serializer
|
||||
case '\f': {retval += "\\f"; break;}
|
||||
case '\n': {retval += "\\n"; break;}
|
||||
case '\r': {retval += "\\r"; break;}
|
||||
default : {retval += c; break;}
|
||||
default :
|
||||
{
|
||||
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||
{
|
||||
retval += "\\u00";
|
||||
retval += char(48 + (c / 16));
|
||||
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
retval += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
@@ -501,7 +559,21 @@ struct serializer
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {retval += *i; break;}
|
||||
default :
|
||||
{
|
||||
const auto c = *i;
|
||||
if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
|
||||
{
|
||||
retval += "\\u00";
|
||||
retval += char(48 + (c / 16));
|
||||
retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
retval += c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
|
||||
@@ -557,8 +629,10 @@ struct serializer
|
||||
for(const auto& item : v)
|
||||
{
|
||||
if(is_first) {is_first = false;} else {token += ',';}
|
||||
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
||||
this->float_prec_, true), item);
|
||||
token += visit(serializer(
|
||||
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !item.comments().empty()), item);
|
||||
}
|
||||
token += ']';
|
||||
return token;
|
||||
@@ -577,8 +651,10 @@ struct serializer
|
||||
if(is_first) {is_first = false;} else {token += ',';}
|
||||
token += format_key(kv.first);
|
||||
token += '=';
|
||||
token += visit(serializer((std::numeric_limits<std::size_t>::max)(),
|
||||
this->float_prec_, true), kv.second);
|
||||
token += visit(serializer(
|
||||
(std::numeric_limits<std::size_t>::max)(), this->float_prec_,
|
||||
/* inlined */ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
}
|
||||
token += '}';
|
||||
return token;
|
||||
@@ -588,8 +664,16 @@ struct serializer
|
||||
{
|
||||
std::string token;
|
||||
|
||||
// print non-table stuff first. because after printing [foo.bar], the
|
||||
// remaining non-table values will be assigned into [foo.bar], not [foo]
|
||||
// print non-table elements first.
|
||||
// ```toml
|
||||
// [foo] # a table we're writing now here
|
||||
// key = "value" # <- non-table element, "key"
|
||||
// # ...
|
||||
// [foo.bar] # <- table element, "bar"
|
||||
// ```
|
||||
// because after printing [foo.bar], the remaining non-table values will
|
||||
// be assigned into [foo.bar], not [foo]. Those values should be printed
|
||||
// earlier.
|
||||
for(const auto& kv : v)
|
||||
{
|
||||
if(kv.second.is_table() || is_array_of_tables(kv.second))
|
||||
@@ -597,21 +681,16 @@ struct serializer
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!kv.second.comments().empty() && !no_comment_)
|
||||
{
|
||||
for(const auto& c : kv.second.comments())
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
token += write_comments(kv.second);
|
||||
|
||||
const auto key_and_sep = format_key(kv.first) + " = ";
|
||||
const auto residual_width = (this->width_ > key_and_sep.size()) ?
|
||||
this->width_ - key_and_sep.size() : 0;
|
||||
token += key_and_sep;
|
||||
token += visit(serializer(residual_width, this->float_prec_, true),
|
||||
kv.second);
|
||||
token += visit(serializer(residual_width, this->float_prec_,
|
||||
/*can be inlined*/ true, /*no comment*/ false, /*keys*/ {},
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
|
||||
if(token.back() != '\n')
|
||||
{
|
||||
token += '\n';
|
||||
@@ -637,45 +716,172 @@ struct serializer
|
||||
ks.push_back(kv.first);
|
||||
|
||||
auto tmp = visit(serializer(this->width_, this->float_prec_,
|
||||
!multiline_table_printed, this->no_comment_, ks),
|
||||
kv.second);
|
||||
!multiline_table_printed, this->no_comment_, ks,
|
||||
/*has_comment*/ !kv.second.comments().empty()), kv.second);
|
||||
|
||||
// If it is the first time to print a multi-line table, it would be
|
||||
// helpful to separate normal key-value pair and subtables by a
|
||||
// newline.
|
||||
// (this checks if the current key-value pair contains newlines.
|
||||
// but it is not perfect because multi-line string can also contain
|
||||
// a newline. in such a case, an empty line will be written) TODO
|
||||
if((!multiline_table_printed) &&
|
||||
std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
|
||||
{
|
||||
multiline_table_printed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// still inline tables only.
|
||||
tmp += '\n';
|
||||
}
|
||||
token += '\n'; // separate key-value pairs and subtables
|
||||
|
||||
if(!kv.second.comments().empty() && !no_comment_)
|
||||
{
|
||||
for(const auto& c : kv.second.comments())
|
||||
token += write_comments(kv.second);
|
||||
token += tmp;
|
||||
|
||||
// care about recursive tables (all tables in each level prints
|
||||
// newline and there will be a full of newlines)
|
||||
if(tmp.substr(tmp.size() - 2, 2) != "\n\n" &&
|
||||
tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" )
|
||||
{
|
||||
token += '#';
|
||||
token += c;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
token += tmp;
|
||||
else
|
||||
{
|
||||
token += write_comments(kv.second);
|
||||
token += tmp;
|
||||
token += '\n';
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string make_array_of_tables(const array_type& v) const
|
||||
{
|
||||
// if it's not inlined, we need to add `[[table.key]]`.
|
||||
// but if it can be inlined, we can format it as the following.
|
||||
// ```
|
||||
// table.key = [
|
||||
// {...},
|
||||
// # comment
|
||||
// {...},
|
||||
// ]
|
||||
// ```
|
||||
// This function checks if inlinization is possible or not, and then
|
||||
// format the array-of-tables in a proper way.
|
||||
//
|
||||
// Note about comments:
|
||||
//
|
||||
// If the array itself has a comment (value_has_comment_ == true), we
|
||||
// should try to make it inline.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// array = [
|
||||
// # comment about table element
|
||||
// {of = "table"}
|
||||
// ]
|
||||
// ```
|
||||
// If it is formatted as a multiline table, the two comments becomes
|
||||
// indistinguishable.
|
||||
// ```toml
|
||||
// # comment about array
|
||||
// # comment about table element
|
||||
// [[array]]
|
||||
// of = "table"
|
||||
// ```
|
||||
// So we need to try to make it inline, and it force-inlines regardless
|
||||
// of the line width limit.
|
||||
// It may fail if the element of a table has comment. In that case,
|
||||
// the array-of-tables will be formatted as a multiline table.
|
||||
if(this->can_be_inlined_ || this->value_has_comment_)
|
||||
{
|
||||
std::string token;
|
||||
if(!keys_.empty())
|
||||
{
|
||||
token += format_key(keys_.back());
|
||||
token += " = ";
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
token += "[\n";
|
||||
for(const auto& item : v)
|
||||
{
|
||||
// if an element of the table has a comment, the table
|
||||
// cannot be inlined.
|
||||
if(this->has_comment_inside(item.as_table()))
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
// write comments for the table itself
|
||||
token += write_comments(item);
|
||||
|
||||
const auto t = this->make_inline_table(item.as_table());
|
||||
|
||||
if(t.size() + 1 > width_ || // +1 for the last comma {...},
|
||||
std::find(t.cbegin(), t.cend(), '\n') != t.cend())
|
||||
{
|
||||
// if the value itself has a comment, ignore the line width limit
|
||||
if( ! this->value_has_comment_)
|
||||
{
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
token += t;
|
||||
token += ",\n";
|
||||
}
|
||||
|
||||
if( ! failed)
|
||||
{
|
||||
token += "]\n";
|
||||
return token;
|
||||
}
|
||||
// if failed, serialize them as [[array.of.tables]].
|
||||
}
|
||||
|
||||
std::string token;
|
||||
for(const auto& item : v)
|
||||
{
|
||||
token += write_comments(item);
|
||||
token += "[[";
|
||||
token += format_keys(keys_);
|
||||
token += "]]\n";
|
||||
token += this->make_multiline_table(item.as_table());
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string write_comments(const value_type& v) const
|
||||
{
|
||||
std::string retval;
|
||||
if(this->no_comment_) {return retval;}
|
||||
|
||||
for(const auto& c : v.comments())
|
||||
{
|
||||
retval += '#';
|
||||
retval += c;
|
||||
retval += '\n';
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool is_array_of_tables(const value_type& v) const
|
||||
{
|
||||
if(!v.is_array()) {return false;}
|
||||
const auto& a = v.as_array();
|
||||
return !a.empty() && a.front().is_table();
|
||||
if(!v.is_array() || v.as_array().empty()) {return false;}
|
||||
return is_array_of_tables(v.as_array());
|
||||
}
|
||||
bool is_array_of_tables(const array_type& v) const
|
||||
{
|
||||
// Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to
|
||||
// check all the element in an array to check if the array is an array
|
||||
// of tables.
|
||||
return std::all_of(v.begin(), v.end(), [](const value_type& elem) {
|
||||
return elem.is_table();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool can_be_inlined_;
|
||||
bool no_comment_;
|
||||
bool value_has_comment_;
|
||||
int float_prec_;
|
||||
std::size_t width_;
|
||||
std::vector<toml::key> keys_;
|
||||
@@ -699,7 +905,7 @@ format(const basic_value<C, M, V>& v, std::size_t w = 80u,
|
||||
oss << v.comments();
|
||||
oss << '\n'; // to split the file comment from the first element
|
||||
}
|
||||
const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
|
||||
const auto serialized = visit(serializer<value_type>(w, fprec, false, no_comment), v);
|
||||
oss << serialized;
|
||||
return oss.str();
|
||||
}
|
||||
@@ -720,7 +926,7 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
nocomment(std::basic_ostream<charT, traits>& os)
|
||||
{
|
||||
// by default, it is zero. and by defalut, it shows comments.
|
||||
// by default, it is zero. and by default, it shows comments.
|
||||
os.iword(detail::comment_index(os)) = 1;
|
||||
return os;
|
||||
}
|
||||
@@ -729,7 +935,7 @@ template<typename charT, typename traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
showcomment(std::basic_ostream<charT, traits>& os)
|
||||
{
|
||||
// by default, it is zero. and by defalut, it shows comments.
|
||||
// by default, it is zero. and by default, it shows comments.
|
||||
os.iword(detail::comment_index(os)) = 0;
|
||||
return os;
|
||||
}
|
||||
@@ -746,7 +952,7 @@ operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
|
||||
const int fprec = static_cast<int>(os.precision());
|
||||
os.width(0);
|
||||
|
||||
// by defualt, iword is initialized byl 0. And by default, toml11 outputs
|
||||
// by default, iword is initialized by 0. And by default, toml11 outputs
|
||||
// comments. So `0` means showcomment. 1 means nocommnet.
|
||||
const bool no_comment = (1 == os.iword(detail::comment_index(os)));
|
||||
|
||||
+10
-3
@@ -3,6 +3,7 @@
|
||||
#ifndef TOML11_SOURCE_LOCATION_HPP
|
||||
#define TOML11_SOURCE_LOCATION_HPP
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
||||
#include "region.hpp"
|
||||
|
||||
@@ -124,7 +125,7 @@ inline std::string format_underline(const std::string& message,
|
||||
|
||||
std::ostringstream retval;
|
||||
|
||||
if(colorize)
|
||||
if(color::should_color() || colorize)
|
||||
{
|
||||
retval << color::colorize; // turn on ANSI color
|
||||
}
|
||||
@@ -136,12 +137,18 @@ inline std::string format_underline(const std::string& message,
|
||||
// if it is "[error]", it removes that part from the message shown.
|
||||
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
||||
{
|
||||
retval << color::bold << color::red << "[error]" << color::reset
|
||||
retval
|
||||
#ifndef TOML11_NO_ERROR_PREFIX
|
||||
<< color::bold << color::red << "[error]" << color::reset
|
||||
#endif
|
||||
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
retval << color::bold << color::red << "[error] " << color::reset
|
||||
retval
|
||||
#ifndef TOML11_NO_ERROR_PREFIX
|
||||
<< color::bold << color::red << "[error] " << color::reset
|
||||
#endif
|
||||
<< color::bold << message << color::reset << '\n';
|
||||
}
|
||||
|
||||
+6
-2
@@ -2,13 +2,17 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_STRING_HPP
|
||||
#define TOML11_STRING_HPP
|
||||
|
||||
#include "version.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#define TOML11_USING_STRING_VIEW 1
|
||||
#include <string_view>
|
||||
#endif
|
||||
#endif
|
||||
@@ -53,7 +57,7 @@ struct string
|
||||
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
||||
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||
|
||||
+36
-8
@@ -2,6 +2,11 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TRAITS_HPP
|
||||
#define TOML11_TRAITS_HPP
|
||||
|
||||
#include "from.hpp"
|
||||
#include "into.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
@@ -9,7 +14,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
#endif // has_include(<string_view>)
|
||||
@@ -84,6 +89,22 @@ struct has_into_toml_method_impl
|
||||
static std::false_type check(...);
|
||||
};
|
||||
|
||||
struct has_specialized_from_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
template<typename T, std::size_t S = sizeof(::toml::from<T>)>
|
||||
static std::true_type check(::toml::from<T>*);
|
||||
};
|
||||
struct has_specialized_into_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
static std::true_type check(::toml::from<T>*);
|
||||
};
|
||||
|
||||
|
||||
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
||||
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
||||
#ifdef __INTEL_COMPILER
|
||||
@@ -114,6 +135,11 @@ template<typename T>
|
||||
struct has_into_toml_method
|
||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||
|
||||
template<typename T>
|
||||
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#undef decltype
|
||||
#endif
|
||||
@@ -121,7 +147,7 @@ struct has_into_toml_method
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++17 and/or/not
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
|
||||
using std::conjunction;
|
||||
using std::disjunction;
|
||||
@@ -183,8 +209,10 @@ template<typename T>
|
||||
struct is_container : conjunction<
|
||||
negation<is_map<T>>, // not a map
|
||||
negation<std::is_same<T, std::string>>, // not a std::string
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
negation<std::is_same<T, std::string_view>>, // not a std::string_view
|
||||
#endif // has_include(<string_view>)
|
||||
#endif
|
||||
has_iterator<T>, // has T::iterator
|
||||
has_value_type<T> // has T::value_type
|
||||
@@ -206,7 +234,7 @@ struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 index_sequence
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::index_sequence;
|
||||
using std::make_index_sequence;
|
||||
@@ -236,12 +264,12 @@ struct index_sequence_maker<0>
|
||||
template<std::size_t N>
|
||||
using make_index_sequence = typename index_sequence_maker<N-1>::type;
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
#endif // cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// C++14 enable_if_t
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::enable_if_t;
|
||||
|
||||
@@ -250,12 +278,12 @@ using std::enable_if_t;
|
||||
template<bool B, typename T>
|
||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
#endif // cplusplus >= 2014
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// return_type_of_t
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
|
||||
|
||||
template<typename F, typename ... Args>
|
||||
using return_type_of_t = std::invoke_result_t<F, Args...>;
|
||||
+24
-1
@@ -21,9 +21,14 @@ class basic_value;
|
||||
using character = char;
|
||||
using key = std::string;
|
||||
|
||||
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
using boolean = bool;
|
||||
using integer = std::int64_t;
|
||||
using floating = double; // "float" is a keyward, cannot use it here.
|
||||
using floating = double; // "float" is a keyword, cannot use it here.
|
||||
// the following stuffs are structs defined here, so aliases are not needed.
|
||||
// - string
|
||||
// - offset_datetime
|
||||
@@ -32,12 +37,26 @@ using floating = double; // "float" is a keyward, cannot use it here.
|
||||
// - local_date
|
||||
// - local_time
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// default toml::value and default array/table. these are defined after defining
|
||||
// basic_value itself.
|
||||
// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
||||
// using array = typename value::array_type;
|
||||
// using table = typename value::table_type;
|
||||
|
||||
// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
|
||||
// GCC -Wshadow=global.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# if 7 <= __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wshadow=global"
|
||||
# else // gcc-6 or older
|
||||
# pragma GCC diagnostic ignored "-Wshadow"
|
||||
# endif
|
||||
#endif
|
||||
enum class value_t : std::uint8_t
|
||||
{
|
||||
empty = 0,
|
||||
@@ -52,6 +71,9 @@ enum class value_t : std::uint8_t
|
||||
array = 9,
|
||||
table = 10,
|
||||
};
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
template<typename charT, typename traits>
|
||||
inline std::basic_ostream<charT, traits>&
|
||||
@@ -147,4 +169,5 @@ template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
|
||||
#endif// TOML11_TYPES_H
|
||||
+60
-3
@@ -7,8 +7,9 @@
|
||||
#include <utility>
|
||||
|
||||
#include "traits.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
# define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
|
||||
#elif defined(__GNUC__)
|
||||
# define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
@@ -21,7 +22,7 @@
|
||||
namespace toml
|
||||
{
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
|
||||
using std::make_unique;
|
||||
|
||||
@@ -33,7 +34,7 @@ inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
||||
return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
|
||||
}
|
||||
|
||||
#endif // __cplusplus >= 2014
|
||||
#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -89,5 +90,61 @@ T from_string(const std::string& str, T opt)
|
||||
return v;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
|
||||
template<typename T>
|
||||
decltype(auto) last_one(T&& tail) noexcept
|
||||
{
|
||||
return std::forward<T>(tail);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
|
||||
{
|
||||
return last_one(std::forward<Ts>(tail)...);
|
||||
}
|
||||
#else // C++11
|
||||
// The following code
|
||||
// ```cpp
|
||||
// 1 | template<typename T, typename ... Ts>
|
||||
// 2 | auto last_one(T&& /*head*/, Ts&& ... tail)
|
||||
// 3 | -> decltype(last_one(std::forward<Ts>(tail)...))
|
||||
// 4 | {
|
||||
// 5 | return last_one(std::forward<Ts>(tail)...);
|
||||
// 6 | }
|
||||
// ```
|
||||
// does not work because the function `last_one(...)` is not yet defined at
|
||||
// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
|
||||
// So we need to determine return type in a different way, like a meta func.
|
||||
|
||||
template<typename T, typename ... Ts>
|
||||
struct last_one_in_pack
|
||||
{
|
||||
using type = typename last_one_in_pack<Ts...>::type;
|
||||
};
|
||||
template<typename T>
|
||||
struct last_one_in_pack<T>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
template<typename ... Ts>
|
||||
using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
|
||||
|
||||
template<typename T>
|
||||
T&& last_one(T&& tail) noexcept
|
||||
{
|
||||
return std::forward<T>(tail);
|
||||
}
|
||||
template<typename T, typename ... Ts>
|
||||
enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
|
||||
last_one(T&& /*head*/, Ts&& ... tail)
|
||||
{
|
||||
return last_one(std::forward<Ts>(tail)...);
|
||||
}
|
||||
|
||||
#endif
|
||||
} // detail
|
||||
|
||||
}// toml
|
||||
#endif // TOML11_UTILITY
|
||||
+108
-85
@@ -66,9 +66,20 @@ throw_key_not_found_error(const Value& v, const key& ky)
|
||||
// ```
|
||||
// It actually points to the top-level table at the first character,
|
||||
// not `[table]`. But it is too confusing. To avoid the confusion, the error
|
||||
// message should explicitly say "key not found in the top-level table".
|
||||
// message should explicitly say "key not found in the top-level table",
|
||||
// or "the parsed file is empty" if there is no content at all (0 bytes in file).
|
||||
const auto loc = v.location();
|
||||
if(loc.line() == 1 && loc.region() == 1)
|
||||
if(loc.line() == 1 && loc.region() == 0)
|
||||
{
|
||||
// First line with a zero-length region means "empty file".
|
||||
// The region will be generated at `parse_toml_file` function
|
||||
// if the file contains no bytes.
|
||||
throw std::out_of_range(format_underline(concat_to_string(
|
||||
"key \"", ky, "\" not found in the top-level table"), {
|
||||
{loc, "the parsed file is empty"}
|
||||
}));
|
||||
}
|
||||
else if(loc.line() == 1 && loc.region() == 1)
|
||||
{
|
||||
// Here it assumes that top-level table starts at the first character.
|
||||
// The region corresponds to the top-level table will be generated at
|
||||
@@ -90,7 +101,7 @@ throw_key_not_found_error(const Value& v, const key& ky)
|
||||
// ```toml
|
||||
// a = {b = "c"}
|
||||
// ```
|
||||
// toml11 consideres the inline table body as the table region. Here,
|
||||
// toml11 considers the inline table body as the table region. Here,
|
||||
// `{b = "c"}` is the region of the table "a". The size of the region
|
||||
// is 9, not 1. The shotest inline table still has two characters, `{`
|
||||
// and `}`. The size cannot be 1.
|
||||
@@ -99,7 +110,7 @@ throw_key_not_found_error(const Value& v, const key& ky)
|
||||
// ```toml
|
||||
// [a]
|
||||
// ```
|
||||
// toml11 consideres the whole table key as the table region. Here,
|
||||
// toml11 considers the whole table key as the table region. Here,
|
||||
// `[a]` is the table region. The size is 3, not 1.
|
||||
//
|
||||
throw std::out_of_range(format_underline(concat_to_string(
|
||||
@@ -236,6 +247,7 @@ class basic_value
|
||||
}
|
||||
basic_value& operator=(const basic_value& v)
|
||||
{
|
||||
if(this == std::addressof(v)) {return *this;}
|
||||
this->cleanup();
|
||||
this->region_info_ = v.region_info_;
|
||||
this->comments_ = v.comments_;
|
||||
@@ -258,6 +270,7 @@ class basic_value
|
||||
}
|
||||
basic_value& operator=(basic_value&& v)
|
||||
{
|
||||
if(this == std::addressof(v)) {return *this;}
|
||||
this->cleanup();
|
||||
this->region_info_ = std::move(v.region_info_);
|
||||
this->comments_ = std::move(v.comments_);
|
||||
@@ -281,9 +294,9 @@ class basic_value
|
||||
|
||||
// overwrite comments ----------------------------------------------------
|
||||
|
||||
basic_value(const basic_value& v, std::vector<std::string> comments)
|
||||
basic_value(const basic_value& v, std::vector<std::string> com)
|
||||
: type_(v.type()), region_info_(v.region_info_),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
@@ -301,9 +314,9 @@ class basic_value
|
||||
}
|
||||
}
|
||||
|
||||
basic_value(basic_value&& v, std::vector<std::string> comments)
|
||||
basic_value(basic_value&& v, std::vector<std::string> com)
|
||||
: type_(v.type()), region_info_(std::move(v.region_info_)),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
switch(this->type_) // here this->type_ is already initialized
|
||||
{
|
||||
@@ -359,9 +372,9 @@ class basic_value
|
||||
template<typename C,
|
||||
template<typename ...> class T,
|
||||
template<typename ...> class A>
|
||||
basic_value(const basic_value<C, T, A>& v, std::vector<std::string> comments)
|
||||
basic_value(const basic_value<C, T, A>& v, std::vector<std::string> com)
|
||||
: type_(v.type()), region_info_(v.region_info_),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
switch(v.type())
|
||||
{
|
||||
@@ -443,10 +456,10 @@ class basic_value
|
||||
assigner(this->boolean_, b);
|
||||
return *this;
|
||||
}
|
||||
basic_value(boolean b, std::vector<std::string> comments)
|
||||
basic_value(boolean b, std::vector<std::string> com)
|
||||
: type_(value_t::boolean),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->boolean_, b);
|
||||
}
|
||||
@@ -478,10 +491,10 @@ class basic_value
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
basic_value(T i, std::vector<std::string> comments)
|
||||
basic_value(T i, std::vector<std::string> com)
|
||||
: type_(value_t::integer),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->integer_, static_cast<integer>(i));
|
||||
}
|
||||
@@ -511,10 +524,10 @@ class basic_value
|
||||
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(T f, std::vector<std::string> comments)
|
||||
basic_value(T f, std::vector<std::string> com)
|
||||
: type_(value_t::floating),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->floating_, f);
|
||||
}
|
||||
@@ -535,10 +548,10 @@ class basic_value
|
||||
assigner(this->string_, s);
|
||||
return *this;
|
||||
}
|
||||
basic_value(toml::string s, std::vector<std::string> comments)
|
||||
basic_value(toml::string s, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, std::move(s));
|
||||
}
|
||||
@@ -563,17 +576,17 @@ class basic_value
|
||||
{
|
||||
assigner(this->string_, toml::string(std::move(s), kind));
|
||||
}
|
||||
basic_value(std::string s, std::vector<std::string> comments)
|
||||
basic_value(std::string s, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(std::move(s)));
|
||||
}
|
||||
basic_value(std::string s, string_t kind, std::vector<std::string> comments)
|
||||
basic_value(std::string s, string_t kind, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(std::move(s), kind));
|
||||
}
|
||||
@@ -598,22 +611,22 @@ class basic_value
|
||||
{
|
||||
assigner(this->string_, toml::string(std::string(s), kind));
|
||||
}
|
||||
basic_value(const char* s, std::vector<std::string> comments)
|
||||
basic_value(const char* s, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(std::string(s)));
|
||||
}
|
||||
basic_value(const char* s, string_t kind, std::vector<std::string> comments)
|
||||
basic_value(const char* s, string_t kind, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(std::string(s), kind));
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
||||
basic_value(std::string_view s)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{}))
|
||||
@@ -628,10 +641,10 @@ class basic_value
|
||||
assigner(this->string_, toml::string(s));
|
||||
return *this;
|
||||
}
|
||||
basic_value(std::string_view s, std::vector<std::string> comments)
|
||||
basic_value(std::string_view s, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(s));
|
||||
}
|
||||
@@ -641,10 +654,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->string_, toml::string(s, kind));
|
||||
}
|
||||
basic_value(std::string_view s, string_t kind, std::vector<std::string> comments)
|
||||
basic_value(std::string_view s, string_t kind, std::vector<std::string> com)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->string_, toml::string(s, kind));
|
||||
}
|
||||
@@ -666,10 +679,10 @@ class basic_value
|
||||
assigner(this->local_date_, ld);
|
||||
return *this;
|
||||
}
|
||||
basic_value(const local_date& ld, std::vector<std::string> comments)
|
||||
basic_value(const local_date& ld, std::vector<std::string> com)
|
||||
: type_(value_t::local_date),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->local_date_, ld);
|
||||
}
|
||||
@@ -682,10 +695,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->local_time_, lt);
|
||||
}
|
||||
basic_value(const local_time& lt, std::vector<std::string> comments)
|
||||
basic_value(const local_time& lt, std::vector<std::string> com)
|
||||
: type_(value_t::local_time),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->local_time_, lt);
|
||||
}
|
||||
@@ -707,10 +720,10 @@ class basic_value
|
||||
}
|
||||
template<typename Rep, typename Period>
|
||||
basic_value(const std::chrono::duration<Rep, Period>& dur,
|
||||
std::vector<std::string> comments)
|
||||
std::vector<std::string> com)
|
||||
: type_(value_t::local_time),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->local_time_, local_time(dur));
|
||||
}
|
||||
@@ -732,10 +745,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->local_datetime_, ldt);
|
||||
}
|
||||
basic_value(const local_datetime& ldt, std::vector<std::string> comments)
|
||||
basic_value(const local_datetime& ldt, std::vector<std::string> com)
|
||||
: type_(value_t::local_datetime),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->local_datetime_, ldt);
|
||||
}
|
||||
@@ -756,10 +769,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->offset_datetime_, odt);
|
||||
}
|
||||
basic_value(const offset_datetime& odt, std::vector<std::string> comments)
|
||||
basic_value(const offset_datetime& odt, std::vector<std::string> com)
|
||||
: type_(value_t::offset_datetime),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->offset_datetime_, odt);
|
||||
}
|
||||
@@ -778,10 +791,10 @@ class basic_value
|
||||
assigner(this->offset_datetime_, offset_datetime(tp));
|
||||
}
|
||||
basic_value(const std::chrono::system_clock::time_point& tp,
|
||||
std::vector<std::string> comments)
|
||||
std::vector<std::string> com)
|
||||
: type_(value_t::offset_datetime),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->offset_datetime_, offset_datetime(tp));
|
||||
}
|
||||
@@ -802,10 +815,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->array_, ary);
|
||||
}
|
||||
basic_value(const array_type& ary, std::vector<std::string> comments)
|
||||
basic_value(const array_type& ary, std::vector<std::string> com)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->array_, ary);
|
||||
}
|
||||
@@ -833,10 +846,10 @@ class basic_value
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_convertible<T, value_type>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
basic_value(std::initializer_list<T> list, std::vector<std::string> comments)
|
||||
basic_value(std::initializer_list<T> list, std::vector<std::string> com)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
array_type ary(list.begin(), list.end());
|
||||
assigner(this->array_, std::move(ary));
|
||||
@@ -876,10 +889,10 @@ class basic_value
|
||||
detail::negation<std::is_same<T, array_type>>,
|
||||
detail::is_container<T>
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(const T& list, std::vector<std::string> comments)
|
||||
basic_value(const T& list, std::vector<std::string> com)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
static_assert(std::is_convertible<typename T::value_type, value_type>::value,
|
||||
"elements of a container should be convertible to toml::value");
|
||||
@@ -915,10 +928,10 @@ class basic_value
|
||||
{
|
||||
assigner(this->table_, tab);
|
||||
}
|
||||
basic_value(const table_type& tab, std::vector<std::string> comments)
|
||||
basic_value(const table_type& tab, std::vector<std::string> com)
|
||||
: type_(value_t::table),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
assigner(this->table_, tab);
|
||||
}
|
||||
@@ -943,10 +956,10 @@ class basic_value
|
||||
}
|
||||
|
||||
basic_value(std::initializer_list<std::pair<key, basic_value>> list,
|
||||
std::vector<std::string> comments)
|
||||
std::vector<std::string> com)
|
||||
: type_(value_t::table),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
table_type tab;
|
||||
for(const auto& elem : list) {tab[elem.first] = elem.second;}
|
||||
@@ -982,10 +995,10 @@ class basic_value
|
||||
detail::negation<std::is_same<Map, table_type>>,
|
||||
detail::is_map<Map>
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(const Map& mp, std::vector<std::string> comments)
|
||||
basic_value(const Map& mp, std::vector<std::string> com)
|
||||
: type_(value_t::table),
|
||||
region_info_(std::make_shared<region_base>(region_base{})),
|
||||
comments_(std::move(comments))
|
||||
comments_(std::move(com))
|
||||
{
|
||||
table_type tab;
|
||||
for(const auto& elem : mp) {tab[elem.first] = elem.second;}
|
||||
@@ -1017,8 +1030,8 @@ class basic_value
|
||||
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(const T& ud, std::vector<std::string> comments)
|
||||
: basic_value(ud.into_toml(), std::move(comments))
|
||||
basic_value(const T& ud, std::vector<std::string> com)
|
||||
: basic_value(ud.into_toml(), std::move(com))
|
||||
{}
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
|
||||
@@ -1033,8 +1046,8 @@ class basic_value
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
basic_value(const T& ud): basic_value(::toml::into<T>::into_toml(ud)) {}
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
basic_value(const T& ud, std::vector<std::string> comments)
|
||||
: basic_value(::toml::into<T>::into_toml(ud), std::move(comments))
|
||||
basic_value(const T& ud, std::vector<std::string> com)
|
||||
: basic_value(::toml::into<T>::into_toml(ud), std::move(com))
|
||||
{}
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
basic_value& operator=(const T& ud)
|
||||
@@ -1047,10 +1060,10 @@ class basic_value
|
||||
//
|
||||
// Those constructors take detail::region that contains parse result.
|
||||
|
||||
basic_value(boolean b, detail::region reg)
|
||||
basic_value(boolean b, detail::region reg, std::vector<std::string> cm)
|
||||
: type_(value_t::boolean),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->boolean_, b);
|
||||
}
|
||||
@@ -1058,68 +1071,75 @@ class basic_value
|
||||
detail::conjunction<
|
||||
std::is_integral<T>, detail::negation<std::is_same<T, boolean>>
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(T i, detail::region reg)
|
||||
basic_value(T i, detail::region reg, std::vector<std::string> cm)
|
||||
: type_(value_t::integer),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->integer_, static_cast<integer>(i));
|
||||
}
|
||||
template<typename T, typename std::enable_if<
|
||||
std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
|
||||
basic_value(T f, detail::region reg)
|
||||
basic_value(T f, detail::region reg, std::vector<std::string> cm)
|
||||
: type_(value_t::floating),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->floating_, static_cast<floating>(f));
|
||||
}
|
||||
basic_value(toml::string s, detail::region reg)
|
||||
basic_value(toml::string s, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::string),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->string_, std::move(s));
|
||||
}
|
||||
basic_value(const local_date& ld, detail::region reg)
|
||||
basic_value(const local_date& ld, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::local_date),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->local_date_, ld);
|
||||
}
|
||||
basic_value(const local_time& lt, detail::region reg)
|
||||
basic_value(const local_time& lt, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::local_time),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->local_time_, lt);
|
||||
}
|
||||
basic_value(const local_datetime& ldt, detail::region reg)
|
||||
basic_value(const local_datetime& ldt, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::local_datetime),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->local_datetime_, ldt);
|
||||
}
|
||||
basic_value(const offset_datetime& odt, detail::region reg)
|
||||
basic_value(const offset_datetime& odt, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::offset_datetime),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->offset_datetime_, odt);
|
||||
}
|
||||
basic_value(const array_type& ary, detail::region reg)
|
||||
basic_value(const array_type& ary, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::array),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->array_, ary);
|
||||
}
|
||||
basic_value(const table_type& tab, detail::region reg)
|
||||
basic_value(const table_type& tab, detail::region reg,
|
||||
std::vector<std::string> cm)
|
||||
: type_(value_t::table),
|
||||
region_info_(std::make_shared<detail::region>(std::move(reg))),
|
||||
comments_(region_info_->comments())
|
||||
comments_(std::move(cm))
|
||||
{
|
||||
assigner(this->table_, tab);
|
||||
}
|
||||
@@ -1127,8 +1147,10 @@ class basic_value
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::is_exact_toml_type<T, value_type>::value,
|
||||
std::nullptr_t>::type = nullptr>
|
||||
basic_value(std::pair<T, detail::region> parse_result)
|
||||
: basic_value(std::move(parse_result.first), std::move(parse_result.second))
|
||||
basic_value(std::pair<T, detail::region> parse_result, std::vector<std::string> com)
|
||||
: basic_value(std::move(parse_result.first),
|
||||
std::move(parse_result.second),
|
||||
std::move(com))
|
||||
{}
|
||||
|
||||
// type checking and casting ============================================
|
||||
@@ -1692,9 +1714,9 @@ class basic_value
|
||||
{
|
||||
switch(this->type_)
|
||||
{
|
||||
case value_t::string : {string_.~string(); return;}
|
||||
case value_t::array : {array_.~array_storage(); return;}
|
||||
case value_t::table : {table_.~table_storage(); return;}
|
||||
case value_t::string : {string_.~string(); return;}
|
||||
case value_t::array : {array_.~array_storage(); return;}
|
||||
case value_t::table : {table_.~table_storage(); return;}
|
||||
default : return;
|
||||
}
|
||||
}
|
||||
@@ -1730,7 +1752,8 @@ class basic_value
|
||||
};
|
||||
|
||||
// default toml::value and default array/table.
|
||||
using value = basic_value<discard_comments, std::unordered_map, std::vector>;
|
||||
// TOML11_DEFAULT_COMMENT_STRATEGY is defined in comments.hpp
|
||||
using value = basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
|
||||
using array = typename value::array_type;
|
||||
using table = typename value::table_type;
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#ifndef TOML11_VERSION_HPP
|
||||
#define TOML11_VERSION_HPP
|
||||
|
||||
// This file checks C++ version.
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
#endif
|
||||
|
||||
// Since MSVC does not define `__cplusplus` correctly unless you pass
|
||||
// `/Zc:__cplusplus` when compiling, the workaround macros are added.
|
||||
// Those enables you to define version manually or to use MSVC specific
|
||||
// version macro automatically.
|
||||
//
|
||||
// The value of `__cplusplus` macro is defined in the C++ standard spec, but
|
||||
// MSVC ignores the value, maybe because of backward compatibility. Instead,
|
||||
// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in
|
||||
// the C++ standard. First we check the manual version definition, and then
|
||||
// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`.
|
||||
//
|
||||
// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
|
||||
//
|
||||
#if defined(TOML11_ENFORCE_CXX11)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L
|
||||
#elif defined(TOML11_ENFORCE_CXX14)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L
|
||||
#elif defined(TOML11_ENFORCE_CXX17)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L
|
||||
#elif defined(TOML11_ENFORCE_CXX20)
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L
|
||||
#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG
|
||||
#else
|
||||
# define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus
|
||||
#endif
|
||||
|
||||
#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900
|
||||
# error "toml11 requires C++11 or later."
|
||||
#endif
|
||||
|
||||
#endif// TOML11_VERSION_HPP
|
||||
Reference in New Issue
Block a user