mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-17 17:58:09 +08:00
@@ -9,27 +9,24 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_resize)
|
||||
BOOST_AUTO_TEST_CASE(test_try_reserve)
|
||||
{
|
||||
{
|
||||
typedef std::vector<int> resizable_type;
|
||||
typedef std::array<int,1> non_resizable_type;
|
||||
BOOST_TEST(toml::detail::has_resize_method<resizable_type>::value);
|
||||
BOOST_TEST(!toml::detail::has_resize_method<non_resizable_type>::value);
|
||||
// since BOOST_TEST is a macro, it cannot handle commas correctly.
|
||||
// When toml::detail::has_reserve_method<std::array<int, 1>>::value
|
||||
// is passed to a macro, C preprocessor considers
|
||||
// toml::detail::has_reserve_method<std::array<int as the first argument
|
||||
// and 1>>::value as the second argument. We need an alias to avoid
|
||||
// this problem.
|
||||
using reservable_type = std::vector<int> ;
|
||||
using nonreservable_type = std::array<int, 1>;
|
||||
BOOST_TEST( toml::detail::has_reserve_method<reservable_type >::value);
|
||||
BOOST_TEST(!toml::detail::has_reserve_method<nonreservable_type>::value);
|
||||
}
|
||||
{
|
||||
std::vector<int> v;
|
||||
toml::resize(v, 10);
|
||||
BOOST_TEST(v.size() == 10u);
|
||||
}
|
||||
{
|
||||
std::array<int, 15> a;
|
||||
toml::resize(a, 10);
|
||||
BOOST_TEST(a.size() == 15u);
|
||||
}
|
||||
{
|
||||
std::array<int, 15> a;
|
||||
BOOST_CHECK_THROW(toml::resize(a, 20), std::invalid_argument);
|
||||
toml::try_reserve(v, 100);
|
||||
BOOST_TEST(v.capacity() == 100u);
|
||||
}
|
||||
}
|
||||
|
||||
|
55
toml/get.hpp
55
toml/get.hpp
@@ -198,23 +198,23 @@ get(const basic_value<C, M, V>& v)
|
||||
// ============================================================================
|
||||
// forward declaration to use this recursively. ignore this and go ahead.
|
||||
|
||||
// array-like type with resize(N) method
|
||||
// array-like type with push_back(value) method
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::has_resize_method<T>, // T::resize(N) works
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::has_push_back_method<T>, // T::push_back(value) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>&);
|
||||
|
||||
// array-like type with resize(N) method
|
||||
// array-like type without push_back(value) method
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
|
||||
detail::negation< // not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
@@ -274,31 +274,54 @@ get(const basic_value<C, M, V>&);
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::has_resize_method<T>, // T::resize(N) works
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::has_push_back_method<T>, // container.push_back(elem) works
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
using value_type = typename T::value_type;
|
||||
const auto& ar = v.as_array();
|
||||
const auto& ary = v.as_array();
|
||||
|
||||
T container;
|
||||
container.resize(ar.size());
|
||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
||||
[](const value& x){return ::toml::get<value_type>(x);});
|
||||
try_reserve(container, ary.size());
|
||||
|
||||
for(const auto& elem : ary)
|
||||
{
|
||||
container.push_back(get<value_type>(elem));
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// array-like types; but does not have resize(); most likely std::array.
|
||||
// std::forward_list does not have push_back, insert, or emplace.
|
||||
// It has insert_after, emplace_after, push_front.
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::is_std_forward_list<T>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
{
|
||||
using value_type = typename T::value_type;
|
||||
T container;
|
||||
for(const auto& elem : v.as_array())
|
||||
{
|
||||
container.push_front(get<value_type>(elem));
|
||||
}
|
||||
container.reverse();
|
||||
return container;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// array-like types, without push_back(). most likely [std|boost]::array.
|
||||
|
||||
template<typename T, typename C,
|
||||
template<typename ...> class M, template<typename ...> class V>
|
||||
detail::enable_if_t<detail::conjunction<
|
||||
detail::is_container<T>, // T is container
|
||||
detail::negation<detail::has_resize_method<T>>, // no T::resize() exists
|
||||
detail::negation< // but not toml::array
|
||||
detail::is_container<T>, // T is a container
|
||||
detail::negation<detail::has_push_back_method<T>>, // w/o push_back
|
||||
detail::negation< // T is not toml::array
|
||||
detail::is_exact_toml_type<T, basic_value<C, M, V>>>
|
||||
>::value, T>
|
||||
get(const basic_value<C, M, V>& v)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
#if __cplusplus >= 201703L
|
||||
#if __has_include(<string_view>)
|
||||
#include <string_view>
|
||||
@@ -43,17 +44,23 @@ struct has_mapped_type_impl
|
||||
template<typename T> static std::true_type check(typename T::mapped_type*);
|
||||
template<typename T> static std::false_type check(...);
|
||||
};
|
||||
struct has_resize_method_impl
|
||||
struct has_reserve_method_impl
|
||||
{
|
||||
constexpr static std::size_t dummy=0;
|
||||
template<typename T> static std::true_type check(decltype(std::declval<T>().resize(dummy))*);
|
||||
template<typename T> static std::false_type check(...);
|
||||
template<typename T> static std::true_type check(
|
||||
decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
|
||||
};
|
||||
struct has_push_back_method_impl
|
||||
{
|
||||
template<typename T> static std::false_type check(...);
|
||||
template<typename T> static std::true_type check(
|
||||
decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
|
||||
};
|
||||
|
||||
struct is_comparable_impl
|
||||
{
|
||||
template<typename T> static std::true_type check(decltype(std::declval<T>() < std::declval<T>())*);
|
||||
template<typename T> static std::false_type check(...);
|
||||
template<typename T> static std::true_type check(
|
||||
decltype(std::declval<T>() < std::declval<T>())*);
|
||||
};
|
||||
|
||||
struct has_from_toml_method_impl
|
||||
@@ -91,7 +98,9 @@ struct has_key_type : decltype(has_key_type_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
|
||||
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
|
||||
|
||||
@@ -149,6 +158,10 @@ template<typename T> struct is_std_tuple : std::false_type{};
|
||||
template<typename ... Ts>
|
||||
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
|
||||
|
||||
template<typename T> struct is_std_forward_list : std::false_type{};
|
||||
template<typename T>
|
||||
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
|
||||
|
||||
template<typename T> struct is_chrono_duration: std::false_type{};
|
||||
template<typename Rep, typename Period>
|
||||
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
|
||||
|
@@ -36,30 +36,25 @@ inline std::unique_ptr<T> make_unique(Ts&& ... args)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline void resize_impl(T& container, std::size_t N, std::true_type)
|
||||
template<typename Container>
|
||||
void try_reserve_impl(Container& container, std::size_t N, std::true_type)
|
||||
{
|
||||
container.resize(N);
|
||||
return ;
|
||||
container.reserve(N);
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void resize_impl(T& container, std::size_t N, std::false_type)
|
||||
template<typename Container>
|
||||
void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
|
||||
{
|
||||
if(container.size() >= N) {return;}
|
||||
|
||||
throw std::invalid_argument("not resizable type");
|
||||
return;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template<typename T>
|
||||
inline void resize(T& container, std::size_t N)
|
||||
template<typename Container>
|
||||
void try_reserve(Container& container, std::size_t N)
|
||||
{
|
||||
if(container.size() == N) {return;}
|
||||
|
||||
return detail::resize_impl(container, N, detail::has_resize_method<T>());
|
||||
if(N <= container.size()) {return;}
|
||||
detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
|
||||
return;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
|
Reference in New Issue
Block a user