diff --git a/single_include/toml.hpp b/single_include/toml.hpp index 78e8603..ca5ba3c 100644 --- a/single_include/toml.hpp +++ b/single_include/toml.hpp @@ -175,9 +175,10 @@ std::string to_string(const integer_format); struct integer_format_info { integer_format fmt = integer_format::dec; - std::size_t width = 0; // minimal width (may exceed) - std::size_t spacer = 0; // position of `_` (if 0, no spacer) - std::string suffix = ""; // _suffix (library extension) + bool uppercase = true; // hex with uppercase + std::size_t width = 0; // minimal width (may exceed) + std::size_t spacer = 0; // position of `_` (if 0, no spacer) + std::string suffix = ""; // _suffix (library extension) }; bool operator==(const integer_format_info&, const integer_format_info&) noexcept; @@ -433,10 +434,11 @@ TOML11_INLINE std::string to_string(const integer_format c) TOML11_INLINE bool operator==(const integer_format_info& lhs, const integer_format_info& rhs) noexcept { - return lhs.fmt == rhs.fmt && - lhs.width == rhs.width && - lhs.spacer == rhs.spacer && - lhs.suffix == rhs.suffix ; + return lhs.fmt == rhs.fmt && + lhs.uppercase == rhs.uppercase && + lhs.width == rhs.width && + lhs.spacer == rhs.spacer && + lhs.suffix == rhs.suffix ; } TOML11_INLINE bool operator!=(const integer_format_info& lhs, const integer_format_info& rhs) noexcept { @@ -3667,6 +3669,32 @@ struct is_std_forward_list_impl> : std::true_type{}; template using is_std_forward_list = is_std_forward_list_impl>; +template struct is_std_basic_string_impl : std::false_type{}; +template +struct is_std_basic_string_impl> : std::true_type{}; +template +using is_std_basic_string = is_std_basic_string_impl>; + +template struct is_1byte_std_basic_string_impl : std::false_type{}; +template +struct is_1byte_std_basic_string_impl> + : std::integral_constant {}; +template +using is_1byte_std_basic_string = is_std_basic_string_impl>; + +#if defined(TOML11_HAS_STRING_VIEW) +template struct is_std_basic_string_view_impl : std::false_type{}; +template +struct is_std_basic_string_view_impl> : std::true_type{}; +template +using is_std_basic_string_view = is_std_basic_string_view_impl>; + +template +struct is_string_view_of : std::false_type {}; +template +struct is_string_view_of, std::basic_string> : std::true_type {}; +#endif + template struct is_chrono_duration_impl: std::false_type{}; template struct is_chrono_duration_impl>: std::true_type{}; @@ -4428,6 +4456,72 @@ inline std::string make_string(std::size_t len, char c) return std::string(len, c); } +// --------------------------------------------------------------------------- + +template +struct string_conv_impl +{ + static_assert(sizeof(Char) == sizeof(char), ""); + static_assert(sizeof(Char2) == sizeof(char), ""); + + static std::basic_string invoke(std::basic_string s) + { + std::basic_string retval; + std::transform(s.begin(), s.end(), std::back_inserter(retval), + [](const Char2 c) {return static_cast(c);}); + return retval; + } + template + static std::basic_string invoke(const Char2 (&s)[N]) + { + std::basic_string retval; + // "string literal" has null-char at the end. to skip it, we use prev. + std::transform(std::begin(s), std::prev(std::end(s)), std::back_inserter(retval), + [](const Char2 c) {return static_cast(c);}); + return retval; + } +}; + +template +struct string_conv_impl +{ + static_assert(sizeof(Char) == sizeof(char), ""); + + static std::basic_string invoke(std::basic_string s) + { + return s; + } + template + static std::basic_string invoke(const Char (&s)[N]) + { + return std::basic_string(s); + } +}; + +template +cxx::enable_if_t::value, S> +string_conv(std::basic_string s) +{ + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + return string_conv_impl::invoke(std::move(s)); +} +template +cxx::enable_if_t::value, S> +string_conv(const char (&s)[N]) +{ + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + using C2 = char; + using T2 = std::char_traits; + using A2 = std::allocator; + + return string_conv_impl::template invoke(s); +} + } // namespace detail } // namespace toml #endif // TOML11_UTILITY_HPP @@ -5634,7 +5728,7 @@ 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 std::string&); +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&); @@ -5662,6 +5756,7 @@ class basic_value 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: @@ -6229,6 +6324,63 @@ class basic_value } #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)) + {} + 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{}; + assigner(this->string_, string_storage(detail::string_conv(x), std::move(fmt))); + return *this; + } + // }}} // constructor (local_date) =========================================== {{{ @@ -6479,8 +6631,14 @@ class basic_value template using enable_if_array_like_t = cxx::enable_if_t, cxx::negation>, - detail::is_container + cxx::negation>, +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, +#endif + cxx::negation>, + cxx::negation> >::value, std::nullptr_t>; public: @@ -6574,7 +6732,9 @@ class basic_value template using enable_if_table_like_t = cxx::enable_if_t>, - detail::is_map + detail::is_map, + cxx::negation>, + cxx::negation> >::value, std::nullptr_t>; public: @@ -7671,10 +7831,10 @@ error_info make_type_error(const basic_value& v, const std::string& fname, c 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 std::string& key) +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 \"" + key + "\" not found"; + const std::string title = fname + ": key \"" + string_conv(key) + "\" not found"; std::vector> locs; if( ! loc.is_ok()) @@ -8353,16 +8513,29 @@ get(const basic_value& v) return static_cast(v.as_floating()); } +// ============================================================================ +// std::string with different char/trait/allocator + +template +cxx::enable_if_t>, + detail::is_1byte_std_basic_string + >::value, T> +get(const basic_value& v) +{ + return detail::string_conv>(v.as_string()); +} + // ============================================================================ // std::string_view #if defined(TOML11_HAS_STRING_VIEW) template -cxx::enable_if_t::value, std::string_view> +cxx::enable_if_t::string_type>::value, T> get(const basic_value& v) { - return std::string_view(v.as_string()); + return T(v.as_string()); } #endif // string_view @@ -8419,6 +8592,10 @@ cxx::enable_if_t, // T is a container detail::has_push_back_method, // .push_back() works detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif cxx::negation>, // no T.from_toml() cxx::negation>, // no toml::from cxx::negation&>> @@ -8489,6 +8666,10 @@ cxx::enable_if_t, // T is a container detail::has_push_back_method, // .push_back() works detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif cxx::negation>, // no T.from_toml() cxx::negation>, // no toml::from cxx::negation&>> @@ -11884,7 +12065,7 @@ parse_hex_integer(location& loc, const context& ctx) if( ! reg.is_ok()) { return err(make_syntax_error("toml::parse_hex_integer: " - "invalid integer: hex_int must be like: 0xC0FFEE, 0xDEAD_BEEF", + "invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef", syntax::hex_int(spec), loc)); } @@ -11912,6 +12093,14 @@ parse_hex_integer(location& loc, const context& ctx) // 0x0000_0000 becomes empty. if(str.empty()) { str = "0"; } + // prefix zero and _ is removed. check if it uses upper/lower case. + // if both upper and lower case letters are found, set upper=true. + const auto lower_not_found = std::find_if(str.begin(), str.end(), + [](const char c) { return std::islower(static_cast(c)) != 0; }) == str.end(); + const auto upper_found = std::find_if(str.begin(), str.end(), + [](const char c) { return std::isupper(static_cast(c)) != 0; }) != str.end(); + fmt.uppercase = lower_not_found || upper_found; + const auto val = TC::parse_int(str, source_location(region(loc)), 16); if(val.is_ok()) { @@ -13285,21 +13474,7 @@ parse_simple_key(location& loc, const context& ctx) if(const auto bare = syntax::unquoted_key(spec).scan(loc)) { - const auto reg = bare.as_string(); - // here we cannot use `if constexpr` because it is C++11. - if(std::is_same::value) - { - return ok(reg); - } - else - { - key_type k; - for(const auto c : reg) - { - k += typename key_type::value_type(c); - } - return ok(k); - } + return ok(string_conv(bare.as_string())); } else { @@ -15686,13 +15861,15 @@ class serializer using array_type = typename value_type::array_type ; using table_type = typename value_type::table_type ; + using char_type = typename string_type::value_type; + public: explicit serializer(const spec& sp) : spec_(sp), force_inline_(false), current_indent_(0) {} - std::string operator()(const std::vector& ks, const value_type& v) + string_type operator()(const std::vector& ks, const value_type& v) { for(const auto& k : ks) { @@ -15701,13 +15878,13 @@ class serializer return (*this)(v); } - std::string operator()(const key_type& k, const value_type& v) + string_type operator()(const key_type& k, const value_type& v) { this->keys_.push_back(k); return (*this)(v); } - std::string operator()(const value_type& v) + string_type operator()(const value_type& v) { switch(v.type()) { @@ -15725,14 +15902,14 @@ class serializer } case value_t::table : { - std::string retval; + string_type retval; if(this->keys_.empty()) // it might be the root table. emit comments here. { retval += format_comments(v.comments(), v.as_table_fmt().indent_type); } if( ! retval.empty()) // we have comment. { - retval += '\n'; + retval += char_type('\n'); } retval += (*this)(v.as_table(), v.as_table_fmt(), v.comments(), v.location()); @@ -15742,7 +15919,7 @@ class serializer { if(this->spec_.ext_null_value) { - return "null"; + return string_conv("null"); } break; } @@ -15758,12 +15935,19 @@ class serializer private: - std::string operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{ + string_type operator()(const boolean_type& b, const boolean_format_info&, const source_location&) // {{{ { - if(b) { return std::string("true"); } else { return std::string("false"); } + if(b) + { + return string_conv("true"); + } + else + { + return string_conv("false"); + } } // }}} - std::string operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{ + string_type operator()(const integer_type i, const integer_format_info& fmt, const source_location& loc) // {{{ { std::ostringstream oss; this->set_locale(oss); @@ -15807,7 +15991,6 @@ class serializer retval += '_'; retval += fmt.suffix; } - return retval; } else { @@ -15820,13 +16003,27 @@ class serializer { case integer_format::hex: { - oss << std::setw(static_cast(fmt.width)) << std::setfill('0') << std::hex << i; - return std::string("0x") + insert_spacer(oss.str()); + oss << std::noshowbase + << std::setw(static_cast(fmt.width)) + << std::setfill('0') + << std::hex; + if(fmt.uppercase) + { + oss << std::uppercase; + } + else + { + oss << std::nouppercase; + } + oss << i; + retval = std::string("0x") + insert_spacer(oss.str()); + break; } case integer_format::oct: { oss << std::setw(static_cast(fmt.width)) << std::setfill('0') << std::oct << i; - return std::string("0o") + insert_spacer(oss.str()); + retval = std::string("0o") + insert_spacer(oss.str()); + break; } case integer_format::bin: { @@ -15855,7 +16052,8 @@ class serializer { oss << *iter; } - return std::string("0b") + oss.str(); + retval = std::string("0b") + oss.str(); + break; } default: { @@ -15865,9 +16063,10 @@ class serializer } } } + return string_conv(retval); } // }}} - std::string operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{ + string_type operator()(const floating_type f, const floating_format_info& fmt, const source_location&) // {{{ { using std::isnan; using std::isinf; @@ -15888,7 +16087,7 @@ class serializer oss << '_'; oss << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } if(isinf(f)) @@ -15903,7 +16102,7 @@ class serializer oss << '_'; oss << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } switch(fmt.fmt) @@ -15928,7 +16127,7 @@ class serializer s += '_'; s += fmt.suffix; } - return s; + return string_conv(s); } case floating_format::fixed: { @@ -15941,7 +16140,7 @@ class serializer { oss << '_' << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } case floating_format::scientific: { @@ -15954,7 +16153,7 @@ class serializer { oss << '_' << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } case floating_format::hex: { @@ -15962,14 +16161,14 @@ class serializer { oss << std::hexfloat << f; // suffix is only for decimal numbers. - return oss.str(); + return string_conv(oss.str()); } else // no hex allowed. output with max precision. { oss << std::setprecision(std::numeric_limits::max_digits10) << std::scientific << f; // suffix is only for decimal numbers. - return oss.str(); + return string_conv(oss.str()); } } default: @@ -15978,58 +16177,58 @@ class serializer { oss << '_' << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } } } // }}} - std::string operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{ + string_type operator()(string_type s, const string_format_info& fmt, const source_location& loc) // {{{ { - std::string retval; + string_type retval; switch(fmt.fmt) { case string_format::basic: { - retval += '"'; + retval += char_type('"'); retval += this->escape_basic_string(s); - retval += '"'; + retval += char_type('"'); return retval; } case string_format::literal: { - if(std::find(s.begin(), s.end(), '\n') != s.end()) + if(std::find(s.begin(), s.end(), char_type('\n')) != s.end()) { throw serialization_error(format_error("toml::serializer: " "(non-multiline) literal string cannot have a newline", loc, "here"), loc); } - retval += '\''; + retval += char_type('\''); retval += s; - retval += '\''; + retval += char_type('\''); return retval; } case string_format::multiline_basic: { - retval += "\"\"\""; + retval += string_conv("\"\"\""); if(fmt.start_with_newline) { - retval += '\n'; + retval += char_type('\n'); } retval += this->escape_ml_basic_string(s); - retval += "\"\"\""; + retval += string_conv("\"\"\""); return retval; } case string_format::multiline_literal: { - retval += "'''"; + retval += string_conv("'''"); if(fmt.start_with_newline) { - retval += '\n'; + retval += char_type('\n'); } retval += s; - retval += "'''"; + retval += string_conv("'''"); return retval; } default: @@ -16041,19 +16240,19 @@ class serializer } } // }}} - std::string operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{ + string_type operator()(const local_date_type& d, const local_date_format_info&, const source_location&) // {{{ { std::ostringstream oss; oss << d; - return oss.str(); + return string_conv(oss.str()); } // }}} - std::string operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{ + string_type operator()(const local_time_type& t, const local_time_format_info& fmt, const source_location&) // {{{ { return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision); } // }}} - std::string operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{ + string_type operator()(const local_datetime_type& dt, const local_datetime_format_info& fmt, const source_location&) // {{{ { std::ostringstream oss; oss << dt.date; @@ -16064,11 +16263,11 @@ class serializer case datetime_delimiter_kind::space: { oss << ' '; break; } default: { oss << 'T'; break; } } - oss << this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision); - return oss.str(); + return string_conv(oss.str()) + + this->format_local_time(dt.time, fmt.has_seconds, fmt.subsecond_precision); } // }}} - std::string operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{ + string_type operator()(const offset_datetime_type& odt, const offset_datetime_format_info& fmt, const source_location&) // {{{ { std::ostringstream oss; oss << odt.date; @@ -16079,12 +16278,12 @@ class serializer case datetime_delimiter_kind::space: { oss << ' '; break; } default: { oss << 'T'; break; } } - oss << this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision); + oss << string_conv(this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision)); oss << odt.offset; - return oss.str(); + return string_conv(oss.str()); } // }}} - std::string operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ + string_type operator()(const array_type& a, const array_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ { array_format f = fmt.fmt; if(fmt.fmt == array_format::default_format) @@ -16173,7 +16372,7 @@ class serializer throw serialization_error("array of table must have its key. " "use format(key, v)", loc); } - std::string retval; + string_type retval; for(const auto& e : a) { assert(e.is_table()); @@ -16183,9 +16382,9 @@ class serializer retval += this->format_indent(e.as_table_fmt().indent_type); this->current_indent_ -= e.as_table_fmt().name_indent; - retval += "[["; + retval += string_conv("[["); retval += this->format_keys(this->keys_).value(); - retval += "]]\n"; + retval += string_conv("]]\n"); retval += this->format_ml_table(e.as_table(), e.as_table_fmt()); } @@ -16194,20 +16393,20 @@ class serializer else if(f == array_format::oneline) { // ignore comments. we cannot emit comments - std::string retval; - retval += "["; + string_type retval; + retval += char_type('['); for(const auto& e : a) { this->force_inline_ = true; retval += (*this)(e); - retval += ", "; + retval += string_conv(", "); } if( ! a.empty()) { retval.pop_back(); // ` ` retval.pop_back(); // `,` } - retval += "]"; + retval += char_type(']'); this->force_inline_ = false; return retval; } @@ -16215,32 +16414,32 @@ class serializer { assert(f == array_format::multiline); - std::string retval; - retval += "[\n"; + string_type retval; + retval += string_conv("[\n"); for(const auto& e : a) { this->current_indent_ += fmt.body_indent; - retval += format_comments(e.comments(), fmt.indent_type); - retval += format_indent(fmt.indent_type); + retval += this->format_comments(e.comments(), fmt.indent_type); + retval += this->format_indent(fmt.indent_type); this->current_indent_ -= fmt.body_indent; this->force_inline_ = true; retval += (*this)(e); - retval += ",\n"; + retval += string_conv(",\n"); } this->force_inline_ = false; this->current_indent_ += fmt.closing_indent; - retval += format_indent(fmt.indent_type); + retval += this->format_indent(fmt.indent_type); this->current_indent_ -= fmt.closing_indent; - retval += "]"; + retval += char_type(']'); return retval; } } // }}} - std::string operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ + string_type operator()(const table_type& t, const table_format_info& fmt, const comment_type& com, const source_location& loc) // {{{ { if(this->force_inline_) { @@ -16257,17 +16456,17 @@ class serializer { if(fmt.fmt == table_format::multiline) { - std::string retval; + string_type retval; // comment is emitted inside format_ml_table if(auto k = this->format_keys(this->keys_)) { this->current_indent_ += fmt.name_indent; - retval += format_comments(com, fmt.indent_type); - retval += format_indent(fmt.indent_type); + retval += this->format_comments(com, fmt.indent_type); + retval += this->format_indent(fmt.indent_type); this->current_indent_ -= fmt.name_indent; - retval += '['; + retval += char_type('['); retval += k.value(); - retval += "]\n"; + retval += string_conv("]\n"); } // otherwise, its the root. @@ -16284,7 +16483,7 @@ class serializer } else if(fmt.fmt == table_format::dotted) { - std::vector keys; + std::vector keys; if(this->keys_.empty()) { throw serialization_error(format_error("toml::serializer: " @@ -16301,7 +16500,7 @@ class serializer { assert(fmt.fmt == table_format::implicit); - std::string retval; + string_type retval; for(const auto& kv : t) { const auto& k = kv.first; @@ -16349,46 +16548,48 @@ class serializer private: - std::string escape_basic_string(const std::string& s) const // {{{ + string_type escape_basic_string(const string_type& s) const // {{{ { - std::string retval; - for(const char c : s) + string_type retval; + for(const char_type c : s) { switch(c) { - case '\\': {retval += "\\\\"; break;} - case '\"': {retval += "\\\""; break;} - case '\b': {retval += "\\b"; break;} - case '\t': {retval += "\\t"; break;} - case '\f': {retval += "\\f"; break;} - case '\n': {retval += "\\n"; break;} - case '\r': {retval += "\\r"; break;} + case char_type('\\'): {retval += string_conv("\\\\"); break;} + case char_type('\"'): {retval += string_conv("\\\""); break;} + case char_type('\b'): {retval += string_conv("\\b" ); break;} + case char_type('\t'): {retval += string_conv("\\t" ); break;} + case char_type('\f'): {retval += string_conv("\\f" ); break;} + case char_type('\n'): {retval += string_conv("\\n" ); break;} + case char_type('\r'): {retval += string_conv("\\r" ); break;} default : { - if(c == 0x1B && spec_.v1_1_0_add_escape_sequence_e) + if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { - retval += "\\e"; + retval += string_conv("\\e"); } - else if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F) + else if((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { if(spec_.v1_1_0_add_escape_sequence_x) { - retval += "\\x"; + retval += string_conv("\\x"); } else { - retval += "\\u00"; + retval += string_conv("\\u00"); } const auto c1 = c / 16; const auto c2 = c % 16; - retval += static_cast('0' + c1); + retval += static_cast('0' + c1); if(c2 < 10) { - retval += static_cast('0' + c2); + retval += static_cast('0' + c2); } else // 10 <= c2 { - retval += static_cast('A' + (c2 - 10)); + retval += static_cast('A' + (c2 - 10)); } } else @@ -16401,45 +16602,47 @@ class serializer return retval; } // }}} - std::string escape_ml_basic_string(const std::string& s) // {{{ + string_type escape_ml_basic_string(const string_type& s) // {{{ { - std::string retval; - for(const char c : s) + string_type retval; + for(const char_type c : s) { switch(c) { - case '\\': {retval += "\\\\"; break;} - case '\b': {retval += "\\b"; break;} - case '\t': {retval += "\\t"; break;} - case '\f': {retval += "\\f"; break;} - case '\n': {retval += "\n"; break;} - case '\r': {retval += "\\r"; break;} + case char_type('\\'): {retval += string_conv("\\\\"); break;} + case char_type('\b'): {retval += string_conv("\\b" ); break;} + case char_type('\t'): {retval += string_conv("\\t" ); break;} + case char_type('\f'): {retval += string_conv("\\f" ); break;} + case char_type('\n'): {retval += string_conv("\n" ); break;} + case char_type('\r'): {retval += string_conv("\\r" ); break;} default : { - if(c == 0x1B && spec_.v1_1_0_add_escape_sequence_e) + if(c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { - retval += "\\e"; + retval += string_conv("\\e"); } - else if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F) + else if((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { if(spec_.v1_1_0_add_escape_sequence_x) { - retval += "\\x"; + retval += string_conv("\\x"); } else { - retval += "\\u00"; + retval += string_conv("\\u00"); } const auto c1 = c / 16; const auto c2 = c % 16; - retval += static_cast('0' + c1); + retval += static_cast('0' + c1); if(c2 < 10) { - retval += static_cast('0' + c2); + retval += static_cast('0' + c2); } else // 10 <= c2 { - retval += static_cast('A' + (c2 - 10)); + retval += static_cast('A' + (c2 - 10)); } } else @@ -16460,16 +16663,16 @@ class serializer // str5 = """Here are three quotation marks: ""\".""" // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" // ``` - auto found_3_quotes = retval.find("\"\"\""); - while(found_3_quotes != std::string::npos) + auto found_3_quotes = retval.find(string_conv("\"\"\"")); + while(found_3_quotes != string_type::npos) { - retval.replace(found_3_quotes, 3, "\"\"\\\""); - found_3_quotes = retval.find("\"\"\""); + retval.replace(found_3_quotes, 3, string_conv("\"\"\\\"")); + found_3_quotes = retval.find(string_conv("\"\"\"")); } return retval; } // }}} - std::string format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{ + string_type format_local_time(const local_time_type& t, const bool has_seconds, const std::size_t subsec_prec) // {{{ { std::ostringstream oss; oss << std::setfill('0') << std::setw(2) << static_cast(t.hour); @@ -16489,10 +16692,10 @@ class serializer oss << '.' << subsec_str.substr(0, subsec_prec); } } - return oss.str(); + return string_conv(oss.str()); } // }}} - std::string format_ml_table(const table_type& t, const table_format_info& fmt) // {{{ + string_type format_ml_table(const table_type& t, const table_format_info& fmt) // {{{ { const auto format_later = [](const value_type& v) -> bool { @@ -16508,7 +16711,7 @@ class serializer return is_ml_table || is_ml_array_table; }; - std::string retval; + string_type retval; this->current_indent_ += fmt.body_indent; for(const auto& kv : t) { @@ -16529,9 +16732,9 @@ class serializer else { retval += format_key(key); - retval += " = "; + retval += string_conv(" = "); retval += (*this)(val); - retval += "\n"; + retval += char_type('\n'); } this->keys_.pop_back(); } @@ -16539,7 +16742,7 @@ class serializer if( ! retval.empty()) { - retval += "\n"; // for readability, add empty line between tables + retval += char_type('\n'); // for readability, add empty line between tables } for(const auto& kv : t) { @@ -16556,33 +16759,33 @@ class serializer return retval; } // }}} - std::string format_inline_table(const table_type& t, const table_format_info&) // {{{ + string_type format_inline_table(const table_type& t, const table_format_info&) // {{{ { // comments are ignored because we cannot write without newline - std::string retval; - retval += '{'; + string_type retval; + retval += char_type('{'); for(const auto& kv : t) { this->force_inline_ = true; retval += this->format_key(kv.first); - retval += " = "; + retval += string_conv(" = "); retval += (*this)(kv.second); - retval += ", "; + retval += string_conv(", "); } if( ! t.empty()) { retval.pop_back(); // ' ' retval.pop_back(); // ',' } - retval += '}'; + retval += char_type('}'); this->force_inline_ = false; return retval; } // }}} - std::string format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{ + string_type format_ml_inline_table(const table_type& t, const table_format_info& fmt) // {{{ { - std::string retval; - retval += "{\n"; + string_type retval; + retval += string_conv("{\n"); this->current_indent_ += fmt.body_indent; for(const auto& kv : t) { @@ -16590,12 +16793,12 @@ class serializer retval += format_comments(kv.second.comments(), fmt.indent_type); retval += format_indent(fmt.indent_type); retval += kv.first; - retval += " = "; + retval += string_conv(" = "); this->force_inline_ = true; retval += (*this)(kv.second); - retval += ",\n"; + retval += string_conv(",\n"); } if( ! t.empty()) { @@ -16609,12 +16812,12 @@ class serializer retval += format_indent(fmt.indent_type); this->current_indent_ -= fmt.closing_indent; - retval += '}'; + retval += char_type('}'); return retval; } // }}} - std::string format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{ - const source_location&, std::vector& keys) + string_type format_dotted_table(const table_type& t, const table_format_info& fmt, // {{{ + const source_location&, std::vector& keys) { // lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }` // and `a` and `b` are `dotted`. @@ -16630,7 +16833,7 @@ class serializer // a.b.c.e = "bar" // ``` - std::string retval; + string_type retval; for(const auto& kv : t) { @@ -16651,10 +16854,10 @@ class serializer retval += format_comments(val.comments(), fmt.indent_type); retval += format_indent(fmt.indent_type); retval += format_keys(keys).value(); - retval += " = "; + retval += string_conv(" = "); this->force_inline_ = true; // sub-table must be inlined retval += (*this)(val); - retval += '\n'; + retval += char_type('\n'); this->force_inline_ = false; } keys.pop_back(); @@ -16662,15 +16865,15 @@ class serializer return retval; } // }}} - std::string format_key(const key_type& key) // {{{ + string_type format_key(const key_type& key) // {{{ { if(key.empty()) { - return std::string("\"\""); + return string_conv("\"\""); } // check the key can be a bare (unquoted) key - auto loc = detail::make_temporary_location(key); + auto loc = detail::make_temporary_location(string_conv(key)); auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc); if(reg.is_ok() && loc.eof()) { @@ -16678,41 +16881,43 @@ class serializer } //if it includes special characters, then format it in a "quoted" key. - std::string formatted("\""); - for(const char c : key) + string_type formatted = string_conv("\""); + for(const char_type c : key) { switch(c) { - case '\\': {formatted += "\\\\"; break;} - case '\"': {formatted += "\\\""; break;} - case '\b': {formatted += "\\b"; break;} - case '\t': {formatted += "\\t"; break;} - case '\f': {formatted += "\\f"; break;} - case '\n': {formatted += "\\n"; break;} - case '\r': {formatted += "\\r"; break;} + case char_type('\\'): {formatted += string_conv("\\\\"); break;} + case char_type('\"'): {formatted += string_conv("\\\""); break;} + case char_type('\b'): {formatted += string_conv("\\b" ); break;} + case char_type('\t'): {formatted += string_conv("\\t" ); break;} + case char_type('\f'): {formatted += string_conv("\\f" ); break;} + case char_type('\n'): {formatted += string_conv("\\n" ); break;} + case char_type('\r'): {formatted += string_conv("\\r" ); break;} default : { // ASCII ctrl char - if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F) + if( (char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { if(spec_.v1_1_0_add_escape_sequence_x) { - formatted += "\\x"; + formatted += string_conv("\\x"); } else { - formatted += "\\u00"; + formatted += string_conv("\\u00"); } const auto c1 = c / 16; const auto c2 = c % 16; - formatted += static_cast('0' + c1); + formatted += static_cast('0' + c1); if(c2 < 10) { - formatted += static_cast('0' + c2); + formatted += static_cast('0' + c2); } else // 10 <= c2 { - formatted += static_cast('A' + (c2 - 10)); + formatted += static_cast('A' + (c2 - 10)); } } else @@ -16723,58 +16928,58 @@ class serializer } } } - formatted += "\""; + formatted += string_conv("\""); return formatted; } // }}} - cxx::optional format_keys(const std::vector& keys) // {{{ + cxx::optional format_keys(const std::vector& keys) // {{{ { if(keys.empty()) { return cxx::make_nullopt(); } - std::string formatted; + string_type formatted; for(const auto& ky : keys) { formatted += format_key(ky); - formatted += '.'; + formatted += char_type('.'); } formatted.pop_back(); // remove the last dot '.' return formatted; } // }}} - std::string format_comments(const discard_comments&, const indent_char) const // {{{ + string_type format_comments(const discard_comments&, const indent_char) const // {{{ { - return ""; + return string_conv(""); } // }}} - std::string format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{ + string_type format_comments(const preserve_comments& comments, const indent_char indent_type) const // {{{ { - std::string retval; + string_type retval; for(const auto& c : comments) { if(c.empty()) {continue;} retval += format_indent(indent_type); - if(c.front() != '#') {retval += '#';} - retval += c; - if(c.back() != '\n') {retval += '\n';} + if(c.front() != '#') {retval += char_type('#');} + retval += string_conv(c); + if(c.back() != '\n') {retval += char_type('\n');} } return retval; } // }}} - std::string format_indent(const indent_char indent_type) const // {{{ + string_type format_indent(const indent_char indent_type) const // {{{ { const auto indent = static_cast((std::max)(0, this->current_indent_)); if(indent_type == indent_char::space) { - return detail::make_string(indent, ' '); + return string_conv(make_string(indent, ' ')); } else if(indent_type == indent_char::tab) { - return detail::make_string(indent, '\t'); + return string_conv(make_string(indent, '\t')); } else { - return ""; + return string_type{}; } } // }}} @@ -16793,29 +16998,38 @@ class serializer } // detail template -std::string format(const basic_value& v, - const spec s = spec::default_version()) +typename basic_value::string_type +format(const basic_value& v, const spec s = spec::default_version()) { detail::serializer ser(s); return ser(v); } template -std::string format(const typename basic_value::key_type& k, - const basic_value& v, - const spec s = spec::default_version()) +typename basic_value::string_type +format(const typename basic_value::key_type& k, + const basic_value& v, + const spec s = spec::default_version()) { detail::serializer ser(s); return ser(k, v); } template -std::string format(const std::vector::key_type>& ks, - const basic_value& v, - const spec s = spec::default_version()) +typename basic_value::string_type +format(const std::vector::key_type>& ks, + const basic_value& v, + const spec s = spec::default_version()) { detail::serializer ser(s); return ser(ks, v); } +template +std::ostream& operator<<(std::ostream& os, const basic_value& v) +{ + os << format(v); + return os; +} + } // toml #if defined(TOML11_COMPILE_SOURCES) @@ -16824,25 +17038,25 @@ namespace toml struct type_config; struct ordered_type_config; -extern template std::string +extern template typename basic_value::string_type format(const basic_value&, const spec); -extern template std::string +extern template typename basic_value::string_type format(const typename basic_value::key_type& k, const basic_value& v, const spec); -extern template std::string +extern template typename basic_value::string_type format(const std::vector::key_type>& ks, const basic_value& v, const spec s); -extern template std::string +extern template typename basic_value::string_type format(const basic_value&, const spec); -extern template std::string +extern template typename basic_value::string_type format(const typename basic_value::key_type& k, const basic_value& v, const spec); -extern template std::string +extern template typename basic_value::string_type format(const std::vector::key_type>& ks, const basic_value& v, const spec s);