Skip to content

Commit

Permalink
Merge branch 'u8string' into v4_1_0
Browse files Browse the repository at this point in the history
  • Loading branch information
ToruNiina committed Jul 17, 2024
2 parents eefca6e + 5e05b75 commit 8434a6b
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 25 deletions.
28 changes: 26 additions & 2 deletions include/toml11/get.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,32 @@ get(const basic_value<TC>& v)
return static_cast<T>(v.as_floating());
}

// ============================================================================
// std::string with different char/trait/allocator

template<typename T, typename TC>
cxx::enable_if_t<cxx::conjunction<
detail::is_not_toml_type<T, basic_value<TC>>,
detail::is_1byte_std_basic_string<T>
>::value, T>
get(const basic_value<TC>& v)
{
using value_type = typename cxx::remove_cvref_t<T>::value_type;
using traits_type = typename cxx::remove_cvref_t<T>::traits_type;
using allocator_type = typename cxx::remove_cvref_t<T>::allocator_type;
return detail::to_string_of<value_type, traits_type, allocator_type>(v.as_string());
}

// ============================================================================
// std::string_view

#if defined(TOML11_HAS_STRING_VIEW)

template<typename T, typename TC>
cxx::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
cxx::enable_if_t<detail::is_string_view_of<T, typename basic_value<TC>::string_type>::value, T>
get(const basic_value<TC>& v)
{
return std::string_view(v.as_string());
return T(v.as_string());
}

#endif // string_view
Expand Down Expand Up @@ -175,6 +191,10 @@ cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
Expand Down Expand Up @@ -245,6 +265,10 @@ cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>, // T is a container
detail::has_push_back_method<T>, // .push_back() works
detail::is_not_toml_type<T, basic_value<TC>>, // but not toml::array
cxx::negation<detail::is_std_basic_string<T>>, // but not std::basic_string<CharT>
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>, // but not std::basic_string_view<CharT>
#endif
cxx::negation<detail::has_from_toml_method<T, TC>>, // no T.from_toml()
cxx::negation<detail::has_specialized_from<T>>, // no toml::from<T>
cxx::negation<std::is_constructible<T, const basic_value<TC>&>>
Expand Down
16 changes: 1 addition & 15 deletions include/toml11/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1701,21 +1701,7 @@ parse_simple_key(location& loc, const context<TC>& 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<key_type, std::string>::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(to_string_of<typename key_type::value_type>(bare.as_string()));
}
else
{
Expand Down
26 changes: 26 additions & 0 deletions include/toml11/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,32 @@ struct is_std_forward_list_impl<std::forward_list<T>> : std::true_type{};
template<typename T>
using is_std_forward_list = is_std_forward_list_impl<cxx::remove_cvref_t<T>>;

template<typename T> struct is_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_std_basic_string_impl<std::basic_string<C, T, A>> : std::true_type{};
template<typename T>
using is_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;

template<typename T> struct is_1byte_std_basic_string_impl : std::false_type{};
template<typename C, typename T, typename A>
struct is_1byte_std_basic_string_impl<std::basic_string<C, T, A>>
: std::integral_constant<bool, sizeof(C) == sizeof(char)> {};
template<typename T>
using is_1byte_std_basic_string = is_std_basic_string_impl<cxx::remove_cvref_t<T>>;

#if defined(TOML11_HAS_STRING_VIEW)
template<typename T> struct is_std_basic_string_view_impl : std::false_type{};
template<typename C, typename T>
struct is_std_basic_string_view_impl<std::basic_string_view<C, T>> : std::true_type{};
template<typename T>
using is_std_basic_string_view = is_std_basic_string_view_impl<cxx::remove_cvref_t<T>>;

template<typename V, typename S>
struct is_string_view_of : std::false_type {};
template<typename C, typename T>
struct is_string_view_of<std::basic_string_view<C, T>, std::basic_string<C, T>> : std::true_type {};
#endif

template<typename T> struct is_chrono_duration_impl: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration_impl<std::chrono::duration<Rep, Period>>: std::true_type{};
Expand Down
60 changes: 60 additions & 0 deletions include/toml11/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,66 @@ inline std::string make_string(std::size_t len, char c)
return std::string(len, c);
}

// ---------------------------------------------------------------------------

template<typename Char, typename Traits, typename Alloc,
typename Char2, typename Traits2, typename Alloc2>
struct to_string_of_impl
{
static_assert(sizeof(Char) == sizeof(char), "");
static_assert(sizeof(Char2) == sizeof(char), "");

static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char2, Traits2, Alloc2> s)
{
std::basic_string<Char, Traits, Alloc> retval;
std::transform(s.begin(), s.end(), std::back_inserter(retval),
[](const Char2 c) {return static_cast<Char>(c);});
return retval;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char2 (&s)[N])
{
std::basic_string<Char, Traits, Alloc> retval;
std::transform(std::begin(s), std::end(s), std::back_inserter(retval),
[](const char c) {return static_cast<Char>(c);});
return retval;
}
};

template<typename Char, typename Traits, typename Alloc>
struct to_string_of_impl<Char, Traits, Alloc, Char, Traits, Alloc>
{
static_assert(sizeof(Char) == sizeof(char), "");

static std::basic_string<Char, Traits, Alloc> invoke(std::basic_string<Char, Traits, Alloc> s)
{
return s;
}
template<std::size_t N>
static std::basic_string<Char, Traits, Alloc> invoke(const Char (&s)[N])
{
return std::basic_string<Char, Traits, Alloc>(s);
}
};

template<typename Char,
typename Traits = std::char_traits<Char>,
typename Alloc = std::allocator<Char>,
typename Char2, typename Traits2, typename Alloc2>
std::basic_string<Char, Traits, Alloc>
to_string_of(std::basic_string<Char2, Traits2, Alloc2> s)
{
return to_string_of_impl<Char, Traits, Alloc, Char2, Traits2, Alloc2>::invoke(std::move(s));
}
template<typename Char,
typename Traits = std::char_traits<Char>,
typename Alloc = std::allocator<Char>,
typename Char2, typename Traits2, typename Alloc2, std::size_t N>
std::basic_string<Char, Traits, Alloc> to_string_of(const char (&s)[N])
{
return to_string_of_impl<Char, Traits, Alloc, Char2, Traits2, Alloc2>::template invoke<N>(s);
}

} // namespace detail
} // namespace toml
#endif // TOML11_UTILITY_HPP
76 changes: 71 additions & 5 deletions include/toml11/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ template<typename TC>
error_info make_type_error(const basic_value<TC>&, const std::string&, const value_t);

template<typename TC>
error_info make_not_found_error(const basic_value<TC>&, const std::string&, const std::string&);
error_info make_not_found_error(const basic_value<TC>&, const std::string&, const typename basic_value<TC>::key_type&);

template<typename TC>
void change_region_of_value(basic_value<TC>&, const basic_value<TC>&);
Expand Down Expand Up @@ -76,6 +76,7 @@ class basic_value
using array_type = typename config_type::template array_type<value_type>;
using table_type = typename config_type::template table_type<key_type, value_type>;
using comment_type = typename config_type::comment_type;
using char_type = typename string_type::value_type;

private:

Expand Down Expand Up @@ -643,6 +644,63 @@ class basic_value
}

#endif // TOML11_HAS_STRING_VIEW

template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::value, std::nullptr_t> = nullptr>
basic_value(const T& x)
: basic_value(x, string_format_info{}, std::vector<std::string>{}, region_type{})
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::value, std::nullptr_t> = nullptr>
basic_value(const T& x, string_format_info fmt)
: basic_value(x, std::move(fmt), std::vector<std::string>{}, region_type{})
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::value, std::nullptr_t> = nullptr>
basic_value(const T& x, std::vector<std::string> com)
: basic_value(x, string_format_info{}, std::move(com), region_type{})
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::value, std::nullptr_t> = nullptr>
basic_value(const T& x, string_format_info fmt, std::vector<std::string> com)
: basic_value(x, std::move(fmt), std::move(com), region_type{})
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::value, std::nullptr_t> = nullptr>
basic_value(const T& x, string_format_info fmt,
std::vector<std::string> com, region_type reg)
: type_(value_t::string),
string_(string_storage(detail::to_string_of<char_type>(x), std::move(fmt))),
region_(std::move(reg)), comments_(std::move(com))
{}
template<typename T, cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<cxx::remove_cvref_t<T>, string_type>>,
detail::is_1byte_std_basic_string<T>
>::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::to_string_of<char_type>(x), std::move(fmt)));
return *this;
}

// }}}

// constructor (local_date) =========================================== {{{
Expand Down Expand Up @@ -893,8 +951,14 @@ class basic_value

template<typename T>
using enable_if_array_like_t = cxx::enable_if_t<cxx::conjunction<
detail::is_container<T>,
cxx::negation<std::is_same<T, array_type>>,
detail::is_container<T>
cxx::negation<detail::is_std_basic_string<T>>,
#if defined(TOML11_HAS_STRING_VIEW)
cxx::negation<detail::is_std_basic_string_view<T>>,
#endif
cxx::negation<detail::has_from_toml_method<T, config_type>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, std::nullptr_t>;

public:
Expand Down Expand Up @@ -988,7 +1052,9 @@ class basic_value
template<typename T>
using enable_if_table_like_t = cxx::enable_if_t<cxx::conjunction<
cxx::negation<std::is_same<T, table_type>>,
detail::is_map<T>
detail::is_map<T>,
cxx::negation<detail::has_from_toml_method<T, config_type>>,
cxx::negation<detail::has_specialized_from<T>>
>::value, std::nullptr_t>;

public:
Expand Down Expand Up @@ -2062,10 +2128,10 @@ error_info make_type_error(const basic_value<TC>& v, const std::string& fname, c
v.location(), "the actual type is " + to_string(v.type()));
}
template<typename TC>
error_info make_not_found_error(const basic_value<TC>& v, const std::string& fname, const std::string& key)
error_info make_not_found_error(const basic_value<TC>& v, const std::string& fname, const typename basic_value<TC>::key_type& key)
{
const auto loc = v.location();
const std::string title = fname + ": key \"" + key + "\" not found";
const std::string title = fname + ": key \"" + to_string_of<char>(key) + "\" not found";

std::vector<std::pair<source_location, std::string>> locs;
if( ! loc.is_ok())
Expand Down
19 changes: 17 additions & 2 deletions tests/test_find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,14 +627,29 @@ TEST_CASE("testing toml::find string conversion")
toml::find<std::string>(v, "key") += "bar";
CHECK_EQ("foobar", toml::find<std::string>(v, "key"));
}
}

#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if defined(TOML11_HAS_CHAR8_T)
TEST_CASE("testing toml::find<string-like>")
{
using value_type = toml::value;
{
value_type v = toml::table{{"key", "foo"}};
CHECK_EQ("foo", toml::find<std::string_view>(v, "key"));
CHECK_EQ(u8"foo", toml::find<std::u8string>(v, "key"));
}
}
#endif

#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
TEST_CASE("testing toml::get<string_view>")
{
using value_type = toml::value;
{
value_type v("foo");
CHECK_EQ("foo", toml::get<std::string_view>(v));
}
}
#endif

TEST_CASE("testing toml::find array conversion")
{
Expand Down
13 changes: 12 additions & 1 deletion tests/test_get.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,19 @@ TEST_CASE("testing toml::get<floating-like>")
}
}

#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
#if defined(TOML11_HAS_CHAR8_T)
TEST_CASE("testing toml::get<string-like>")
{
using value_type = toml::value;
{
value_type v("foo");
CHECK_EQ(u8"foo", toml::get<std::u8string>(v));
}
}
#endif

#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
TEST_CASE("testing toml::get<string_view>")
{
using value_type = toml::value;
{
Expand Down
Loading

0 comments on commit 8434a6b

Please sign in to comment.