diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4909753..ed2d13b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(boost_container) add_subdirectory(boost_multiprecision) add_subdirectory(parse_file) add_subdirectory(reflect) +add_subdirectory(u8string) add_subdirectory(unicode) diff --git a/examples/u8string/.gitignore b/examples/u8string/.gitignore new file mode 100644 index 0000000..5df90cf --- /dev/null +++ b/examples/u8string/.gitignore @@ -0,0 +1 @@ +u8string diff --git a/examples/u8string/CMakeLists.txt b/examples/u8string/CMakeLists.txt new file mode 100644 index 0000000..c550092 --- /dev/null +++ b/examples/u8string/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(u8string u8string.cpp) +target_link_libraries(u8string PRIVATE toml11::toml11) +target_compile_features(u8string PRIVATE cxx_std_20) +set_target_properties(u8string PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/examples/u8string/spec_example.toml b/examples/u8string/spec_example.toml new file mode 100644 index 0000000..3fe43f0 --- /dev/null +++ b/examples/u8string/spec_example.toml @@ -0,0 +1,23 @@ +# This is a TOML document + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +dob = 1979-05-27T07:32:00-08:00 + +[database] +enabled = true +ports = [ 8000, 8001, 8002 ] +data = [ ["delta", "phi"], [3.14] ] +temp_targets = { cpu = 79.5, case = 72.0 } + +[servers] + +[servers.alpha] +ip = "10.0.0.1" +role = "frontend" + +[servers.beta] +ip = "10.0.0.2" +role = "backend" diff --git a/examples/u8string/u8string.cpp b/examples/u8string/u8string.cpp new file mode 100644 index 0000000..c6388a5 --- /dev/null +++ b/examples/u8string/u8string.cpp @@ -0,0 +1,120 @@ +#include + +#include +#include + +#include + +struct u8config +{ + using comment_type = toml::preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::u8string; // XXX + + template + using array_type = std::vector; + template + using table_type = std::unordered_map; + + static toml::result + parse_int(const std::string& str, const toml::source_location src, const std::uint8_t base) + { + return toml::read_int(str, src, base); + } + static toml::result + parse_float(const std::string& str, const toml::source_location src, const bool is_hex) + { + return toml::read_float(str, src, is_hex); + } +}; + +int main() +{ + const auto root = toml::parse("spec_example.toml"); + + // using member functions + { + assert(root.at(u8"title").as_string() == u8"TOML Example"); + + assert(root.at(u8"owner").at(u8"name").as_string() == u8"Tom Preston-Werner"); + + const auto dob = root.at(u8"owner").at(u8"dob" ).as_offset_datetime(); + assert(dob.date .year == 1979); + assert(dob.date .month == static_cast(toml::month_t::May)); + assert(dob.date .day == 27); + assert(dob.time .hour == 7); + assert(dob.time .minute == 32); + assert(dob.time .second == 0); + assert(dob.offset.hour == -8); + assert(dob.offset.minute == 0); + + assert(root.at(u8"database").at(u8"enabled").as_boolean()); + assert(root.at(u8"database").at(u8"ports").at(0).as_integer() == 8000); + assert(root.at(u8"database").at(u8"ports").at(1).as_integer() == 8001); + assert(root.at(u8"database").at(u8"ports").at(2).as_integer() == 8002); + assert(root.at(u8"database").at(u8"data").at(0).at(0).as_string() == u8"delta"); + assert(root.at(u8"database").at(u8"data").at(0).at(1).as_string() == u8"phi"); + assert(root.at(u8"database").at(u8"data").at(1).at(0).as_floating() == 3.14); + assert(root.at(u8"database").at(u8"temp_targets").at(u8"cpu" ).as_floating() == 79.5); + assert(root.at(u8"database").at(u8"temp_targets").at(u8"case").as_floating() == 72.0); + + assert(root.at(u8"servers").at(u8"alpha").at(u8"ip" ).as_string() == u8"10.0.0.1"); + assert(root.at(u8"servers").at(u8"alpha").at(u8"role").as_string() == u8"frontend"); + assert(root.at(u8"servers").at(u8"beta" ).at(u8"ip" ).as_string() == u8"10.0.0.2"); + assert(root.at(u8"servers").at(u8"beta" ).at(u8"role").as_string() == u8"backend"); + } + + // using toml::find + { + // you can get as std::string from u8string, using toml::get/find + assert(toml::find(root, u8"title") == "TOML Example"); + + assert(toml::find(root, u8"owner", u8"name") == "Tom Preston-Werner"); + + const auto dob = toml::find(root, u8"owner", u8"dob"); + assert(dob.date .year == 1979); + assert(dob.date .month == static_cast(toml::month_t::May)); + assert(dob.date .day == 27); + assert(dob.time .hour == 7); + assert(dob.time .minute == 32); + assert(dob.time .second == 0); + assert(dob.offset.hour == -8); + assert(dob.offset.minute == 0); + + assert(toml::find(root, u8"database", u8"enabled")); + + const auto ports = toml::find>(root, u8"database", u8"ports"); + assert(ports.at(0) == 8000); + assert(ports.at(1) == 8001); + assert(ports.at(2) == 8002); + + const auto data = toml::find, std::vector>>(root, u8"database", u8"data"); + assert(data.first.at(0) == "delta"); + assert(data.first.at(1) == "phi"); + assert(data.second.at(0) == 3.14); + + const auto temp_targets = toml::find>(root, u8"database", u8"temp_targets"); + assert(temp_targets.at("cpu" ) == 79.5); + assert(temp_targets.at("case") == 72.0); + + const auto servers = toml::find>>(root, u8"servers"); + assert(servers.at("alpha").at("ip" ) == "10.0.0.1"); + assert(servers.at("alpha").at("role") == "frontend"); + assert(servers.at("beta" ).at("ip" ) == "10.0.0.2"); + assert(servers.at("beta" ).at("role") == "backend" ); + } + + const std::u8string out = toml::format(root); + + std::string printable; + std::transform(out.begin(), out.end(), std::back_inserter(printable), + [](const char8_t c) {return static_cast(c);}); + std::cout << printable << std::endl; + + std::cout << "ok." << std::endl; + + return 0; +} diff --git a/include/toml11/get.hpp b/include/toml11/get.hpp index 8cdad9c..3805d09 100644 --- a/include/toml11/get.hpp +++ b/include/toml11/get.hpp @@ -218,16 +218,33 @@ template cxx::enable_if_t::value, T> get(const basic_value&); -// map-like +// std::map (key is convertible from toml::value::key_type) template cxx::enable_if_t, // T is map detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible cxx::negation>, // no T.from_toml() cxx::negation>, // no toml::from cxx::negation&>> >::value, T> -get(const basic_value&); +get(const basic_value& v); + +// std::map (key is not convertible from toml::value::key_type, but +// is a std::basic_string) +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v); // toml::from::from_toml(v) template @@ -384,10 +401,13 @@ get(const basic_value& v) // ============================================================================ // map-like types; most likely STL map, like std::map or std::unordered_map. +// key is convertible from toml::value::key_type template cxx::enable_if_t, // T is map detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible cxx::negation>, // no T.from_toml() cxx::negation>, // no toml::from cxx::negation&>> @@ -409,6 +429,31 @@ get(const basic_value& v) return m; } +// key is NOT convertible from toml::value::key_type but std::basic_string +template +cxx::enable_if_t, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>> + >::value, T> +get(const basic_value& v) +{ + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + + T m; + for(const auto& kv : v.as_table()) + { + m.emplace(detail::string_conv(kv.first), get(kv.second)); + } + return m; +} + // ============================================================================ // user-defined, but convertible types.