Merge branch 'u8string' into v4_1_0

This commit is contained in:
ToruNiina
2024-07-18 01:03:58 +09:00
8 changed files with 313 additions and 26 deletions

View File

@@ -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
@@ -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>&>>
@@ -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>&>>

View File

@@ -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
{

View File

@@ -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{};

View File

@@ -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

View File

@@ -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>&);
@@ -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:
@@ -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) =========================================== {{{
@@ -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:
@@ -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:
@@ -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())

View File

@@ -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
}
#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")
{

View File

@@ -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;
{

View File

@@ -587,6 +587,105 @@ TEST_CASE("testing constructor (string_view)")
}
#endif
#ifdef TOML11_HAS_CHAR8_T
TEST_CASE("testing constructor (u8string)")
{
toml::string_format_info fmt;
fmt.fmt = toml::string_format::basic;
const std::string eq("hoge");
const std::string ne("fuga");
const std::u8string ref(u8"hoge");
{
toml::value x(ref);
test_is_type(x, toml::value_t::string);
test_as_type_throws(x, toml::value_t::string);
test_as_type_fmt_throws(x, toml::value_t::string);
test_as_type<toml::value_t::string>(x, "hoge", "fuga");
}
// -----------------------------------------------------------------------
{
toml::value x_with_comments(ref, std::vector<std::string>{"foo", "bar"});
test_is_type (x_with_comments, toml::value_t::string);
test_as_type_throws (x_with_comments, toml::value_t::string);
test_as_type_fmt_throws(x_with_comments, toml::value_t::string);
test_as_type<toml::value_t::string>(x_with_comments, eq, ne);
CHECK_EQ(x_with_comments.comments().size(), 2);
CHECK_EQ(x_with_comments.comments().at(0), "foo");
CHECK_EQ(x_with_comments.comments().at(1), "bar");
CHECK_EQ(x_with_comments.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_with_format(eq, fmt);
test_is_type (x_with_format, toml::value_t::string);
test_as_type_throws (x_with_format, toml::value_t::string);
test_as_type_fmt_throws(x_with_format, toml::value_t::string);
test_as_type <toml::value_t::string>(x_with_format, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_with_format, fmt);
CHECK_EQ(x_with_format.comments().size(), 0);
CHECK_EQ(x_with_format.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_with_com_fmt(ref, fmt,
std::vector<std::string>{"foo", "bar"});
test_is_type (x_with_com_fmt, toml::value_t::string);
test_as_type_throws (x_with_com_fmt, toml::value_t::string);
test_as_type_fmt_throws(x_with_com_fmt, toml::value_t::string);
test_as_type <toml::value_t::string>(x_with_com_fmt, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_with_com_fmt, fmt);
CHECK_EQ(x_with_com_fmt.comments().size(), 2);
CHECK_EQ(x_with_com_fmt.comments().at(0), "foo");
CHECK_EQ(x_with_com_fmt.comments().at(1), "bar");
CHECK_EQ(x_with_com_fmt.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_assign(ne, fmt);
x_assign = ref;
test_is_type (x_assign, toml::value_t::string);
test_as_type_throws (x_assign, toml::value_t::string);
test_as_type_fmt_throws(x_assign, toml::value_t::string);
test_as_type <toml::value_t::string>(x_assign, eq, ne);
test_as_type_fmt<toml::value_t::string>(x_assign, fmt);
CHECK_EQ(x_assign.comments().size(), 0);
CHECK_EQ(x_assign.location().is_ok(), false);
}
// -----------------------------------------------------------------------
{
toml::value x_assign_different_type(true);
x_assign_different_type = ref;
test_is_type (x_assign_different_type, toml::value_t::string);
test_as_type_throws (x_assign_different_type, toml::value_t::string);
test_as_type_fmt_throws(x_assign_different_type, toml::value_t::string);
test_as_type<toml::value_t::string>(x_assign_different_type, eq, ne);
CHECK_EQ(x_assign_different_type.comments().size(), 0);
CHECK_EQ(x_assign_different_type.location().is_ok(), false);
}
}
#endif
TEST_CASE("testing constructor (local_date)")
{
toml::local_date_format_info fmt;