#ifndef TOML11_VALUE_HPP #define TOML11_VALUE_HPP #include "color.hpp" #include "datetime.hpp" #include "exception.hpp" #include "error_info.hpp" #include "format.hpp" #include "region.hpp" #include "source_location.hpp" #include "storage.hpp" #include "traits.hpp" #include "value_t.hpp" #include "version.hpp" // IWYU pragma: keep < TOML11_HAS_STRING_VIEW #ifdef TOML11_HAS_STRING_VIEW #include #endif #ifdef TOML11_ENABLE_ACCESS_CHECK #include #endif #include namespace toml { inline namespace TOML11_INLINE_VERSION_NAMESPACE { template class basic_value; struct type_error final : public ::toml::exception { public: type_error(std::string what_arg, source_location loc) : what_(std::move(what_arg)), loc_(std::move(loc)) {} ~type_error() noexcept override = default; const char* what() const noexcept override {return what_.c_str();} source_location const& location() const noexcept {return loc_;} private: std::string what_; source_location loc_; }; // only for internal use namespace detail { template error_info make_type_error(const basic_value&, const std::string&, const value_t); template error_info make_not_found_error(const basic_value&, const std::string&, const typename basic_value::key_type&); template void change_region_of_value(basic_value&, const basic_value&); template struct getter; #ifdef TOML11_ENABLE_ACCESS_CHECK template void unset_access_flag(basic_value&); #endif } // detail template class basic_value { public: using config_type = TypeConfig; using key_type = typename config_type::string_type; using value_type = basic_value; using boolean_type = typename config_type::boolean_type; using integer_type = typename config_type::integer_type; using floating_type = typename config_type::floating_type; using string_type = typename config_type::string_type; 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 = typename config_type::template array_type; using table_type = typename config_type::template table_type; using comment_type = typename config_type::comment_type; using char_type = typename string_type::value_type; private: using region_type = detail::region; public: basic_value() noexcept : type_(value_t::empty), empty_('\0'), region_{}, comments_{} #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} ~basic_value() noexcept {this->cleanup();} // copy/move constructor/assigner ===================================== {{{ basic_value(const basic_value& v) : type_(v.type_), region_(v.region_), comments_(v.comments_) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{v.accessed()} #endif { 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 : assigner(empty_ , '\0' ); break; } } basic_value(basic_value&& v) : type_(v.type()), region_(std::move(v.region_)), comments_(std::move(v.comments_)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{v.accessed()} #endif { 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 : assigner(empty_ , '\0' ); break; } } basic_value& operator=(const basic_value& v) { if(this == std::addressof(v)) {return *this;} this->cleanup(); this->type_ = v.type_; this->region_ = v.region_; this->comments_ = v.comments_; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = v.accessed(); #endif 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 : assigner(empty_ , '\0' ); break; } return *this; } basic_value& operator=(basic_value&& v) { if(this == std::addressof(v)) {return *this;} this->cleanup(); this->type_ = v.type_; this->region_ = std::move(v.region_); this->comments_ = std::move(v.comments_); #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = v.accessed(); #endif 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 : assigner(empty_ , '\0' ); break; } return *this; } // }}} // constructor to overwrite commnets ================================== {{{ basic_value(basic_value v, std::vector com) : type_(v.type()), region_(std::move(v.region_)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{v.accessed()} #endif { 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 : assigner(empty_ , '\0' ); break; } } // }}} // conversion between different basic_values ========================== {{{ template basic_value(basic_value other) : type_(other.type_), region_(std::move(other.region_)), comments_(std::move(other.comments_)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{other.accessed()} #endif { switch(other.type_) { // use auto-convert in constructor case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; case value_t::string : assigner(string_ , std::move(other.string_ )); break; case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; // may have different container type case value_t::array : { array_type tmp( std::make_move_iterator(other.array_.value.get().begin()), std::make_move_iterator(other.array_.value.get().end())); assigner(array_, array_storage( detail::storage(std::move(tmp)), other.array_.format )); break; } case value_t::table : { table_type tmp( std::make_move_iterator(other.table_.value.get().begin()), std::make_move_iterator(other.table_.value.get().end())); assigner(table_, table_storage( detail::storage(std::move(tmp)), other.table_.format )); break; } default: break; } } template basic_value(basic_value other, std::vector com) : type_(other.type_), region_(std::move(other.region_)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{other.accessed()} #endif { switch(other.type_) { // use auto-convert in constructor case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; case value_t::string : assigner(string_ , std::move(other.string_ )); break; case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; // may have different container type case value_t::array : { array_type tmp( std::make_move_iterator(other.array_.value.get().begin()), std::make_move_iterator(other.array_.value.get().end())); assigner(array_, array_storage( detail::storage(std::move(tmp)), other.array_.format )); break; } case value_t::table : { table_type tmp( std::make_move_iterator(other.table_.value.get().begin()), std::make_move_iterator(other.table_.value.get().end())); assigner(table_, table_storage( detail::storage(std::move(tmp)), other.table_.format )); break; } default: break; } } template basic_value& operator=(basic_value other) { this->cleanup(); this->region_ = other.region_; this->comments_ = comment_type(other.comments_); this->type_ = other.type_; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = other.accessed(); #endif switch(other.type_) { // use auto-convert in constructor case value_t::boolean : assigner(boolean_ , std::move(other.boolean_ )); break; case value_t::integer : assigner(integer_ , std::move(other.integer_ )); break; case value_t::floating : assigner(floating_ , std::move(other.floating_ )); break; case value_t::string : assigner(string_ , std::move(other.string_ )); break; case value_t::offset_datetime: assigner(offset_datetime_, std::move(other.offset_datetime_)); break; case value_t::local_datetime : assigner(local_datetime_ , std::move(other.local_datetime_ )); break; case value_t::local_date : assigner(local_date_ , std::move(other.local_date_ )); break; case value_t::local_time : assigner(local_time_ , std::move(other.local_time_ )); break; // may have different container type case value_t::array : { array_type tmp( std::make_move_iterator(other.array_.value.get().begin()), std::make_move_iterator(other.array_.value.get().end())); assigner(array_, array_storage( detail::storage(std::move(tmp)), other.array_.format )); break; } case value_t::table : { table_type tmp( std::make_move_iterator(other.table_.value.get().begin()), std::make_move_iterator(other.table_.value.get().end())); assigner(table_, table_storage( detail::storage(std::move(tmp)), other.table_.format )); break; } default: break; } return *this; } // }}} // constructor (boolean) ============================================== {{{ basic_value(boolean_type x) : basic_value(x, boolean_format_info{}, std::vector{}, region_type{}) {} basic_value(boolean_type x, boolean_format_info fmt) : basic_value(x, fmt, std::vector{}, region_type{}) {} basic_value(boolean_type x, std::vector com) : basic_value(x, boolean_format_info{}, std::move(com), region_type{}) {} basic_value(boolean_type x, boolean_format_info fmt, std::vector com) : basic_value(x, fmt, std::move(com), region_type{}) {} basic_value(boolean_type x, boolean_format_info fmt, std::vector com, region_type reg) : type_(value_t::boolean), boolean_(boolean_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(boolean_type x) { boolean_format_info fmt; if(this->is_boolean()) { fmt = this->as_boolean_fmt(); } this->cleanup(); this->type_ = value_t::boolean; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->boolean_, boolean_storage(x, fmt)); return *this; } // }}} // constructor (integer) ============================================== {{{ basic_value(integer_type x) : basic_value(std::move(x), integer_format_info{}, std::vector{}, region_type{}) {} basic_value(integer_type x, integer_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} basic_value(integer_type x, std::vector com) : basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{}) {} basic_value(integer_type x, integer_format_info fmt, std::vector com) : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) {} basic_value(integer_type x, integer_format_info fmt, std::vector com, region_type reg) : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(integer_type x) { integer_format_info fmt; if(this->is_integer()) { fmt = this->as_integer_fmt(); } this->cleanup(); this->type_ = value_t::integer; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->integer_, integer_storage(std::move(x), std::move(fmt))); return *this; } private: template using enable_if_integer_like_t = cxx::enable_if_t, boolean_type>>, cxx::negation, integer_type>>, std::is_integral> >::value, std::nullptr_t>; public: template = nullptr> basic_value(T x) : basic_value(std::move(x), integer_format_info{}, std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, integer_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, std::vector com) : basic_value(std::move(x), integer_format_info{}, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, integer_format_info fmt, std::vector com) : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) {} template = nullptr> basic_value(T x, integer_format_info fmt, std::vector com, region_type reg) : type_(value_t::integer), integer_(integer_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} template = nullptr> basic_value& operator=(T x) { integer_format_info fmt; if(this->is_integer()) { fmt = this->as_integer_fmt(); } this->cleanup(); this->type_ = value_t::integer; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->integer_, integer_storage(x, std::move(fmt))); return *this; } // }}} // constructor (floating) ============================================= {{{ basic_value(floating_type x) : basic_value(std::move(x), floating_format_info{}, std::vector{}, region_type{}) {} basic_value(floating_type x, floating_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} basic_value(floating_type x, std::vector com) : basic_value(std::move(x), floating_format_info{}, std::move(com), region_type{}) {} basic_value(floating_type x, floating_format_info fmt, std::vector com) : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) {} basic_value(floating_type x, floating_format_info fmt, std::vector com, region_type reg) : type_(value_t::floating), floating_(floating_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(floating_type x) { floating_format_info fmt; if(this->is_floating()) { fmt = this->as_floating_fmt(); } this->cleanup(); this->type_ = value_t::floating; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->floating_, floating_storage(std::move(x), std::move(fmt))); return *this; } private: template using enable_if_floating_like_t = cxx::enable_if_t, floating_type>>, std::is_floating_point> >::value, std::nullptr_t>; public: template = nullptr> basic_value(T x) : basic_value(x, floating_format_info{}, std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, floating_format_info fmt) : basic_value(x, std::move(fmt), std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, std::vector com) : basic_value(x, floating_format_info{}, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, floating_format_info fmt, std::vector com) : basic_value(x, std::move(fmt), std::move(com), region_type{}) {} template = nullptr> basic_value(T x, floating_format_info fmt, std::vector com, region_type reg) : type_(value_t::floating), floating_(floating_storage(x, std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} template = nullptr> basic_value& operator=(T x) { floating_format_info fmt; if(this->is_floating()) { fmt = this->as_floating_fmt(); } this->cleanup(); this->type_ = value_t::floating; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->floating_, floating_storage(x, std::move(fmt))); return *this; } // }}} // constructor (string) =============================================== {{{ basic_value(string_type x) : basic_value(std::move(x), string_format_info{}, std::vector{}, region_type{}) {} basic_value(string_type x, string_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} basic_value(string_type x, std::vector com) : basic_value(std::move(x), string_format_info{}, std::move(com), region_type{}) {} basic_value(string_type x, string_format_info fmt, std::vector com) : basic_value(std::move(x), std::move(fmt), std::move(com), region_type{}) {} basic_value(string_type x, string_format_info fmt, std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(std::move(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(string_type x) { string_format_info fmt; if(this->is_string()) { fmt = this->as_string_fmt(); } this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->string_, string_storage(x, std::move(fmt))); return *this; } // "string literal" basic_value(const typename string_type::value_type* x) : basic_value(x, string_format_info{}, std::vector{}, region_type{}) {} basic_value(const typename string_type::value_type* x, string_format_info fmt) : basic_value(x, std::move(fmt), std::vector{}, region_type{}) {} basic_value(const typename string_type::value_type* x, std::vector com) : basic_value(x, string_format_info{}, std::move(com), region_type{}) {} basic_value(const typename string_type::value_type* x, string_format_info fmt, std::vector com) : basic_value(x, std::move(fmt), std::move(com), region_type{}) {} basic_value(const typename string_type::value_type* x, string_format_info fmt, std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(const typename string_type::value_type* x) { string_format_info fmt; if(this->is_string()) { fmt = this->as_string_fmt(); } this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->string_, string_storage(string_type(x), std::move(fmt))); return *this; } #if defined(TOML11_HAS_STRING_VIEW) using string_view_type = std::basic_string_view< typename string_type::value_type, typename string_type::traits_type>; basic_value(string_view_type x) : basic_value(x, string_format_info{}, std::vector{}, region_type{}) {} basic_value(string_view_type x, string_format_info fmt) : basic_value(x, std::move(fmt), std::vector{}, region_type{}) {} basic_value(string_view_type x, std::vector com) : basic_value(x, string_format_info{}, std::move(com), region_type{}) {} basic_value(string_view_type x, string_format_info fmt, std::vector com) : basic_value(x, std::move(fmt), std::move(com), region_type{}) {} basic_value(string_view_type x, string_format_info fmt, std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(string_type(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(string_view_type x) { string_format_info fmt; if(this->is_string()) { fmt = this->as_string_fmt(); } this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->string_, string_storage(string_type(x), std::move(fmt))); return *this; } #endif // TOML11_HAS_STRING_VIEW template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value(const T& x) : basic_value(x, string_format_info{}, std::vector{}, region_type{}) {} template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value(const T& x, string_format_info fmt) : basic_value(x, std::move(fmt), std::vector{}, region_type{}) {} template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value(const T& x, std::vector com) : basic_value(x, string_format_info{}, std::move(com), region_type{}) {} template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value(const T& x, string_format_info fmt, std::vector com) : basic_value(x, std::move(fmt), std::move(com), region_type{}) {} template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value(const T& x, string_format_info fmt, std::vector com, region_type reg) : type_(value_t::string), string_(string_storage(detail::string_conv(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} template, string_type>>, detail::is_1byte_std_basic_string >::value, std::nullptr_t> = nullptr> basic_value& operator=(const T& x) { string_format_info fmt; if(this->is_string()) { fmt = this->as_string_fmt(); } this->cleanup(); this->type_ = value_t::string; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->string_, string_storage(detail::string_conv(x), std::move(fmt))); return *this; } // }}} // constructor (local_date) =========================================== {{{ basic_value(local_date_type x) : basic_value(x, local_date_format_info{}, std::vector{}, region_type{}) {} basic_value(local_date_type x, local_date_format_info fmt) : basic_value(x, fmt, std::vector{}, region_type{}) {} basic_value(local_date_type x, std::vector com) : basic_value(x, local_date_format_info{}, std::move(com), region_type{}) {} basic_value(local_date_type x, local_date_format_info fmt, std::vector com) : basic_value(x, fmt, std::move(com), region_type{}) {} basic_value(local_date_type x, local_date_format_info fmt, std::vector com, region_type reg) : type_(value_t::local_date), local_date_(local_date_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(local_date_type x) { local_date_format_info fmt; if(this->is_local_date()) { fmt = this->as_local_date_fmt(); } this->cleanup(); this->type_ = value_t::local_date; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->local_date_, local_date_storage(x, fmt)); return *this; } // }}} // constructor (local_time) =========================================== {{{ basic_value(local_time_type x) : basic_value(x, local_time_format_info{}, std::vector{}, region_type{}) {} basic_value(local_time_type x, local_time_format_info fmt) : basic_value(x, fmt, std::vector{}, region_type{}) {} basic_value(local_time_type x, std::vector com) : basic_value(x, local_time_format_info{}, std::move(com), region_type{}) {} basic_value(local_time_type x, local_time_format_info fmt, std::vector com) : basic_value(x, fmt, std::move(com), region_type{}) {} basic_value(local_time_type x, local_time_format_info fmt, std::vector com, region_type reg) : type_(value_t::local_time), local_time_(local_time_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(local_time_type x) { local_time_format_info fmt; if(this->is_local_time()) { fmt = this->as_local_time_fmt(); } this->cleanup(); this->type_ = value_t::local_time; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->local_time_, local_time_storage(x, fmt)); return *this; } template basic_value(const std::chrono::duration& x) : basic_value(local_time_type(x), local_time_format_info{}, std::vector{}, region_type{}) {} template basic_value(const std::chrono::duration& x, local_time_format_info fmt) : basic_value(local_time_type(x), std::move(fmt), std::vector{}, region_type{}) {} template basic_value(const std::chrono::duration& x, std::vector com) : basic_value(local_time_type(x), local_time_format_info{}, std::move(com), region_type{}) {} template basic_value(const std::chrono::duration& x, local_time_format_info fmt, std::vector com) : basic_value(local_time_type(x), std::move(fmt), std::move(com), region_type{}) {} template basic_value(const std::chrono::duration& x, local_time_format_info fmt, std::vector com, region_type reg) : basic_value(local_time_type(x), std::move(fmt), std::move(com), std::move(reg)) {} template basic_value& operator=(const std::chrono::duration& x) { local_time_format_info fmt; if(this->is_local_time()) { fmt = this->as_local_time_fmt(); } this->cleanup(); this->type_ = value_t::local_time; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->local_time_, local_time_storage(local_time_type(x), std::move(fmt))); return *this; } // }}} // constructor (local_datetime) =========================================== {{{ basic_value(local_datetime_type x) : basic_value(x, local_datetime_format_info{}, std::vector{}, region_type{}) {} basic_value(local_datetime_type x, local_datetime_format_info fmt) : basic_value(x, fmt, std::vector{}, region_type{}) {} basic_value(local_datetime_type x, std::vector com) : basic_value(x, local_datetime_format_info{}, std::move(com), region_type{}) {} basic_value(local_datetime_type x, local_datetime_format_info fmt, std::vector com) : basic_value(x, fmt, std::move(com), region_type{}) {} basic_value(local_datetime_type x, local_datetime_format_info fmt, std::vector com, region_type reg) : type_(value_t::local_datetime), local_datetime_(local_datetime_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(local_datetime_type x) { local_datetime_format_info fmt; if(this->is_local_datetime()) { fmt = this->as_local_datetime_fmt(); } this->cleanup(); this->type_ = value_t::local_datetime; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->local_datetime_, local_datetime_storage(x, fmt)); return *this; } // }}} // constructor (offset_datetime) =========================================== {{{ basic_value(offset_datetime_type x) : basic_value(x, offset_datetime_format_info{}, std::vector{}, region_type{}) {} basic_value(offset_datetime_type x, offset_datetime_format_info fmt) : basic_value(x, fmt, std::vector{}, region_type{}) {} basic_value(offset_datetime_type x, std::vector com) : basic_value(x, offset_datetime_format_info{}, std::move(com), region_type{}) {} basic_value(offset_datetime_type x, offset_datetime_format_info fmt, std::vector com) : basic_value(x, fmt, std::move(com), region_type{}) {} basic_value(offset_datetime_type x, offset_datetime_format_info fmt, std::vector com, region_type reg) : type_(value_t::offset_datetime), offset_datetime_(offset_datetime_storage(x, fmt)), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(offset_datetime_type x) { offset_datetime_format_info fmt; if(this->is_offset_datetime()) { fmt = this->as_offset_datetime_fmt(); } this->cleanup(); this->type_ = value_t::offset_datetime; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->offset_datetime_, offset_datetime_storage(x, fmt)); return *this; } // system_clock::time_point basic_value(std::chrono::system_clock::time_point x) : basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::vector{}, region_type{}) {} basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt) : basic_value(offset_datetime_type(x), fmt, std::vector{}, region_type{}) {} basic_value(std::chrono::system_clock::time_point x, std::vector com) : basic_value(offset_datetime_type(x), offset_datetime_format_info{}, std::move(com), region_type{}) {} basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt, std::vector com) : basic_value(offset_datetime_type(x), fmt, std::move(com), region_type{}) {} basic_value(std::chrono::system_clock::time_point x, offset_datetime_format_info fmt, std::vector com, region_type reg) : basic_value(offset_datetime_type(x), std::move(fmt), std::move(com), std::move(reg)) {} basic_value& operator=(std::chrono::system_clock::time_point x) { offset_datetime_format_info fmt; if(this->is_offset_datetime()) { fmt = this->as_offset_datetime_fmt(); } this->cleanup(); this->type_ = value_t::offset_datetime; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->offset_datetime_, offset_datetime_storage(offset_datetime_type(x), fmt)); return *this; } // }}} // constructor (array) ================================================ {{{ basic_value(array_type x) : basic_value(std::move(x), array_format_info{}, std::vector{}, region_type{}) {} basic_value(array_type x, array_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} basic_value(array_type x, std::vector com) : basic_value(std::move(x), array_format_info{}, std::move(com), region_type{}) {} basic_value(array_type x, array_format_info fmt, std::vector com) : basic_value(std::move(x), fmt, std::move(com), region_type{}) {} basic_value(array_type x, array_format_info fmt, std::vector com, region_type reg) : type_(value_t::array), array_(array_storage( detail::storage(std::move(x)), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(array_type x) { array_format_info fmt; if(this->is_array()) { fmt = this->as_array_fmt(); } this->cleanup(); this->type_ = value_t::array; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->array_, array_storage( detail::storage(std::move(x)), std::move(fmt))); return *this; } private: template using enable_if_array_like_t = cxx::enable_if_t, cxx::negation>, cxx::negation>, #if defined(TOML11_HAS_STRING_VIEW) cxx::negation>, #endif cxx::negation>, cxx::negation> >::value, std::nullptr_t>; public: template = nullptr> basic_value(T x) : basic_value(std::move(x), array_format_info{}, std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, array_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, std::vector com) : basic_value(std::move(x), array_format_info{}, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, array_format_info fmt, std::vector com) : basic_value(std::move(x), fmt, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, array_format_info fmt, std::vector com, region_type reg) : type_(value_t::array), array_(array_storage( detail::storage(array_type( std::make_move_iterator(x.begin()), std::make_move_iterator(x.end())) ), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} template = nullptr> basic_value& operator=(T x) { array_format_info fmt; if(this->is_array()) { fmt = this->as_array_fmt(); } this->cleanup(); this->type_ = value_t::array; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif array_type a(std::make_move_iterator(x.begin()), std::make_move_iterator(x.end())); assigner(this->array_, array_storage( detail::storage(std::move(a)), std::move(fmt))); return *this; } // }}} // constructor (table) ================================================ {{{ basic_value(table_type x) : basic_value(std::move(x), table_format_info{}, std::vector{}, region_type{}) {} basic_value(table_type x, table_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} basic_value(table_type x, std::vector com) : basic_value(std::move(x), table_format_info{}, std::move(com), region_type{}) {} basic_value(table_type x, table_format_info fmt, std::vector com) : basic_value(std::move(x), fmt, std::move(com), region_type{}) {} basic_value(table_type x, table_format_info fmt, std::vector com, region_type reg) : type_(value_t::table), table_(table_storage( detail::storage(std::move(x)), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} basic_value& operator=(table_type x) { table_format_info fmt; if(this->is_table()) { fmt = this->as_table_fmt(); } this->cleanup(); this->type_ = value_t::table; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif assigner(this->table_, table_storage( detail::storage(std::move(x)), std::move(fmt))); return *this; } // table-like private: template using enable_if_table_like_t = cxx::enable_if_t>, detail::is_map, cxx::negation>, cxx::negation> >::value, std::nullptr_t>; public: template = nullptr> basic_value(T x) : basic_value(std::move(x), table_format_info{}, std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, table_format_info fmt) : basic_value(std::move(x), std::move(fmt), std::vector{}, region_type{}) {} template = nullptr> basic_value(T x, std::vector com) : basic_value(std::move(x), table_format_info{}, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, table_format_info fmt, std::vector com) : basic_value(std::move(x), fmt, std::move(com), region_type{}) {} template = nullptr> basic_value(T x, table_format_info fmt, std::vector com, region_type reg) : type_(value_t::table), table_(table_storage( detail::storage(table_type( std::make_move_iterator(x.begin()), std::make_move_iterator(x.end()) )), std::move(fmt) )), region_(std::move(reg)), comments_(std::move(com)) #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} template = nullptr> basic_value& operator=(T x) { table_format_info fmt; if(this->is_table()) { fmt = this->as_table_fmt(); } this->cleanup(); this->type_ = value_t::table; this->region_ = region_type{}; #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif table_type t(std::make_move_iterator(x.begin()), std::make_move_iterator(x.end())); assigner(this->table_, table_storage( detail::storage(std::move(t)), std::move(fmt))); return *this; } // }}} // constructor (user_defined) ========================================= {{{ template::value, std::nullptr_t> = nullptr> basic_value(const T& ud) : basic_value( into>::template into_toml(ud)) {} template::value, std::nullptr_t> = nullptr> basic_value(const T& ud, std::vector com) : basic_value( into>::template into_toml(ud), std::move(com)) {} template::value, std::nullptr_t> = nullptr> basic_value& operator=(const T& ud) { *this = into>::template into_toml(ud); #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif return *this; } template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value(const T& ud): basic_value(ud.into_toml()) {} template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value(const T& ud, std::vector com) : basic_value(ud.into_toml(), std::move(com)) {} template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value& operator=(const T& ud) { *this = ud.into_toml(); #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif return *this; } template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value(const T& ud): basic_value(ud.template into_toml()) {} template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value(const T& ud, std::vector com) : basic_value(ud.template into_toml(), std::move(com)) {} template, cxx::negation> >::value, std::nullptr_t> = nullptr> basic_value& operator=(const T& ud) { *this = ud.template into_toml(); #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif return *this; } // }}} // empty value with region info ======================================= {{{ // mainly for `null` extension basic_value(detail::none_t, region_type reg) noexcept : type_(value_t::empty), empty_('\0'), region_(std::move(reg)), comments_{} #ifdef TOML11_ENABLE_ACCESS_CHECK , accessed_{false} #endif {} // }}} // type checking ====================================================== {{{ template, value_type>::value, std::nullptr_t> = nullptr> bool is() const noexcept { return this->is(detail::type_to_enum::value); } bool is(value_t t) const noexcept { this->set_accessed(); return t == this->type_; } bool is_empty() 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 );} bool is_array_of_tables() const noexcept { this->set_accessed(); if( ! this->is_array()) {return false;} const auto& a = this->as_array(std::nothrow); // already checked. // when you define [[array.of.tables]], at least one empty table will be // assigned. In case of array of inline tables, `array_of_tables = []`, // there is no reason to consider this as an array of *tables*. // So empty array is not an array-of-tables. if(a.empty()) {return false;} // since toml v1.0.0 allows array of heterogeneous types, we need to // check all the elements. if any of the elements is not a table, it // is a heterogeneous array and cannot be expressed by `[[aot]]` form. for(const auto& e : a) { if( ! e.is_table()) {return false;} } return true; } value_t type() const noexcept { this->set_accessed(); return type_; } // }}} // as_xxx (noexcept) version ========================================== {{{ template detail::enum_to_type_t> const& as(const std::nothrow_t&) const noexcept { this->set_accessed(); return detail::getter::get_nothrow(*this); } template detail::enum_to_type_t>& as(const std::nothrow_t&) noexcept { this->set_accessed(); return detail::getter::get_nothrow(*this); } boolean_type const& as_boolean (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->boolean_.value;} integer_type const& as_integer (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->integer_.value;} floating_type const& as_floating (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->floating_.value;} string_type const& as_string (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->string_.value;} offset_datetime_type const& as_offset_datetime(const std::nothrow_t&) const noexcept {this->set_accessed(); return this->offset_datetime_.value;} local_datetime_type const& as_local_datetime (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_datetime_.value;} local_date_type const& as_local_date (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_date_.value;} local_time_type const& as_local_time (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->local_time_.value;} array_type const& as_array (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->array_.value.get();} table_type const& as_table (const std::nothrow_t&) const noexcept {this->set_accessed(); return this->table_.value.get();} boolean_type & as_boolean (const std::nothrow_t&) noexcept {this->set_accessed(); return this->boolean_.value;} integer_type & as_integer (const std::nothrow_t&) noexcept {this->set_accessed(); return this->integer_.value;} floating_type & as_floating (const std::nothrow_t&) noexcept {this->set_accessed(); return this->floating_.value;} string_type & as_string (const std::nothrow_t&) noexcept {this->set_accessed(); return this->string_.value;} offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept {this->set_accessed(); return this->offset_datetime_.value;} local_datetime_type & as_local_datetime (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_datetime_.value;} local_date_type & as_local_date (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_date_.value;} local_time_type & as_local_time (const std::nothrow_t&) noexcept {this->set_accessed(); return this->local_time_.value;} array_type & as_array (const std::nothrow_t&) noexcept {this->set_accessed(); return this->array_.value.get();} table_type & as_table (const std::nothrow_t&) noexcept {this->set_accessed(); return this->table_.value.get();} // }}} // as_xxx (throw) ===================================================== {{{ template detail::enum_to_type_t> const& as() const { return detail::getter::get(*this); } template detail::enum_to_type_t>& as() { return detail::getter::get(*this); } boolean_type const& as_boolean() const { if(this->type_ != value_t::boolean) { this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); } this->set_accessed(); return this->boolean_.value; } integer_type const& as_integer() const { if(this->type_ != value_t::integer) { this->throw_bad_cast("toml::value::as_integer()", value_t::integer); } this->set_accessed(); return this->integer_.value; } floating_type const& as_floating() const { if(this->type_ != value_t::floating) { this->throw_bad_cast("toml::value::as_floating()", value_t::floating); } this->set_accessed(); return this->floating_.value; } string_type const& as_string() const { if(this->type_ != value_t::string) { this->throw_bad_cast("toml::value::as_string()", value_t::string); } this->set_accessed(); return this->string_.value; } offset_datetime_type const& as_offset_datetime() const { if(this->type_ != value_t::offset_datetime) { this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); } this->set_accessed(); return this->offset_datetime_.value; } local_datetime_type const& as_local_datetime() const { if(this->type_ != value_t::local_datetime) { this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); } this->set_accessed(); return this->local_datetime_.value; } local_date_type const& as_local_date() const { if(this->type_ != value_t::local_date) { this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); } this->set_accessed(); return this->local_date_.value; } local_time_type const& as_local_time() const { if(this->type_ != value_t::local_time) { this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); } this->set_accessed(); return this->local_time_.value; } array_type const& as_array() const { if(this->type_ != value_t::array) { this->throw_bad_cast("toml::value::as_array()", value_t::array); } this->set_accessed(); return this->array_.value.get(); } table_type const& as_table() const { if(this->type_ != value_t::table) { this->throw_bad_cast("toml::value::as_table()", value_t::table); } this->set_accessed(); return this->table_.value.get(); } // ------------------------------------------------------------------------ // nonconst reference boolean_type& as_boolean() { if(this->type_ != value_t::boolean) { this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); } this->set_accessed(); return this->boolean_.value; } integer_type& as_integer() { if(this->type_ != value_t::integer) { this->throw_bad_cast("toml::value::as_integer()", value_t::integer); } this->set_accessed(); return this->integer_.value; } floating_type& as_floating() { if(this->type_ != value_t::floating) { this->throw_bad_cast("toml::value::as_floating()", value_t::floating); } this->set_accessed(); return this->floating_.value; } string_type& as_string() { if(this->type_ != value_t::string) { this->throw_bad_cast("toml::value::as_string()", value_t::string); } this->set_accessed(); return this->string_.value; } offset_datetime_type& as_offset_datetime() { if(this->type_ != value_t::offset_datetime) { this->throw_bad_cast("toml::value::as_offset_datetime()", value_t::offset_datetime); } this->set_accessed(); return this->offset_datetime_.value; } local_datetime_type& as_local_datetime() { if(this->type_ != value_t::local_datetime) { this->throw_bad_cast("toml::value::as_local_datetime()", value_t::local_datetime); } this->set_accessed(); return this->local_datetime_.value; } local_date_type& as_local_date() { if(this->type_ != value_t::local_date) { this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); } this->set_accessed(); return this->local_date_.value; } local_time_type& as_local_time() { if(this->type_ != value_t::local_time) { this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); } this->set_accessed(); return this->local_time_.value; } array_type& as_array() { if(this->type_ != value_t::array) { this->throw_bad_cast("toml::value::as_array()", value_t::array); } this->set_accessed(); return this->array_.value.get(); } table_type& as_table() { if(this->type_ != value_t::table) { this->throw_bad_cast("toml::value::as_table()", value_t::table); } this->set_accessed(); return this->table_.value.get(); } // }}} // format accessors (noexcept) ======================================== {{{ template detail::enum_to_fmt_type_t const& as_fmt(const std::nothrow_t&) const noexcept { return detail::getter::get_fmt_nothrow(*this); } template detail::enum_to_fmt_type_t& as_fmt(const std::nothrow_t&) noexcept { return detail::getter::get_fmt_nothrow(*this); } boolean_format_info & as_boolean_fmt (const std::nothrow_t&) noexcept {return this->boolean_.format;} integer_format_info & as_integer_fmt (const std::nothrow_t&) noexcept {return this->integer_.format;} floating_format_info & as_floating_fmt (const std::nothrow_t&) noexcept {return this->floating_.format;} string_format_info & as_string_fmt (const std::nothrow_t&) noexcept {return this->string_.format;} offset_datetime_format_info& as_offset_datetime_fmt(const std::nothrow_t&) noexcept {return this->offset_datetime_.format;} local_datetime_format_info & as_local_datetime_fmt (const std::nothrow_t&) noexcept {return this->local_datetime_.format;} local_date_format_info & as_local_date_fmt (const std::nothrow_t&) noexcept {return this->local_date_.format;} local_time_format_info & as_local_time_fmt (const std::nothrow_t&) noexcept {return this->local_time_.format;} array_format_info & as_array_fmt (const std::nothrow_t&) noexcept {return this->array_.format;} table_format_info & as_table_fmt (const std::nothrow_t&) noexcept {return this->table_.format;} boolean_format_info const& as_boolean_fmt (const std::nothrow_t&) const noexcept {return this->boolean_.format;} integer_format_info const& as_integer_fmt (const std::nothrow_t&) const noexcept {return this->integer_.format;} floating_format_info const& as_floating_fmt (const std::nothrow_t&) const noexcept {return this->floating_.format;} string_format_info const& as_string_fmt (const std::nothrow_t&) const noexcept {return this->string_.format;} offset_datetime_format_info const& as_offset_datetime_fmt(const std::nothrow_t&) const noexcept {return this->offset_datetime_.format;} local_datetime_format_info const& as_local_datetime_fmt (const std::nothrow_t&) const noexcept {return this->local_datetime_.format;} local_date_format_info const& as_local_date_fmt (const std::nothrow_t&) const noexcept {return this->local_date_.format;} local_time_format_info const& as_local_time_fmt (const std::nothrow_t&) const noexcept {return this->local_time_.format;} array_format_info const& as_array_fmt (const std::nothrow_t&) const noexcept {return this->array_.format;} table_format_info const& as_table_fmt (const std::nothrow_t&) const noexcept {return this->table_.format;} // }}} // format accessors (throw) =========================================== {{{ template detail::enum_to_fmt_type_t const& as_fmt() const { return detail::getter::get_fmt(*this); } template detail::enum_to_fmt_type_t& as_fmt() { return detail::getter::get_fmt(*this); } boolean_format_info const& as_boolean_fmt() const { if(this->type_ != value_t::boolean) { this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); } return this->boolean_.format; } integer_format_info const& as_integer_fmt() const { if(this->type_ != value_t::integer) { this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); } return this->integer_.format; } floating_format_info const& as_floating_fmt() const { if(this->type_ != value_t::floating) { this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); } return this->floating_.format; } string_format_info const& as_string_fmt() const { if(this->type_ != value_t::string) { this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); } return this->string_.format; } offset_datetime_format_info const& as_offset_datetime_fmt() const { if(this->type_ != value_t::offset_datetime) { this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime); } return this->offset_datetime_.format; } local_datetime_format_info const& as_local_datetime_fmt() const { if(this->type_ != value_t::local_datetime) { this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime); } return this->local_datetime_.format; } local_date_format_info const& as_local_date_fmt() const { if(this->type_ != value_t::local_date) { this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date); } return this->local_date_.format; } local_time_format_info const& as_local_time_fmt() const { if(this->type_ != value_t::local_time) { this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time); } return this->local_time_.format; } array_format_info const& as_array_fmt() const { if(this->type_ != value_t::array) { this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); } return this->array_.format; } table_format_info const& as_table_fmt() const { if(this->type_ != value_t::table) { this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); } return this->table_.format; } // ------------------------------------------------------------------------ // nonconst reference boolean_format_info& as_boolean_fmt() { if(this->type_ != value_t::boolean) { this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); } return this->boolean_.format; } integer_format_info& as_integer_fmt() { if(this->type_ != value_t::integer) { this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); } return this->integer_.format; } floating_format_info& as_floating_fmt() { if(this->type_ != value_t::floating) { this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); } return this->floating_.format; } string_format_info& as_string_fmt() { if(this->type_ != value_t::string) { this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); } return this->string_.format; } offset_datetime_format_info& as_offset_datetime_fmt() { if(this->type_ != value_t::offset_datetime) { this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", value_t::offset_datetime); } return this->offset_datetime_.format; } local_datetime_format_info& as_local_datetime_fmt() { if(this->type_ != value_t::local_datetime) { this->throw_bad_cast("toml::value::as_local_datetime_fmt()", value_t::local_datetime); } return this->local_datetime_.format; } local_date_format_info& as_local_date_fmt() { if(this->type_ != value_t::local_date) { this->throw_bad_cast("toml::value::as_local_date_fmt()", value_t::local_date); } return this->local_date_.format; } local_time_format_info& as_local_time_fmt() { if(this->type_ != value_t::local_time) { this->throw_bad_cast("toml::value::as_local_time_fmt()", value_t::local_time); } return this->local_time_.format; } array_format_info& as_array_fmt() { if(this->type_ != value_t::array) { this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); } return this->array_.format; } table_format_info& as_table_fmt() { if(this->type_ != value_t::table) { this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); } return this->table_.format; } // }}} // table accessors ==================================================== {{{ value_type& at(const key_type& k) { if(!this->is_table()) { this->throw_bad_cast("toml::value::at(key_type)", value_t::table); } auto& table = this->as_table(std::nothrow); const auto found = table.find(k); if(found == table.end()) { this->throw_key_not_found_error("toml::value::at", k); } assert(found->first == k); return found->second; } value_type const& at(const key_type& k) const { if(!this->is_table()) { this->throw_bad_cast("toml::value::at(key_type)", value_t::table); } const auto& table = this->as_table(std::nothrow); const auto found = table.find(k); if(found == table.end()) { this->throw_key_not_found_error("toml::value::at", k); } assert(found->first == k); return found->second; } value_type& operator[](const key_type& k) { if(this->is_empty()) { (*this) = table_type{}; } else if( ! this->is_table()) // initialized, but not a table { this->throw_bad_cast("toml::value::operator[](key_type)", value_t::table); } return (this->as_table(std::nothrow))[k]; } std::size_t count(const key_type& k) const { if(!this->is_table()) { this->throw_bad_cast("toml::value::count(key_type)", value_t::table); } return this->as_table(std::nothrow).count(k); } bool contains(const key_type& k) const { if(!this->is_table()) { this->throw_bad_cast("toml::value::contains(key_type)", value_t::table); } const auto& table = this->as_table(std::nothrow); return table.find(k) != table.end(); } // }}} // array accessors ==================================================== {{{ value_type& at(const std::size_t idx) { if(!this->is_array()) { this->throw_bad_cast("toml::value::at(idx)", value_t::array); } auto& ar = this->as_array(std::nothrow); if(ar.size() <= idx) { std::ostringstream oss; oss << "actual length (" << ar.size() << ") is shorter than the specified index (" << idx << ")."; throw std::out_of_range(format_error( "toml::value::at(idx): no element corresponding to the index", this->location(), oss.str() )); } return ar.at(idx); } value_type const& at(const std::size_t idx) const { if(!this->is_array()) { this->throw_bad_cast("toml::value::at(idx)", value_t::array); } const auto& ar = this->as_array(std::nothrow); if(ar.size() <= idx) { std::ostringstream oss; oss << "actual length (" << ar.size() << ") is shorter than the specified index (" << idx << ")."; throw std::out_of_range(format_error( "toml::value::at(idx): no element corresponding to the index", this->location(), oss.str() )); } return ar.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()) { this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); } this->as_array(std::nothrow).push_back(x); return; } void push_back(value_type&& x) { if(!this->is_array()) { this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); } this->as_array(std::nothrow).push_back(std::move(x)); return; } template value_type& emplace_back(Ts&& ... args) { if(!this->is_array()) { this->throw_bad_cast("toml::value::emplace_back(idx)", value_t::array); } auto& ar = this->as_array(std::nothrow); ar.emplace_back(std::forward(args) ...); return ar.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).size(); } default: { throw type_error(format_error( "toml::value::size(): bad_cast to container types", this->location(), "the actual type is " + to_string(this->type_) ), this->location()); } } } // }}} source_location location() const { return source_location(this->region_); } comment_type const& comments() const noexcept {return this->comments_;} comment_type& comments() noexcept {return this->comments_;} #ifdef TOML11_ENABLE_ACCESS_CHECK bool accessed() const {return this->accessed_.load();} #endif private: // private helper functions =========================================== {{{ void set_accessed() const noexcept { #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_.store(true); #endif return; } void cleanup() noexcept { switch(this->type_) { case value_t::boolean : { boolean_ .~boolean_storage (); break; } case value_t::integer : { integer_ .~integer_storage (); break; } case value_t::floating : { floating_ .~floating_storage (); break; } case value_t::string : { string_ .~string_storage (); break; } case value_t::offset_datetime : { offset_datetime_.~offset_datetime_storage (); break; } case value_t::local_datetime : { local_datetime_ .~local_datetime_storage (); break; } case value_t::local_date : { local_date_ .~local_date_storage (); break; } case value_t::local_time : { local_time_ .~local_time_storage (); break; } case value_t::array : { array_ .~array_storage (); break; } case value_t::table : { table_ .~table_storage (); break; } default : { break; } } #ifdef TOML11_ENABLE_ACCESS_CHECK this->accessed_ = false; #endif this->type_ = value_t::empty; return; } 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; } [[noreturn]] void throw_bad_cast(const std::string& funcname, const value_t ty) const { throw type_error(format_error(detail::make_type_error(*this, funcname, ty)), this->location()); } [[noreturn]] void throw_key_not_found_error(const std::string& funcname, const key_type& key) const { throw std::out_of_range(format_error( detail::make_not_found_error(*this, funcname, key))); } template friend void detail::change_region_of_value(basic_value&, const basic_value&); template friend class basic_value; #ifdef TOML11_ENABLE_ACCESS_CHECK template friend void detail::unset_access_flag(basic_value&); #endif // }}} private: using boolean_storage = detail::value_with_format; using integer_storage = detail::value_with_format; using floating_storage = detail::value_with_format; using string_storage = detail::value_with_format; using offset_datetime_storage = detail::value_with_format; using local_datetime_storage = detail::value_with_format; using local_date_storage = detail::value_with_format; using local_time_storage = detail::value_with_format; using array_storage = detail::value_with_format, array_format_info >; using table_storage = detail::value_with_format, table_format_info >; private: value_t type_; union { char empty_; // the smallest type boolean_storage boolean_; integer_storage integer_; floating_storage floating_; string_storage string_; offset_datetime_storage offset_datetime_; local_datetime_storage local_datetime_; local_date_storage local_date_; local_time_storage local_time_; array_storage array_; table_storage table_; }; region_type region_; comment_type comments_; #ifdef TOML11_ENABLE_ACCESS_CHECK mutable std::atomic accessed_; #endif }; template 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 bool operator!=(const basic_value& lhs, const basic_value& rhs) { return !(lhs == rhs); } template cxx::enable_if_t::array_type>, detail::is_comparable::table_type> >::value, bool> 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 cxx::enable_if_t::array_type>, detail::is_comparable::table_type> >::value, bool> operator<=(const basic_value& lhs, const basic_value& rhs) { return (lhs < rhs) || (lhs == rhs); } template cxx::enable_if_t::array_type>, detail::is_comparable::table_type> >::value, bool> operator>(const basic_value& lhs, const basic_value& rhs) { return !(lhs <= rhs); } template cxx::enable_if_t::array_type>, detail::is_comparable::table_type> >::value, bool> operator>=(const basic_value& lhs, const basic_value& rhs) { return !(lhs < rhs); } // error_info helper namespace detail { template error_info make_error_info_rec(error_info e, const basic_value& v, std::string msg, Ts&& ... tail) { return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward(tail)...); } } // detail template error_info make_error_info( std::string title, const basic_value& v, std::string msg, Ts&& ... tail) { return make_error_info(std::move(title), v.location(), std::move(msg), std::forward(tail)...); } template std::string format_error(std::string title, const basic_value& v, std::string msg, Ts&& ... tail) { return format_error(std::move(title), v.location(), std::move(msg), std::forward(tail)...); } namespace detail { template error_info make_type_error(const basic_value& v, const std::string& fname, const value_t ty) { return make_error_info(fname + ": bad_cast to " + to_string(ty), v.location(), "the actual type is " + to_string(v.type())); } template error_info make_not_found_error(const basic_value& v, const std::string& fname, const typename basic_value::key_type& key) { const auto loc = v.location(); const std::string title = fname + ": key \"" + string_conv(key) + "\" not found"; std::vector> locs; if( ! loc.is_ok()) { return error_info(title, locs); } if(loc.first_line_number() == 1 && loc.first_column_number() == 1 && loc.length() == 1) { // The top-level table has its region at the 0th 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 // the 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". locs.emplace_back(v.location(), "at the top-level table"); } else { locs.emplace_back(v.location(), "in this table"); } return error_info(title, locs); } #define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \ template \ struct getter \ { \ using value_type = basic_value; \ using result_type = enum_to_type_t; \ using format_type = enum_to_fmt_type_t; \ \ static result_type& get(value_type& v) \ { \ return v.as_ ## ty(); \ } \ static result_type const& get(const value_type& v) \ { \ return v.as_ ## ty(); \ } \ \ static result_type& get_nothrow(value_type& v) noexcept \ { \ return v.as_ ## ty(std::nothrow); \ } \ static result_type const& get_nothrow(const value_type& v) noexcept \ { \ return v.as_ ## ty(std::nothrow); \ } \ \ static format_type& get_fmt(value_type& v) \ { \ return v.as_ ## ty ## _fmt(); \ } \ static format_type const& get_fmt(const value_type& v) \ { \ return v.as_ ## ty ## _fmt(); \ } \ \ static format_type& get_fmt_nothrow(value_type& v) noexcept \ { \ return v.as_ ## ty ## _fmt(std::nothrow); \ } \ static format_type const& get_fmt_nothrow(const value_type& v) noexcept \ { \ return v.as_ ## ty ## _fmt(std::nothrow); \ } \ }; TOML11_DETAIL_GENERATE_COMPTIME_GETTER(boolean ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(integer ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(floating ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(string ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(offset_datetime) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_datetime ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_date ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_time ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(array ) TOML11_DETAIL_GENERATE_COMPTIME_GETTER(table ) #undef TOML11_DETAIL_GENERATE_COMPTIME_GETTER template void change_region_of_value(basic_value& dst, const basic_value& src) { dst.region_ = std::move(src.region_); return; } #ifdef TOML11_ENABLE_ACCESS_CHECK template void unset_access_flag(basic_value& v) { v.accessed_.store(false); } template void unset_access_flag_recursively(basic_value& v) { switch(v.type()) { case value_t::empty : { return unset_access_flag(v); } case value_t::boolean : { return unset_access_flag(v); } case value_t::integer : { return unset_access_flag(v); } case value_t::floating : { return unset_access_flag(v); } case value_t::string : { return unset_access_flag(v); } case value_t::offset_datetime : { return unset_access_flag(v); } case value_t::local_datetime : { return unset_access_flag(v); } case value_t::local_date : { return unset_access_flag(v); } case value_t::local_time : { return unset_access_flag(v); } case value_t::array: { for(auto& elem : v.as_array()) { unset_access_flag_recursively(elem); } return unset_access_flag(v); } case value_t::table: { for(auto& kv : v.as_table()) { unset_access_flag_recursively(kv.second); } return unset_access_flag(v); } default: { return unset_access_flag(v); } } } #endif } // namespace detail } // TOML11_INLINE_VERSION_NAMESPACE } // namespace toml #endif // TOML11_VALUE_HPP