From eba1aa2fde8f772ed783d6555b577bf972d2fc9a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 20 Jul 2024 04:36:32 +0900 Subject: [PATCH 1/3] feat: take string type itself when conversion --- include/toml11/get.hpp | 5 +---- include/toml11/parser.hpp | 2 +- include/toml11/utility.hpp | 35 ++++++++++++++++++++--------------- include/toml11/value.hpp | 6 +++--- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/toml11/get.hpp b/include/toml11/get.hpp index dbf327a9..8cdad9c9 100644 --- a/include/toml11/get.hpp +++ b/include/toml11/get.hpp @@ -119,10 +119,7 @@ cxx::enable_if_t::value, T> get(const basic_value& v) { - using value_type = typename cxx::remove_cvref_t::value_type; - using traits_type = typename cxx::remove_cvref_t::traits_type; - using allocator_type = typename cxx::remove_cvref_t::allocator_type; - return detail::to_string_of(v.as_string()); + return detail::string_conv>(v.as_string()); } // ============================================================================ diff --git a/include/toml11/parser.hpp b/include/toml11/parser.hpp index 37e4d326..92dfb2f5 100644 --- a/include/toml11/parser.hpp +++ b/include/toml11/parser.hpp @@ -1693,7 +1693,7 @@ parse_simple_key(location& loc, const context& ctx) if(const auto bare = syntax::unquoted_key(spec).scan(loc)) { - return ok(to_string_of(bare.as_string())); + return ok(string_conv(bare.as_string())); } else { diff --git a/include/toml11/utility.hpp b/include/toml11/utility.hpp index 66dfc769..b82b3f4a 100644 --- a/include/toml11/utility.hpp +++ b/include/toml11/utility.hpp @@ -103,7 +103,7 @@ inline std::string make_string(std::size_t len, char c) template -struct to_string_of_impl +struct string_conv_impl { static_assert(sizeof(Char) == sizeof(char), ""); static_assert(sizeof(Char2) == sizeof(char), ""); @@ -126,7 +126,7 @@ struct to_string_of_impl }; template -struct to_string_of_impl +struct string_conv_impl { static_assert(sizeof(Char) == sizeof(char), ""); @@ -141,22 +141,27 @@ struct to_string_of_impl } }; -template, - typename Alloc = std::allocator, - typename Char2, typename Traits2, typename Alloc2> -std::basic_string -to_string_of(std::basic_string s) +template +cxx::enable_if_t::value, S> +string_conv(std::basic_string s) { - return to_string_of_impl::invoke(std::move(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, - typename Alloc = std::allocator, - typename Char2, typename Traits2, typename Alloc2, std::size_t N> -std::basic_string to_string_of(const char (&s)[N]) +template +cxx::enable_if_t::value, S> +string_conv(const char (&s)[N]) { - return to_string_of_impl::template invoke(s); + 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 diff --git a/include/toml11/value.hpp b/include/toml11/value.hpp index 5d706713..22c35359 100644 --- a/include/toml11/value.hpp +++ b/include/toml11/value.hpp @@ -680,7 +680,7 @@ class basic_value basic_value(const T& x, string_format_info fmt, std::vector com, region_type reg) : type_(value_t::string), - string_(string_storage(detail::to_string_of(x), std::move(fmt))), + string_(string_storage(detail::string_conv(x), std::move(fmt))), region_(std::move(reg)), comments_(std::move(com)) {} templatecleanup(); this->type_ = value_t::string; this->region_ = region_type{}; - assigner(this->string_, string_storage(detail::to_string_of(x), std::move(fmt))); + assigner(this->string_, string_storage(detail::string_conv(x), std::move(fmt))); return *this; } @@ -2131,7 +2131,7 @@ 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 \"" + to_string_of(key) + "\" not found"; + const std::string title = fname + ": key \"" + string_conv(key) + "\" not found"; std::vector> locs; if( ! loc.is_ok()) From 6085c53ea2191d405dc25c19987165f2a69be6e2 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 20 Jul 2024 17:21:56 +0900 Subject: [PATCH 2/3] fix: skip null char in string literal --- include/toml11/utility.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/toml11/utility.hpp b/include/toml11/utility.hpp index b82b3f4a..9e30ccb7 100644 --- a/include/toml11/utility.hpp +++ b/include/toml11/utility.hpp @@ -119,8 +119,9 @@ struct string_conv_impl static std::basic_string invoke(const Char2 (&s)[N]) { std::basic_string retval; - std::transform(std::begin(s), std::end(s), std::back_inserter(retval), - [](const char c) {return static_cast(c);}); + // "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; } }; From 43f5a74bf06180f8e5b3e4106fe4957ea0f91f1a Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 20 Jul 2024 17:22:10 +0900 Subject: [PATCH 3/3] feat: support string_type in toml::format --- include/toml11/serializer.hpp | 374 ++++++++++++++++++---------------- src/serializer.cpp | 12 +- 2 files changed, 203 insertions(+), 183 deletions(-) diff --git a/include/toml11/serializer.hpp b/include/toml11/serializer.hpp index 43398f83..cac3f4bd 100644 --- a/include/toml11/serializer.hpp +++ b/include/toml11/serializer.hpp @@ -59,13 +59,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) { @@ -74,13 +76,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()) { @@ -98,14 +100,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()); @@ -115,7 +117,7 @@ class serializer { if(this->spec_.ext_null_value) { - return "null"; + return string_conv("null"); } break; } @@ -131,12 +133,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); @@ -180,7 +189,6 @@ class serializer retval += '_'; retval += fmt.suffix; } - return retval; } else { @@ -194,12 +202,14 @@ 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()); + 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: { @@ -228,7 +238,8 @@ class serializer { oss << *iter; } - return std::string("0b") + oss.str(); + retval = std::string("0b") + oss.str(); + break; } default: { @@ -238,9 +249,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; @@ -261,7 +273,7 @@ class serializer oss << '_'; oss << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } if(isinf(f)) @@ -276,7 +288,7 @@ class serializer oss << '_'; oss << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } switch(fmt.fmt) @@ -301,7 +313,7 @@ class serializer s += '_'; s += fmt.suffix; } - return s; + return string_conv(s); } case floating_format::fixed: { @@ -314,7 +326,7 @@ class serializer { oss << '_' << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } case floating_format::scientific: { @@ -327,7 +339,7 @@ class serializer { oss << '_' << fmt.suffix; } - return oss.str(); + return string_conv(oss.str()); } case floating_format::hex: { @@ -335,14 +347,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: @@ -351,58 +363,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: @@ -414,19 +426,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; @@ -437,11 +449,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; @@ -452,12 +464,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) @@ -546,7 +558,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()); @@ -556,9 +568,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()); } @@ -567,20 +579,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; } @@ -588,32 +600,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_) { @@ -630,17 +642,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. @@ -657,7 +669,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: " @@ -674,7 +686,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; @@ -722,46 +734,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 @@ -774,45 +788,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 @@ -833,16 +849,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); @@ -862,10 +878,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 { @@ -881,7 +897,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) { @@ -902,9 +918,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(); } @@ -912,7 +928,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) { @@ -929,33 +945,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) { @@ -963,12 +979,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()) { @@ -982,12 +998,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`. @@ -1003,7 +1019,7 @@ class serializer // a.b.c.e = "bar" // ``` - std::string retval; + string_type retval; for(const auto& kv : t) { @@ -1024,10 +1040,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(); @@ -1035,15 +1051,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()) { @@ -1051,41 +1067,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 @@ -1096,58 +1114,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{}; } } // }}} @@ -1166,24 +1184,26 @@ 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); @@ -1197,25 +1217,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); diff --git a/src/serializer.cpp b/src/serializer.cpp index 4800bd5f..5dcaffe0 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -10,25 +10,25 @@ namespace toml struct type_config; struct ordered_type_config; -template std::string +template typename basic_value::string_type format(const basic_value&, const spec); -template std::string +template typename basic_value::string_type format(const typename basic_value::key_type& k, const basic_value& v, const spec); -template std::string +template typename basic_value::string_type format(const std::vector::key_type>& ks, const basic_value& v, const spec s); -template std::string +template typename basic_value::string_type format(const basic_value&, const spec); -template std::string +template typename basic_value::string_type format(const typename basic_value::key_type& k, const basic_value& v, const spec); -template std::string +template typename basic_value::string_type format(const std::vector::key_type>& ks, const basic_value& v, const spec s);