// Copyright Toru Niina 2017. // Distributed under the MIT License. #ifndef TOML11_VALUE_HPP #define TOML11_VALUE_HPP #include #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 inline region_base const* get_region(const Value& v) { return v.region_info_.get(); } template void change_region(Value& v, region reg) { v.region_info_ = std::make_shared(std::move(reg)); return; } template [[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 [[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". const auto loc = v.location(); 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 consideres 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 consideres 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 struct switch_cast {}; #define TOML11_GENERATE_SWITCH_CASTER(TYPE) \ template<> \ struct switch_cast \ { \ template \ static typename Value::TYPE##_type& invoke(Value& v) \ { \ return v.as_##TYPE(); \ } \ template \ static typename Value::TYPE##_type const& invoke(const Value& v) \ { \ return v.as_##TYPE(); \ } \ template \ 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 class Table = std::unordered_map, template class Array = std::vector> class basic_value { template static void assigner(T& dst, U&& v) { const auto tmp = ::new(std::addressof(dst)) T(std::forward(v)); assert(tmp == std::addressof(dst)); (void)tmp; } using region_base = detail::region_base; template class T, template class A> friend class basic_value; public: using comment_type = Comment; using key_type = ::toml::key; using value_type = basic_value; 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; using table_type = Table; public: basic_value() noexcept : type_(value_t::empty), region_info_(std::make_shared(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 comments) : type_(v.type()), region_info_(v.region_info_), comments_(std::move(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, std::vector comments) : type_(v.type()), region_info_(std::move(v.region_info_)), comments_(std::move(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; } } // ----------------------------------------------------------------------- // conversion between different basic_values. template class T, template class A> 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 : { 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 class T, template class A> basic_value(const basic_value& v, std::vector comments) : type_(v.type()), region_info_(v.region_info_), comments_(std::move(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 class T, template class A> basic_value& operator=(const basic_value& 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{})) { assigner(this->boolean_, b); } basic_value& operator=(boolean b) { this->cleanup(); this->type_ = value_t::boolean; this->region_info_ = std::make_shared(region_base{}); assigner(this->boolean_, b); return *this; } basic_value(boolean b, std::vector comments) : type_(value_t::boolean), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->boolean_, b); } // integer ============================================================== template, detail::negation>>::value, std::nullptr_t>::type = nullptr> basic_value(T i) : type_(value_t::integer), region_info_(std::make_shared(region_base{})) { assigner(this->integer_, static_cast(i)); } template, detail::negation>>::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{}); assigner(this->integer_, static_cast(i)); return *this; } template, detail::negation>>::value, std::nullptr_t>::type = nullptr> basic_value(T i, std::vector comments) : type_(value_t::integer), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->integer_, static_cast(i)); } // floating ============================================================= template::value, std::nullptr_t>::type = nullptr> basic_value(T f) : type_(value_t::floating), region_info_(std::make_shared(region_base{})) { assigner(this->floating_, static_cast(f)); } template::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{}); assigner(this->floating_, static_cast(f)); return *this; } template::value, std::nullptr_t>::type = nullptr> basic_value(T f, std::vector comments) : type_(value_t::floating), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->floating_, f); } // string =============================================================== basic_value(toml::string s) : type_(value_t::string), region_info_(std::make_shared(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{}); assigner(this->string_, s); return *this; } basic_value(toml::string s, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->string_, std::move(s)); } basic_value(std::string s) : type_(value_t::string), region_info_(std::make_shared(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{}); 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{})) { assigner(this->string_, toml::string(std::move(s), kind)); } basic_value(std::string s, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->string_, toml::string(std::move(s))); } basic_value(std::string s, string_t kind, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{})) { 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{}); 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{})) { assigner(this->string_, toml::string(std::string(s), kind)); } basic_value(const char* s, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->string_, toml::string(std::string(s))); } basic_value(const char* s, string_t kind, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->string_, toml::string(std::string(s), kind)); } #if __cplusplus >= 201703L basic_value(std::string_view s) : type_(value_t::string), region_info_(std::make_shared(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{}); assigner(this->string_, toml::string(s)); return *this; } basic_value(std::string_view s, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{})) { assigner(this->string_, toml::string(s, kind)); } basic_value(std::string_view s, string_t kind, std::vector comments) : type_(value_t::string), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{})) { 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{}); assigner(this->local_date_, ld); return *this; } basic_value(const local_date& ld, std::vector comments) : type_(value_t::local_date), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{})) { assigner(this->local_time_, lt); } basic_value(const local_time& lt, std::vector comments) : type_(value_t::local_time), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); assigner(this->local_time_, lt); return *this; } template basic_value(const std::chrono::duration& dur) : type_(value_t::local_time), region_info_(std::make_shared(region_base{})) { assigner(this->local_time_, local_time(dur)); } template basic_value(const std::chrono::duration& dur, std::vector comments) : type_(value_t::local_time), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { assigner(this->local_time_, local_time(dur)); } template basic_value& operator=(const std::chrono::duration& dur) { this->cleanup(); this->type_ = value_t::local_time; this->region_info_ = std::make_shared(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{})) { assigner(this->local_datetime_, ldt); } basic_value(const local_datetime& ldt, std::vector comments) : type_(value_t::local_datetime), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); 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{})) { assigner(this->offset_datetime_, odt); } basic_value(const offset_datetime& odt, std::vector comments) : type_(value_t::offset_datetime), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); 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{})) { assigner(this->offset_datetime_, offset_datetime(tp)); } basic_value(const std::chrono::system_clock::time_point& tp, std::vector comments) : type_(value_t::offset_datetime), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); 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{})) { assigner(this->array_, ary); } basic_value(const array_type& ary, std::vector comments) : type_(value_t::array), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); assigner(this->array_, ary); return *this; } // array (initializer_list) ---------------------------------------------- template::value, std::nullptr_t>::type = nullptr> basic_value(std::initializer_list list) : type_(value_t::array), region_info_(std::make_shared(region_base{})) { array_type ary(list.begin(), list.end()); assigner(this->array_, std::move(ary)); } template::value, std::nullptr_t>::type = nullptr> basic_value(std::initializer_list list, std::vector comments) : type_(value_t::array), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { array_type ary(list.begin(), list.end()); assigner(this->array_, std::move(ary)); } template::value, std::nullptr_t>::type = nullptr> basic_value& operator=(std::initializer_list list) { this->cleanup(); this->type_ = value_t::array; this->region_info_ = std::make_shared(region_base{}); array_type ary(list.begin(), list.end()); assigner(this->array_, std::move(ary)); return *this; } // array (STL Containers) ------------------------------------------------ template>, detail::is_container >::value, std::nullptr_t>::type = nullptr> basic_value(const T& list) : type_(value_t::array), region_info_(std::make_shared(region_base{})) { static_assert(std::is_convertible::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>, detail::is_container >::value, std::nullptr_t>::type = nullptr> basic_value(const T& list, std::vector comments) : type_(value_t::array), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { static_assert(std::is_convertible::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>, detail::is_container >::value, std::nullptr_t>::type = nullptr> basic_value& operator=(const T& list) { static_assert(std::is_convertible::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{}); 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{})) { assigner(this->table_, tab); } basic_value(const table_type& tab, std::vector comments) : type_(value_t::table), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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{}); assigner(this->table_, tab); return *this; } // initializer-list ------------------------------------------------------ basic_value(std::initializer_list> list) : type_(value_t::table), region_info_(std::make_shared(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> list, std::vector comments) : type_(value_t::table), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { 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> list) { this->cleanup(); this->type_ = value_t::table; this->region_info_ = std::make_shared(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>, detail::is_map >::value, std::nullptr_t>::type = nullptr> basic_value(const Map& mp) : type_(value_t::table), region_info_(std::make_shared(region_base{})) { table_type tab; for(const auto& elem : mp) {tab[elem.first] = elem.second;} assigner(this->table_, std::move(tab)); } template>, detail::is_map >::value, std::nullptr_t>::type = nullptr> basic_value(const Map& mp, std::vector comments) : type_(value_t::table), region_info_(std::make_shared(region_base{})), comments_(std::move(comments)) { table_type tab; for(const auto& elem : mp) {tab[elem.first] = elem.second;} assigner(this->table_, std::move(tab)); } template>, detail::is_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{}); 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::value, std::nullptr_t>::type = nullptr> basic_value(const T& ud): basic_value(ud.into_toml()) {} template::value, std::nullptr_t>::type = nullptr> basic_value(const T& ud, std::vector comments) : basic_value(ud.into_toml(), std::move(comments)) {} template::value, std::nullptr_t>::type = nullptr> basic_value& operator=(const T& ud) { *this = ud.into_toml(); return *this; } // convert using into struct ----------------------------------------- template)> basic_value(const T& ud): basic_value(::toml::into::into_toml(ud)) {} template)> basic_value(const T& ud, std::vector comments) : basic_value(::toml::into::into_toml(ud), std::move(comments)) {} template)> basic_value& operator=(const T& ud) { *this = ::toml::into::into_toml(ud); return *this; } // for internal use ------------------------------------------------------ // // Those constructors take detail::region that contains parse result. basic_value(boolean b, detail::region reg) : type_(value_t::boolean), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->boolean_, b); } template, detail::negation> >::value, std::nullptr_t>::type = nullptr> basic_value(T i, detail::region reg) : type_(value_t::integer), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->integer_, static_cast(i)); } template::value, std::nullptr_t>::type = nullptr> basic_value(T f, detail::region reg) : type_(value_t::floating), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->floating_, static_cast(f)); } basic_value(toml::string s, detail::region reg) : type_(value_t::string), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->string_, std::move(s)); } basic_value(const local_date& ld, detail::region reg) : type_(value_t::local_date), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_date_, ld); } basic_value(const local_time& lt, detail::region reg) : type_(value_t::local_time), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_time_, lt); } basic_value(const local_datetime& ldt, detail::region reg) : type_(value_t::local_datetime), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->local_datetime_, ldt); } basic_value(const offset_datetime& odt, detail::region reg) : type_(value_t::offset_datetime), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->offset_datetime_, odt); } basic_value(const array_type& ary, detail::region reg) : type_(value_t::array), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->array_, ary); } basic_value(const table_type& tab, detail::region reg) : type_(value_t::table), region_info_(std::make_shared(std::move(reg))), comments_(region_info_->comments()) { assigner(this->table_, tab); } template::value, std::nullptr_t>::type = nullptr> basic_value(std::pair parse_result) : basic_value(std::move(parse_result.first), std::move(parse_result.second)) {} // type checking and casting ============================================ template::value, std::nullptr_t>::type = nullptr> bool is() const noexcept { return detail::type_to_enum::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 typename detail::enum_to_type::type& cast() & { if(this->type_ != T) { detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); } return detail::switch_cast::invoke(*this); } template typename detail::enum_to_type::type const& cast() const& { if(this->type_ != T) { detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); } return detail::switch_cast::invoke(*this); } template typename detail::enum_to_type::type&& cast() && { if(this->type_ != T) { detail::throw_bad_cast("toml::value::cast: ", this->type_, *this); } return detail::switch_cast::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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "toml::value::as_boolean(): ", this->type_, *this); } return this->boolean_; } integer & as_integer() & { if(this->type_ != value_t::integer) { detail::throw_bad_cast( "toml::value::as_integer(): ", this->type_, *this); } return this->integer_; } floating & as_floating() & { if(this->type_ != value_t::floating) { detail::throw_bad_cast( "toml::value::as_floating(): ", this->type_, *this); } return this->floating_; } string & as_string() & { if(this->type_ != value_t::string) { detail::throw_bad_cast( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "toml::value::push_back(value): ", this->type_, *this); } this->as_array(std::nothrow).push_back(std::move(x)); return; } template value_type& emplace_back(Ts&& ... args) { if(!this->is_array()) { detail::throw_bad_cast( "toml::value::emplace_back(...): ", this->type_, *this); } this->as_array(std::nothrow).emplace_back(std::forward(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( "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( "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 friend region_base const* detail::get_region(const Value& v); template friend void detail::change_region(Value& v, region reg); private: using array_storage = detail::storage; using table_storage = detail::storage; 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_info_; comment_type comments_; }; // default toml::value and default array/table. using value = basic_value; using array = typename value::array_type; using table = typename value::table_type; template class T, template class A> inline bool operator==(const basic_value& lhs, const basic_value& 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 class T, template class A> inline bool operator!=(const basic_value& lhs, const basic_value& rhs) { return !(lhs == rhs); } template class T, template class A> typename std::enable_if::array_type>, detail::is_comparable::table_type> >::value, bool>::type operator<(const basic_value& lhs, const basic_value& 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 class T, template class A> typename std::enable_if::array_type>, detail::is_comparable::table_type> >::value, bool>::type operator<=(const basic_value& lhs, const basic_value& rhs) { return (lhs < rhs) || (lhs == rhs); } template class T, template class A> typename std::enable_if::array_type>, detail::is_comparable::table_type> >::value, bool>::type operator>(const basic_value& lhs, const basic_value& rhs) { return !(lhs <= rhs); } template class T, template class A> typename std::enable_if::array_type>, detail::is_comparable::table_type> >::value, bool>::type operator>=(const basic_value& lhs, const basic_value& rhs) { return !(lhs < rhs); } template class T, template class A> inline std::string format_error(const std::string& err_msg, const basic_value& v, const std::string& comment, std::vector hints = {}, const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { return detail::format_underline(err_msg, {{v.location(), comment}}, std::move(hints), colorize); } template class T, template class A> inline std::string format_error(const std::string& err_msg, const toml::basic_value& v1, const std::string& comment1, const toml::basic_value& v2, const std::string& comment2, std::vector 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 class T, template class A> inline std::string format_error(const std::string& err_msg, const toml::basic_value& v1, const std::string& comment1, const toml::basic_value& v2, const std::string& comment2, const toml::basic_value& v3, const std::string& comment3, std::vector 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 class T, template class A> detail::return_type_of_t visit(Visitor&& visitor, const toml::basic_value& 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 class T, template class A> detail::return_type_of_t visit(Visitor&& visitor, toml::basic_value& 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 class T, template class A> detail::return_type_of_t visit(Visitor&& visitor, toml::basic_value&& 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