diff options
Diffstat (limited to 'src/toml11/toml/value.hpp')
-rw-r--r-- | src/toml11/toml/value.hpp | 2035 |
1 files changed, 2035 insertions, 0 deletions
diff --git a/src/toml11/toml/value.hpp b/src/toml11/toml/value.hpp new file mode 100644 index 000000000..1b43db8d4 --- /dev/null +++ b/src/toml11/toml/value.hpp @@ -0,0 +1,2035 @@ +// Copyright Toru Niina 2017. +// Distributed under the MIT License. +#ifndef TOML11_VALUE_HPP +#define TOML11_VALUE_HPP +#include <cassert> + +#include "comments.hpp" +#include "exception.hpp" +#include "into.hpp" +#include "region.hpp" +#include "source_location.hpp" +#include "storage.hpp" +#include "traits.hpp" +#include "types.hpp" +#include "utility.hpp" + +namespace toml +{ + +namespace detail +{ + +// to show error messages. not recommended for users. +template<typename Value> +inline region_base const* get_region(const Value& v) +{ + return v.region_info_.get(); +} + +template<typename Value> +void change_region(Value& v, region reg) +{ + v.region_info_ = std::make_shared<region>(std::move(reg)); + return; +} + +template<value_t Expected, typename Value> +[[noreturn]] inline void +throw_bad_cast(const std::string& funcname, value_t actual, const Value& v) +{ + throw type_error(detail::format_underline( + concat_to_string(funcname, "bad_cast to ", Expected), { + {v.location(), concat_to_string("the actual type is ", actual)} + }), v.location()); +} + +// Throw `out_of_range` from `toml::value::at()` and `toml::find()` +// after generating an error message. +// +// The implementation is a bit complicated and there are many edge-cases. +// If you are not interested in the error message generation, just skip this. +template<typename Value> +[[noreturn]] void +throw_key_not_found_error(const Value& v, const key& ky) +{ + // The top-level table has its region at the first character of the file. + // That means that, in the case when a key is not found in the top-level + // table, the error message points to the first character. If the file has + // its first table at the first line, the error message would be like this. + // ```console + // [error] key "a" not found + // --> example.toml + // | + // 1 | [table] + // | ^------ in this table + // ``` + // It actually points to the top-level table at the first character, + // not `[table]`. But it is too confusing. To avoid the confusion, the error + // message should explicitly say "key not found in the top-level table", + // or "the parsed file is empty" if there is no content at all (0 bytes in file). + const auto loc = v.location(); + if(loc.line() == 1 && loc.region() == 0) + { + // First line with a zero-length region means "empty file". + // The region will be generated at `parse_toml_file` function + // if the file contains no bytes. + throw std::out_of_range(format_underline(concat_to_string( + "key \"", ky, "\" not found in the top-level table"), { + {loc, "the parsed file is empty"} + })); + } + else if(loc.line() == 1 && loc.region() == 1) + { + // Here it assumes that top-level table starts at the first character. + // The region corresponds to the top-level table will be generated at + // `parse_toml_file` function. + // It also assumes that the top-level table size is just one and + // the line number is `1`. It is always satisfied. And those conditions + // are satisfied only if the table is the top-level table. + // + // 1. one-character dot-key at the first line + // ```toml + // a.b = "c" + // ``` + // toml11 counts whole key as the table key. Here, `a.b` is the region + // of the table "a". It could be counter intuitive, but it works. + // The size of the region is 3, not 1. The above example is the shortest + // dot-key example. The size cannot be 1. + // + // 2. one-character inline-table at the first line + // ```toml + // a = {b = "c"} + // ``` + // toml11 considers the inline table body as the table region. Here, + // `{b = "c"}` is the region of the table "a". The size of the region + // is 9, not 1. The shotest inline table still has two characters, `{` + // and `}`. The size cannot be 1. + // + // 3. one-character table declaration at the first line + // ```toml + // [a] + // ``` + // toml11 considers the whole table key as the table region. Here, + // `[a]` is the table region. The size is 3, not 1. + // + throw std::out_of_range(format_underline(concat_to_string( + "key \"", ky, "\" not found in the top-level table"), { + {loc, "the top-level table starts here"} + })); + } + else + { + // normal table. + throw std::out_of_range(format_underline(concat_to_string( + "key \"", ky, "\" not found"), { {loc, "in this table"} })); + } +} + +// switch by `value_t` at the compile time. +template<value_t T> +struct switch_cast {}; +#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \ + template<> \ + struct switch_cast<value_t::TYPE> \ + { \ + template<typename Value> \ + static typename Value::TYPE##_type& invoke(Value& v) \ + { \ + return v.as_##TYPE(); \ + } \ + template<typename Value> \ + static typename Value::TYPE##_type const& invoke(const Value& v) \ + { \ + return v.as_##TYPE(); \ + } \ + template<typename Value> \ + static typename Value::TYPE##_type&& invoke(Value&& v) \ + { \ + return std::move(v).as_##TYPE(); \ + } \ + }; \ + /**/ +TOML11_GENERATE_SWITCH_CASTER(boolean) +TOML11_GENERATE_SWITCH_CASTER(integer) +TOML11_GENERATE_SWITCH_CASTER(floating) +TOML11_GENERATE_SWITCH_CASTER(string) +TOML11_GENERATE_SWITCH_CASTER(offset_datetime) +TOML11_GENERATE_SWITCH_CASTER(local_datetime) +TOML11_GENERATE_SWITCH_CASTER(local_date) +TOML11_GENERATE_SWITCH_CASTER(local_time) +TOML11_GENERATE_SWITCH_CASTER(array) +TOML11_GENERATE_SWITCH_CASTER(table) + +#undef TOML11_GENERATE_SWITCH_CASTER + +}// detail + +template<typename Comment, // discard/preserve_comment + template<typename ...> class Table = std::unordered_map, + template<typename ...> class Array = std::vector> +class basic_value +{ + template<typename T, typename U> + static void assigner(T& dst, U&& v) + { + const auto tmp = ::new(std::addressof(dst)) T(std::forward<U>(v)); + assert(tmp == std::addressof(dst)); + (void)tmp; + } + + using region_base = detail::region_base; + + template<typename C, template<typename ...> class T, + template<typename ...> class A> + friend class basic_value; + + public: + + using comment_type = Comment; + using key_type = ::toml::key; + using value_type = basic_value<comment_type, Table, Array>; + using boolean_type = ::toml::boolean; + using integer_type = ::toml::integer; + using floating_type = ::toml::floating; + using string_type = ::toml::string; + using local_time_type = ::toml::local_time; + using local_date_type = ::toml::local_date; + using local_datetime_type = ::toml::local_datetime; + using offset_datetime_type = ::toml::offset_datetime; + using array_type = Array<value_type>; + using table_type = Table<key_type, value_type>; + + public: + + basic_value() noexcept + : type_(value_t::empty), + region_info_(std::make_shared<region_base>(region_base{})) + {} + ~basic_value() noexcept {this->cleanup();} + + basic_value(const basic_value& v) + : type_(v.type()), region_info_(v.region_info_), comments_(v.comments_) + { + switch(v.type()) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : assigner(array_ , v.array_ ); break; + case value_t::table : assigner(table_ , v.table_ ); break; + default: break; + } + } + basic_value(basic_value&& v) + : type_(v.type()), region_info_(std::move(v.region_info_)), + comments_(std::move(v.comments_)) + { + switch(this->type_) // here this->type_ is already initialized + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default: break; + } + } + basic_value& operator=(const basic_value& v) + { + this->cleanup(); + this->region_info_ = v.region_info_; + this->comments_ = v.comments_; + this->type_ = v.type(); + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : assigner(array_ , v.array_ ); break; + case value_t::table : assigner(table_ , v.table_ ); break; + default: break; + } + return *this; + } + basic_value& operator=(basic_value&& v) + { + this->cleanup(); + this->region_info_ = std::move(v.region_info_); + this->comments_ = std::move(v.comments_); + this->type_ = v.type(); + switch(this->type_) + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default: break; + } + return *this; + } + + // overwrite comments ---------------------------------------------------- + + basic_value(const basic_value& v, std::vector<std::string> com) + : type_(v.type()), region_info_(v.region_info_), + comments_(std::move(com)) + { + switch(v.type()) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : assigner(array_ , v.array_ ); break; + case value_t::table : assigner(table_ , v.table_ ); break; + default: break; + } + } + + basic_value(basic_value&& v, std::vector<std::string> com) + : type_(v.type()), region_info_(std::move(v.region_info_)), + comments_(std::move(com)) + { + switch(this->type_) // here this->type_ is already initialized + { + case value_t::boolean : assigner(boolean_ , std::move(v.boolean_ )); break; + case value_t::integer : assigner(integer_ , std::move(v.integer_ )); break; + case value_t::floating : assigner(floating_ , std::move(v.floating_ )); break; + case value_t::string : assigner(string_ , std::move(v.string_ )); break; + case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break; + case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break; + case value_t::local_date : assigner(local_date_ , std::move(v.local_date_ )); break; + case value_t::local_time : assigner(local_time_ , std::move(v.local_time_ )); break; + case value_t::array : assigner(array_ , std::move(v.array_ )); break; + case value_t::table : assigner(table_ , std::move(v.table_ )); break; + default: break; + } + } + + // ----------------------------------------------------------------------- + // conversion between different basic_values. + template<typename C, + template<typename ...> class T, + template<typename ...> class A> + basic_value(const basic_value<C, T, A>& v) + : type_(v.type()), region_info_(v.region_info_), comments_(v.comments()) + { + switch(v.type()) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : + { + array_type tmp(v.as_array(std::nothrow).begin(), + v.as_array(std::nothrow).end()); + assigner(array_, std::move(tmp)); + break; + } + case value_t::table : + { + table_type tmp(v.as_table(std::nothrow).begin(), + v.as_table(std::nothrow).end()); + assigner(table_, std::move(tmp)); + break; + } + default: break; + } + } + template<typename C, + template<typename ...> class T, + template<typename ...> class A> + 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(com)) + { + switch(v.type()) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : + { + array_type tmp(v.as_array(std::nothrow).begin(), + v.as_array(std::nothrow).end()); + assigner(array_, std::move(tmp)); + break; + } + case value_t::table : + { + table_type tmp(v.as_table(std::nothrow).begin(), + v.as_table(std::nothrow).end()); + assigner(table_, std::move(tmp)); + break; + } + default: break; + } + } + template<typename C, + template<typename ...> class T, + template<typename ...> class A> + basic_value& operator=(const basic_value<C, T, A>& v) + { + this->region_info_ = v.region_info_; + this->comments_ = comment_type(v.comments()); + this->type_ = v.type(); + switch(v.type()) + { + case value_t::boolean : assigner(boolean_ , v.boolean_ ); break; + case value_t::integer : assigner(integer_ , v.integer_ ); break; + case value_t::floating : assigner(floating_ , v.floating_ ); break; + case value_t::string : assigner(string_ , v.string_ ); break; + case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break; + case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break; + case value_t::local_date : assigner(local_date_ , v.local_date_ ); break; + case value_t::local_time : assigner(local_time_ , v.local_time_ ); break; + case value_t::array : + { + array_type tmp(v.as_array(std::nothrow).begin(), + v.as_array(std::nothrow).end()); + assigner(array_, std::move(tmp)); + break; + } + case value_t::table : + { + table_type tmp(v.as_table(std::nothrow).begin(), + v.as_table(std::nothrow).end()); + assigner(table_, std::move(tmp)); + break; + } + default: break; + } + return *this; + } + + // boolean ============================================================== + + basic_value(boolean b) + : type_(value_t::boolean), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->boolean_, b); + } + basic_value& operator=(boolean b) + { + this->cleanup(); + this->type_ = value_t::boolean; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->boolean_, b); + return *this; + } + 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(com)) + { + assigner(this->boolean_, b); + } + + // integer ============================================================== + + 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) + : type_(value_t::integer), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->integer_, static_cast<integer>(i)); + } + + 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& operator=(T i) + { + this->cleanup(); + this->type_ = value_t::integer; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->integer_, static_cast<integer>(i)); + return *this; + } + + 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> com) + : type_(value_t::integer), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + assigner(this->integer_, static_cast<integer>(i)); + } + + // floating ============================================================= + + template<typename T, typename std::enable_if< + std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr> + basic_value(T f) + : type_(value_t::floating), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->floating_, static_cast<floating>(f)); + } + + + template<typename T, typename std::enable_if< + std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr> + basic_value& operator=(T f) + { + this->cleanup(); + this->type_ = value_t::floating; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->floating_, static_cast<floating>(f)); + return *this; + } + + 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> com) + : type_(value_t::floating), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + assigner(this->floating_, f); + } + + // string =============================================================== + + basic_value(toml::string s) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, std::move(s)); + } + basic_value& operator=(toml::string s) + { + this->cleanup(); + this->type_ = value_t::string ; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->string_, s); + return *this; + } + 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(com)) + { + assigner(this->string_, std::move(s)); + } + + basic_value(std::string s) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(std::move(s))); + } + basic_value& operator=(std::string s) + { + this->cleanup(); + this->type_ = value_t::string ; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->string_, toml::string(std::move(s))); + return *this; + } + basic_value(std::string s, string_t kind) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(std::move(s), kind)); + } + 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(com)) + { + assigner(this->string_, toml::string(std::move(s))); + } + 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(com)) + { + assigner(this->string_, toml::string(std::move(s), kind)); + } + + basic_value(const char* s) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(std::string(s))); + } + basic_value& operator=(const char* s) + { + this->cleanup(); + this->type_ = value_t::string ; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->string_, toml::string(std::string(s))); + return *this; + } + basic_value(const char* s, string_t kind) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(std::string(s), kind)); + } + 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(com)) + { + assigner(this->string_, toml::string(std::string(s))); + } + 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(com)) + { + assigner(this->string_, toml::string(std::string(s), kind)); + } + +#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0 + basic_value(std::string_view s) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(s)); + } + basic_value& operator=(std::string_view s) + { + this->cleanup(); + this->type_ = value_t::string ; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->string_, toml::string(s)); + return *this; + } + 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(com)) + { + assigner(this->string_, toml::string(s)); + } + basic_value(std::string_view s, string_t kind) + : type_(value_t::string), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->string_, toml::string(s, kind)); + } + 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(com)) + { + assigner(this->string_, toml::string(s, kind)); + } +#endif + + // local date =========================================================== + + basic_value(const local_date& ld) + : type_(value_t::local_date), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->local_date_, ld); + } + basic_value& operator=(const local_date& ld) + { + this->cleanup(); + this->type_ = value_t::local_date; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->local_date_, ld); + return *this; + } + 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(com)) + { + assigner(this->local_date_, ld); + } + + // local time =========================================================== + + basic_value(const local_time& lt) + : type_(value_t::local_time), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->local_time_, lt); + } + 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(com)) + { + assigner(this->local_time_, lt); + } + basic_value& operator=(const local_time& lt) + { + this->cleanup(); + this->type_ = value_t::local_time; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->local_time_, lt); + return *this; + } + + template<typename Rep, typename Period> + basic_value(const std::chrono::duration<Rep, Period>& dur) + : type_(value_t::local_time), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->local_time_, local_time(dur)); + } + template<typename Rep, typename Period> + basic_value(const std::chrono::duration<Rep, Period>& dur, + std::vector<std::string> com) + : type_(value_t::local_time), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + assigner(this->local_time_, local_time(dur)); + } + template<typename Rep, typename Period> + basic_value& operator=(const std::chrono::duration<Rep, Period>& dur) + { + this->cleanup(); + this->type_ = value_t::local_time; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->local_time_, local_time(dur)); + return *this; + } + + // local datetime ======================================================= + + basic_value(const local_datetime& ldt) + : type_(value_t::local_datetime), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->local_datetime_, ldt); + } + 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(com)) + { + assigner(this->local_datetime_, ldt); + } + basic_value& operator=(const local_datetime& ldt) + { + this->cleanup(); + this->type_ = value_t::local_datetime; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->local_datetime_, ldt); + return *this; + } + + // offset datetime ====================================================== + + basic_value(const offset_datetime& odt) + : type_(value_t::offset_datetime), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->offset_datetime_, odt); + } + 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(com)) + { + assigner(this->offset_datetime_, odt); + } + basic_value& operator=(const offset_datetime& odt) + { + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->offset_datetime_, odt); + return *this; + } + basic_value(const std::chrono::system_clock::time_point& tp) + : type_(value_t::offset_datetime), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->offset_datetime_, offset_datetime(tp)); + } + basic_value(const std::chrono::system_clock::time_point& tp, + std::vector<std::string> com) + : type_(value_t::offset_datetime), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + assigner(this->offset_datetime_, offset_datetime(tp)); + } + basic_value& operator=(const std::chrono::system_clock::time_point& tp) + { + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->offset_datetime_, offset_datetime(tp)); + return *this; + } + + // array ================================================================ + + basic_value(const array_type& ary) + : type_(value_t::array), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->array_, ary); + } + 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(com)) + { + assigner(this->array_, ary); + } + basic_value& operator=(const array_type& ary) + { + this->cleanup(); + this->type_ = value_t::array ; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->array_, ary); + return *this; + } + + // array (initializer_list) ---------------------------------------------- + + 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) + : type_(value_t::array), + region_info_(std::make_shared<region_base>(region_base{})) + { + array_type ary(list.begin(), list.end()); + assigner(this->array_, std::move(ary)); + } + 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> com) + : type_(value_t::array), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + array_type ary(list.begin(), list.end()); + assigner(this->array_, std::move(ary)); + } + template<typename T, typename std::enable_if< + std::is_convertible<T, value_type>::value, + std::nullptr_t>::type = nullptr> + basic_value& operator=(std::initializer_list<T> list) + { + this->cleanup(); + this->type_ = value_t::array; + this->region_info_ = std::make_shared<region_base>(region_base{}); + + array_type ary(list.begin(), list.end()); + assigner(this->array_, std::move(ary)); + return *this; + } + + // array (STL Containers) ------------------------------------------------ + + template<typename T, typename std::enable_if<detail::conjunction< + detail::negation<std::is_same<T, array_type>>, + detail::is_container<T> + >::value, std::nullptr_t>::type = nullptr> + basic_value(const T& list) + : type_(value_t::array), + region_info_(std::make_shared<region_base>(region_base{})) + { + static_assert(std::is_convertible<typename T::value_type, value_type>::value, + "elements of a container should be convertible to toml::value"); + + array_type ary(list.size()); + std::copy(list.begin(), list.end(), ary.begin()); + assigner(this->array_, std::move(ary)); + } + template<typename T, typename std::enable_if<detail::conjunction< + 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> com) + : type_(value_t::array), + region_info_(std::make_shared<region_base>(region_base{})), + 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"); + + array_type ary(list.size()); + std::copy(list.begin(), list.end(), ary.begin()); + assigner(this->array_, std::move(ary)); + } + template<typename T, typename std::enable_if<detail::conjunction< + detail::negation<std::is_same<T, array_type>>, + detail::is_container<T> + >::value, std::nullptr_t>::type = nullptr> + basic_value& operator=(const T& list) + { + static_assert(std::is_convertible<typename T::value_type, value_type>::value, + "elements of a container should be convertible to toml::value"); + + this->cleanup(); + this->type_ = value_t::array; + this->region_info_ = std::make_shared<region_base>(region_base{}); + + array_type ary(list.size()); + std::copy(list.begin(), list.end(), ary.begin()); + assigner(this->array_, std::move(ary)); + return *this; + } + + // table ================================================================ + + basic_value(const table_type& tab) + : type_(value_t::table), + region_info_(std::make_shared<region_base>(region_base{})) + { + assigner(this->table_, tab); + } + 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(com)) + { + assigner(this->table_, tab); + } + basic_value& operator=(const table_type& tab) + { + this->cleanup(); + this->type_ = value_t::table; + this->region_info_ = std::make_shared<region_base>(region_base{}); + assigner(this->table_, tab); + return *this; + } + + // initializer-list ------------------------------------------------------ + + basic_value(std::initializer_list<std::pair<key, basic_value>> list) + : type_(value_t::table), + region_info_(std::make_shared<region_base>(region_base{})) + { + table_type tab; + for(const auto& elem : list) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + } + + basic_value(std::initializer_list<std::pair<key, basic_value>> list, + std::vector<std::string> com) + : type_(value_t::table), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + table_type tab; + for(const auto& elem : list) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + } + basic_value& operator=(std::initializer_list<std::pair<key, basic_value>> list) + { + this->cleanup(); + this->type_ = value_t::table; + this->region_info_ = std::make_shared<region_base>(region_base{}); + + table_type tab; + for(const auto& elem : list) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + return *this; + } + + // other table-like ----------------------------------------------------- + + template<typename Map, typename std::enable_if<detail::conjunction< + detail::negation<std::is_same<Map, table_type>>, + detail::is_map<Map> + >::value, std::nullptr_t>::type = nullptr> + basic_value(const Map& mp) + : type_(value_t::table), + region_info_(std::make_shared<region_base>(region_base{})) + { + table_type tab; + for(const auto& elem : mp) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + } + template<typename Map, typename std::enable_if<detail::conjunction< + 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> com) + : type_(value_t::table), + region_info_(std::make_shared<region_base>(region_base{})), + comments_(std::move(com)) + { + table_type tab; + for(const auto& elem : mp) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + } + template<typename Map, typename std::enable_if<detail::conjunction< + detail::negation<std::is_same<Map, table_type>>, + detail::is_map<Map> + >::value, std::nullptr_t>::type = nullptr> + basic_value& operator=(const Map& mp) + { + this->cleanup(); + this->type_ = value_t::table; + this->region_info_ = std::make_shared<region_base>(region_base{}); + + table_type tab; + for(const auto& elem : mp) {tab[elem.first] = elem.second;} + assigner(this->table_, std::move(tab)); + return *this; + } + + // user-defined ========================================================= + + // convert using into_toml() method ------------------------------------- + + template<typename T, typename std::enable_if< + detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr> + basic_value(const T& ud): basic_value(ud.into_toml()) {} + + 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> 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> + basic_value& operator=(const T& ud) + { + *this = ud.into_toml(); + return *this; + } + + // convert using into<T> struct ----------------------------------------- + + 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> 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) + { + *this = ::toml::into<T>::into_toml(ud); + return *this; + } + + // for internal use ------------------------------------------------------ + // + // Those constructors take detail::region that contains parse result. + + basic_value(boolean b, detail::region reg, std::vector<std::string> cm) + : type_(value_t::boolean), + region_info_(std::make_shared<detail::region>(std::move(reg))), + comments_(std::move(cm)) + { + assigner(this->boolean_, b); + } + 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, detail::region reg, std::vector<std::string> cm) + : type_(value_t::integer), + region_info_(std::make_shared<detail::region>(std::move(reg))), + 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, std::vector<std::string> cm) + : type_(value_t::floating), + region_info_(std::make_shared<detail::region>(std::move(reg))), + comments_(std::move(cm)) + { + assigner(this->floating_, static_cast<floating>(f)); + } + 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_(std::move(cm)) + { + assigner(this->string_, std::move(s)); + } + 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_(std::move(cm)) + { + assigner(this->local_date_, ld); + } + 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_(std::move(cm)) + { + assigner(this->local_time_, lt); + } + 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_(std::move(cm)) + { + assigner(this->local_datetime_, ldt); + } + 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_(std::move(cm)) + { + assigner(this->offset_datetime_, odt); + } + 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_(std::move(cm)) + { + assigner(this->array_, ary); + } + 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_(std::move(cm)) + { + assigner(this->table_, tab); + } + + 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, std::vector<std::string> com) + : basic_value(std::move(parse_result.first), + std::move(parse_result.second), + std::move(com)) + {} + + // type checking and casting ============================================ + + template<typename T, typename std::enable_if< + detail::is_exact_toml_type<T, value_type>::value, + std::nullptr_t>::type = nullptr> + bool is() const noexcept + { + return detail::type_to_enum<T, value_type>::value == this->type_; + } + bool is(value_t t) const noexcept {return t == this->type_;} + + bool is_uninitialized() const noexcept {return this->is(value_t::empty );} + bool is_boolean() const noexcept {return this->is(value_t::boolean );} + bool is_integer() const noexcept {return this->is(value_t::integer );} + bool is_floating() const noexcept {return this->is(value_t::floating );} + bool is_string() const noexcept {return this->is(value_t::string );} + bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);} + bool is_local_datetime() const noexcept {return this->is(value_t::local_datetime );} + bool is_local_date() const noexcept {return this->is(value_t::local_date );} + bool is_local_time() const noexcept {return this->is(value_t::local_time );} + bool is_array() const noexcept {return this->is(value_t::array );} + bool is_table() const noexcept {return this->is(value_t::table );} + + value_t type() const noexcept {return type_;} + + template<value_t T> + typename detail::enum_to_type<T, value_type>::type& cast() & + { + if(this->type_ != T) + { + detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this); + } + return detail::switch_cast<T>::invoke(*this); + } + template<value_t T> + typename detail::enum_to_type<T, value_type>::type const& cast() const& + { + if(this->type_ != T) + { + detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this); + } + return detail::switch_cast<T>::invoke(*this); + } + template<value_t T> + typename detail::enum_to_type<T, value_type>::type&& cast() && + { + if(this->type_ != T) + { + detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this); + } + return detail::switch_cast<T>::invoke(std::move(*this)); + } + + // ------------------------------------------------------------------------ + // nothrow version + + boolean const& as_boolean (const std::nothrow_t&) const& noexcept {return this->boolean_;} + integer const& as_integer (const std::nothrow_t&) const& noexcept {return this->integer_;} + floating const& as_floating (const std::nothrow_t&) const& noexcept {return this->floating_;} + string const& as_string (const std::nothrow_t&) const& noexcept {return this->string_;} + offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;} + local_datetime const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;} + local_date const& as_local_date (const std::nothrow_t&) const& noexcept {return this->local_date_;} + local_time const& as_local_time (const std::nothrow_t&) const& noexcept {return this->local_time_;} + array_type const& as_array (const std::nothrow_t&) const& noexcept {return this->array_.value();} + table_type const& as_table (const std::nothrow_t&) const& noexcept {return this->table_.value();} + + boolean & as_boolean (const std::nothrow_t&) & noexcept {return this->boolean_;} + integer & as_integer (const std::nothrow_t&) & noexcept {return this->integer_;} + floating & as_floating (const std::nothrow_t&) & noexcept {return this->floating_;} + string & as_string (const std::nothrow_t&) & noexcept {return this->string_;} + offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;} + local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;} + local_date & as_local_date (const std::nothrow_t&) & noexcept {return this->local_date_;} + local_time & as_local_time (const std::nothrow_t&) & noexcept {return this->local_time_;} + array_type & as_array (const std::nothrow_t&) & noexcept {return this->array_.value();} + table_type & as_table (const std::nothrow_t&) & noexcept {return this->table_.value();} + + boolean && as_boolean (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);} + integer && as_integer (const std::nothrow_t&) && noexcept {return std::move(this->integer_);} + floating && as_floating (const std::nothrow_t&) && noexcept {return std::move(this->floating_);} + string && as_string (const std::nothrow_t&) && noexcept {return std::move(this->string_);} + offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);} + local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);} + local_date && as_local_date (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);} + local_time && as_local_time (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);} + array_type && as_array (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());} + table_type && as_table (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());} + + // ======================================================================== + // throw version + // ------------------------------------------------------------------------ + // const reference {{{ + + boolean const& as_boolean() const& + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast<value_t::boolean>( + "toml::value::as_boolean(): ", this->type_, *this); + } + return this->boolean_; + } + integer const& as_integer() const& + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast<value_t::integer>( + "toml::value::as_integer(): ", this->type_, *this); + } + return this->integer_; + } + floating const& as_floating() const& + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast<value_t::floating>( + "toml::value::as_floating(): ", this->type_, *this); + } + return this->floating_; + } + string const& as_string() const& + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast<value_t::string>( + "toml::value::as_string(): ", this->type_, *this); + } + return this->string_; + } + offset_datetime const& as_offset_datetime() const& + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast<value_t::offset_datetime>( + "toml::value::as_offset_datetime(): ", this->type_, *this); + } + return this->offset_datetime_; + } + local_datetime const& as_local_datetime() const& + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast<value_t::local_datetime>( + "toml::value::as_local_datetime(): ", this->type_, *this); + } + return this->local_datetime_; + } + local_date const& as_local_date() const& + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast<value_t::local_date>( + "toml::value::as_local_date(): ", this->type_, *this); + } + return this->local_date_; + } + local_time const& as_local_time() const& + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast<value_t::local_time>( + "toml::value::as_local_time(): ", this->type_, *this); + } + return this->local_time_; + } + array_type const& as_array() const& + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::as_array(): ", this->type_, *this); + } + return this->array_.value(); + } + table_type const& as_table() const& + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::as_table(): ", this->type_, *this); + } + return this->table_.value(); + } + // }}} + // ------------------------------------------------------------------------ + // nonconst reference {{{ + + boolean & as_boolean() & + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast<value_t::boolean>( + "toml::value::as_boolean(): ", this->type_, *this); + } + return this->boolean_; + } + integer & as_integer() & + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast<value_t::integer>( + "toml::value::as_integer(): ", this->type_, *this); + } + return this->integer_; + } + floating & as_floating() & + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast<value_t::floating>( + "toml::value::as_floating(): ", this->type_, *this); + } + return this->floating_; + } + string & as_string() & + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast<value_t::string>( + "toml::value::as_string(): ", this->type_, *this); + } + return this->string_; + } + offset_datetime & as_offset_datetime() & + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast<value_t::offset_datetime>( + "toml::value::as_offset_datetime(): ", this->type_, *this); + } + return this->offset_datetime_; + } + local_datetime & as_local_datetime() & + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast<value_t::local_datetime>( + "toml::value::as_local_datetime(): ", this->type_, *this); + } + return this->local_datetime_; + } + local_date & as_local_date() & + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast<value_t::local_date>( + "toml::value::as_local_date(): ", this->type_, *this); + } + return this->local_date_; + } + local_time & as_local_time() & + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast<value_t::local_time>( + "toml::value::as_local_time(): ", this->type_, *this); + } + return this->local_time_; + } + array_type & as_array() & + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::as_array(): ", this->type_, *this); + } + return this->array_.value(); + } + table_type & as_table() & + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::as_table(): ", this->type_, *this); + } + return this->table_.value(); + } + + // }}} + // ------------------------------------------------------------------------ + // rvalue reference {{{ + + boolean && as_boolean() && + { + if(this->type_ != value_t::boolean) + { + detail::throw_bad_cast<value_t::boolean>( + "toml::value::as_boolean(): ", this->type_, *this); + } + return std::move(this->boolean_); + } + integer && as_integer() && + { + if(this->type_ != value_t::integer) + { + detail::throw_bad_cast<value_t::integer>( + "toml::value::as_integer(): ", this->type_, *this); + } + return std::move(this->integer_); + } + floating && as_floating() && + { + if(this->type_ != value_t::floating) + { + detail::throw_bad_cast<value_t::floating>( + "toml::value::as_floating(): ", this->type_, *this); + } + return std::move(this->floating_); + } + string && as_string() && + { + if(this->type_ != value_t::string) + { + detail::throw_bad_cast<value_t::string>( + "toml::value::as_string(): ", this->type_, *this); + } + return std::move(this->string_); + } + offset_datetime && as_offset_datetime() && + { + if(this->type_ != value_t::offset_datetime) + { + detail::throw_bad_cast<value_t::offset_datetime>( + "toml::value::as_offset_datetime(): ", this->type_, *this); + } + return std::move(this->offset_datetime_); + } + local_datetime && as_local_datetime() && + { + if(this->type_ != value_t::local_datetime) + { + detail::throw_bad_cast<value_t::local_datetime>( + "toml::value::as_local_datetime(): ", this->type_, *this); + } + return std::move(this->local_datetime_); + } + local_date && as_local_date() && + { + if(this->type_ != value_t::local_date) + { + detail::throw_bad_cast<value_t::local_date>( + "toml::value::as_local_date(): ", this->type_, *this); + } + return std::move(this->local_date_); + } + local_time && as_local_time() && + { + if(this->type_ != value_t::local_time) + { + detail::throw_bad_cast<value_t::local_time>( + "toml::value::as_local_time(): ", this->type_, *this); + } + return std::move(this->local_time_); + } + array_type && as_array() && + { + if(this->type_ != value_t::array) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::as_array(): ", this->type_, *this); + } + return std::move(this->array_.value()); + } + table_type && as_table() && + { + if(this->type_ != value_t::table) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::as_table(): ", this->type_, *this); + } + return std::move(this->table_.value()); + } + // }}} + + // accessors ============================================================= + // + // may throw type_error or out_of_range + // + value_type& at(const key& k) + { + if(!this->is_table()) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::at(key): ", this->type_, *this); + } + if(this->as_table(std::nothrow).count(k) == 0) + { + detail::throw_key_not_found_error(*this, k); + } + return this->as_table(std::nothrow).at(k); + } + value_type const& at(const key& k) const + { + if(!this->is_table()) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::at(key): ", this->type_, *this); + } + if(this->as_table(std::nothrow).count(k) == 0) + { + detail::throw_key_not_found_error(*this, k); + } + return this->as_table(std::nothrow).at(k); + } + value_type& operator[](const key& k) + { + if(this->is_uninitialized()) + { + *this = table_type{}; + } + else if(!this->is_table()) // initialized, but not a table + { + detail::throw_bad_cast<value_t::table>( + "toml::value::operator[](key): ", this->type_, *this); + } + return this->as_table(std::nothrow)[k]; + } + + value_type& at(const std::size_t idx) + { + if(!this->is_array()) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::at(idx): ", this->type_, *this); + } + if(this->as_array(std::nothrow).size() <= idx) + { + throw std::out_of_range(detail::format_underline( + "toml::value::at(idx): no element corresponding to the index", { + {this->location(), concat_to_string("the length is ", + this->as_array(std::nothrow).size(), + ", and the specified index is ", idx)} + })); + } + return this->as_array().at(idx); + } + value_type const& at(const std::size_t idx) const + { + if(!this->is_array()) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::at(idx): ", this->type_, *this); + } + if(this->as_array(std::nothrow).size() <= idx) + { + throw std::out_of_range(detail::format_underline( + "toml::value::at(idx): no element corresponding to the index", { + {this->location(), concat_to_string("the length is ", + this->as_array(std::nothrow).size(), + ", and the specified index is ", idx)} + })); + } + return this->as_array(std::nothrow).at(idx); + } + + value_type& operator[](const std::size_t idx) noexcept + { + // no check... + return this->as_array(std::nothrow)[idx]; + } + value_type const& operator[](const std::size_t idx) const noexcept + { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + void push_back(const value_type& x) + { + if(!this->is_array()) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::push_back(value): ", this->type_, *this); + } + this->as_array(std::nothrow).push_back(x); + return; + } + void push_back(value_type&& x) + { + if(!this->is_array()) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::push_back(value): ", this->type_, *this); + } + this->as_array(std::nothrow).push_back(std::move(x)); + return; + } + + template<typename ... Ts> + value_type& emplace_back(Ts&& ... args) + { + if(!this->is_array()) + { + detail::throw_bad_cast<value_t::array>( + "toml::value::emplace_back(...): ", this->type_, *this); + } + this->as_array(std::nothrow).emplace_back(std::forward<Ts>(args) ...); + return this->as_array(std::nothrow).back(); + } + + std::size_t size() const + { + switch(this->type_) + { + case value_t::array: + { + return this->as_array(std::nothrow).size(); + } + case value_t::table: + { + return this->as_table(std::nothrow).size(); + } + case value_t::string: + { + return this->as_string(std::nothrow).str.size(); + } + default: + { + throw type_error(detail::format_underline( + "toml::value::size(): bad_cast to container types", { + {this->location(), + concat_to_string("the actual type is ", this->type_)} + }), this->location()); + } + } + } + + std::size_t count(const key_type& k) const + { + if(!this->is_table()) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::count(key): ", this->type_, *this); + } + return this->as_table(std::nothrow).count(k); + } + + bool contains(const key_type& k) const + { + if(!this->is_table()) + { + detail::throw_bad_cast<value_t::table>( + "toml::value::contains(key): ", this->type_, *this); + } + return (this->as_table(std::nothrow).count(k) != 0); + } + + source_location location() const + { + return source_location(this->region_info_.get()); + } + + comment_type const& comments() const noexcept {return this->comments_;} + comment_type& comments() noexcept {return this->comments_;} + + private: + + void cleanup() noexcept + { + switch(this->type_) + { + case value_t::string : {string_.~string(); return;} + case value_t::array : {array_.~array_storage(); return;} + case value_t::table : {table_.~table_storage(); return;} + default : return; + } + } + + // for error messages + template<typename Value> + friend region_base const* detail::get_region(const Value& v); + + template<typename Value> + friend void detail::change_region(Value& v, detail::region reg); + + private: + + using array_storage = detail::storage<array_type>; + using table_storage = detail::storage<table_type>; + + value_t type_; + union + { + boolean boolean_; + integer integer_; + floating floating_; + string string_; + offset_datetime offset_datetime_; + local_datetime local_datetime_; + local_date local_date_; + local_time local_time_; + array_storage array_; + table_storage table_; + }; + std::shared_ptr<region_base> region_info_; + comment_type comments_; +}; + +// default toml::value and default array/table. +// TOML11_DEFAULT_COMMENT_STRATEGY is defined in comments.hpp +using value = basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>; +using array = typename value::array_type; +using table = typename value::table_type; + +template<typename C, template<typename ...> class T, template<typename ...> class A> +inline bool +operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + if(lhs.type() != rhs.type()) {return false;} + if(lhs.comments() != rhs.comments()) {return false;} + + switch(lhs.type()) + { + case value_t::boolean : + { + return lhs.as_boolean() == rhs.as_boolean(); + } + case value_t::integer : + { + return lhs.as_integer() == rhs.as_integer(); + } + case value_t::floating : + { + return lhs.as_floating() == rhs.as_floating(); + } + case value_t::string : + { + return lhs.as_string() == rhs.as_string(); + } + case value_t::offset_datetime: + { + return lhs.as_offset_datetime() == rhs.as_offset_datetime(); + } + case value_t::local_datetime: + { + return lhs.as_local_datetime() == rhs.as_local_datetime(); + } + case value_t::local_date: + { + return lhs.as_local_date() == rhs.as_local_date(); + } + case value_t::local_time: + { + return lhs.as_local_time() == rhs.as_local_time(); + } + case value_t::array : + { + return lhs.as_array() == rhs.as_array(); + } + case value_t::table : + { + return lhs.as_table() == rhs.as_table(); + } + case value_t::empty : {return true; } + default: {return false;} + } +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +inline bool operator!=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + return !(lhs == rhs); +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +typename std::enable_if<detail::conjunction< + detail::is_comparable<typename basic_value<C, T, A>::array_type>, + detail::is_comparable<typename basic_value<C, T, A>::table_type> + >::value, bool>::type +operator<(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + if(lhs.type() != rhs.type()){return (lhs.type() < rhs.type());} + switch(lhs.type()) + { + case value_t::boolean : + { + return lhs.as_boolean() < rhs.as_boolean() || + (lhs.as_boolean() == rhs.as_boolean() && + lhs.comments() < rhs.comments()); + } + case value_t::integer : + { + return lhs.as_integer() < rhs.as_integer() || + (lhs.as_integer() == rhs.as_integer() && + lhs.comments() < rhs.comments()); + } + case value_t::floating : + { + return lhs.as_floating() < rhs.as_floating() || + (lhs.as_floating() == rhs.as_floating() && + lhs.comments() < rhs.comments()); + } + case value_t::string : + { + return lhs.as_string() < rhs.as_string() || + (lhs.as_string() == rhs.as_string() && + lhs.comments() < rhs.comments()); + } + case value_t::offset_datetime: + { + return lhs.as_offset_datetime() < rhs.as_offset_datetime() || + (lhs.as_offset_datetime() == rhs.as_offset_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_datetime: + { + return lhs.as_local_datetime() < rhs.as_local_datetime() || + (lhs.as_local_datetime() == rhs.as_local_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_date: + { + return lhs.as_local_date() < rhs.as_local_date() || + (lhs.as_local_date() == rhs.as_local_date() && + lhs.comments() < rhs.comments()); + } + case value_t::local_time: + { + return lhs.as_local_time() < rhs.as_local_time() || + (lhs.as_local_time() == rhs.as_local_time() && + lhs.comments() < rhs.comments()); + } + case value_t::array : + { + return lhs.as_array() < rhs.as_array() || + (lhs.as_array() == rhs.as_array() && + lhs.comments() < rhs.comments()); + } + case value_t::table : + { + return lhs.as_table() < rhs.as_table() || + (lhs.as_table() == rhs.as_table() && + lhs.comments() < rhs.comments()); + } + case value_t::empty : + { + return lhs.comments() < rhs.comments(); + } + default: + { + return lhs.comments() < rhs.comments(); + } + } +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +typename std::enable_if<detail::conjunction< + detail::is_comparable<typename basic_value<C, T, A>::array_type>, + detail::is_comparable<typename basic_value<C, T, A>::table_type> + >::value, bool>::type +operator<=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + return (lhs < rhs) || (lhs == rhs); +} +template<typename C, template<typename ...> class T, template<typename ...> class A> +typename std::enable_if<detail::conjunction< + detail::is_comparable<typename basic_value<C, T, A>::array_type>, + detail::is_comparable<typename basic_value<C, T, A>::table_type> + >::value, bool>::type +operator>(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + return !(lhs <= rhs); +} +template<typename C, template<typename ...> class T, template<typename ...> class A> +typename std::enable_if<detail::conjunction< + detail::is_comparable<typename basic_value<C, T, A>::array_type>, + detail::is_comparable<typename basic_value<C, T, A>::table_type> + >::value, bool>::type +operator>=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs) +{ + return !(lhs < rhs); +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +inline std::string format_error(const std::string& err_msg, + const basic_value<C, T, A>& v, const std::string& comment, + std::vector<std::string> hints = {}, + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) +{ + return detail::format_underline(err_msg, {{v.location(), comment}}, + std::move(hints), colorize); +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +inline std::string format_error(const std::string& err_msg, + const toml::basic_value<C, T, A>& v1, const std::string& comment1, + const toml::basic_value<C, T, A>& v2, const std::string& comment2, + std::vector<std::string> hints = {}, + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) +{ + return detail::format_underline(err_msg, { + {v1.location(), comment1}, {v2.location(), comment2} + }, std::move(hints), colorize); +} + +template<typename C, template<typename ...> class T, template<typename ...> class A> +inline std::string format_error(const std::string& err_msg, + const toml::basic_value<C, T, A>& v1, const std::string& comment1, + const toml::basic_value<C, T, A>& v2, const std::string& comment2, + const toml::basic_value<C, T, A>& v3, const std::string& comment3, + std::vector<std::string> hints = {}, + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) +{ + return detail::format_underline(err_msg, {{v1.location(), comment1}, + {v2.location(), comment2}, {v3.location(), comment3} + }, std::move(hints), colorize); +} + +template<typename Visitor, typename C, + template<typename ...> class T, template<typename ...> class A> +detail::return_type_of_t<Visitor, const toml::boolean&> +visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(v.as_boolean ());} + case value_t::integer : {return visitor(v.as_integer ());} + case value_t::floating : {return visitor(v.as_floating ());} + case value_t::string : {return visitor(v.as_string ());} + case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} + case value_t::local_datetime : {return visitor(v.as_local_datetime ());} + case value_t::local_date : {return visitor(v.as_local_date ());} + case value_t::local_time : {return visitor(v.as_local_time ());} + case value_t::array : {return visitor(v.as_array ());} + case value_t::table : {return visitor(v.as_table ());} + case value_t::empty : break; + default: break; + } + throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid basic_value.", v, "here")); +} + +template<typename Visitor, typename C, + template<typename ...> class T, template<typename ...> class A> +detail::return_type_of_t<Visitor, toml::boolean&> +visit(Visitor&& visitor, toml::basic_value<C, T, A>& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(v.as_boolean ());} + case value_t::integer : {return visitor(v.as_integer ());} + case value_t::floating : {return visitor(v.as_floating ());} + case value_t::string : {return visitor(v.as_string ());} + case value_t::offset_datetime: {return visitor(v.as_offset_datetime());} + case value_t::local_datetime : {return visitor(v.as_local_datetime ());} + case value_t::local_date : {return visitor(v.as_local_date ());} + case value_t::local_time : {return visitor(v.as_local_time ());} + case value_t::array : {return visitor(v.as_array ());} + case value_t::table : {return visitor(v.as_table ());} + case value_t::empty : break; + default: break; + } + throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid basic_value.", v, "here")); +} + +template<typename Visitor, typename C, + template<typename ...> class T, template<typename ...> class A> +detail::return_type_of_t<Visitor, toml::boolean&&> +visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v) +{ + switch(v.type()) + { + case value_t::boolean : {return visitor(std::move(v.as_boolean ()));} + case value_t::integer : {return visitor(std::move(v.as_integer ()));} + case value_t::floating : {return visitor(std::move(v.as_floating ()));} + case value_t::string : {return visitor(std::move(v.as_string ()));} + case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));} + case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));} + case value_t::local_date : {return visitor(std::move(v.as_local_date ()));} + case value_t::local_time : {return visitor(std::move(v.as_local_time ()));} + case value_t::array : {return visitor(std::move(v.as_array ()));} + case value_t::table : {return visitor(std::move(v.as_table ()));} + case value_t::empty : break; + default: break; + } + throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid basic_value.", v, "here")); +} + +}// toml +#endif// TOML11_VALUE |