diff --git a/tests/test_utility.cpp b/tests/test_utility.cpp index c4cb003..6919399 100644 --- a/tests/test_utility.cpp +++ b/tests/test_utility.cpp @@ -9,27 +9,24 @@ #include #include -BOOST_AUTO_TEST_CASE(test_resize) +BOOST_AUTO_TEST_CASE(test_try_reserve) { { - typedef std::vector resizable_type; - typedef std::array non_resizable_type; - BOOST_TEST(toml::detail::has_resize_method::value); - BOOST_TEST(!toml::detail::has_resize_method::value); + // since BOOST_TEST is a macro, it cannot handle commas correctly. + // When toml::detail::has_reserve_method>::value + // is passed to a macro, C preprocessor considers + // toml::detail::has_reserve_method>::value as the second argument. We need an alias to avoid + // this problem. + using reservable_type = std::vector ; + using nonreservable_type = std::array; + BOOST_TEST( toml::detail::has_reserve_method::value); + BOOST_TEST(!toml::detail::has_reserve_method::value); } { std::vector v; - toml::resize(v, 10); - BOOST_TEST(v.size() == 10u); - } - { - std::array a; - toml::resize(a, 10); - BOOST_TEST(a.size() == 15u); - } - { - std::array a; - BOOST_CHECK_THROW(toml::resize(a, 20), std::invalid_argument); + toml::try_reserve(v, 100); + BOOST_TEST(v.capacity() == 100u); } } diff --git a/toml/get.hpp b/toml/get.hpp index 0dd6284..e42fa02 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -198,24 +198,24 @@ get(const basic_value& 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 class M, template class V> detail::enable_if_t, // T is container - detail::has_resize_method, // T::resize(N) works - detail::negation< // but not toml::array + detail::is_container, // T is a container + detail::has_push_back_method, // T::push_back(value) works + detail::negation< // but not toml::array detail::is_exact_toml_type>> >::value, T> get(const basic_value&); -// array-like type with resize(N) method +// array-like type without push_back(value) method template class M, template class V> detail::enable_if_t, // T is container - detail::negation>, // no T::resize() exists - detail::negation< // not toml::array + detail::is_container, // T is a container + detail::negation>, // w/o push_back(...) + detail::negation< // not toml::array detail::is_exact_toml_type>> >::value, T> get(const basic_value&); @@ -274,31 +274,54 @@ get(const basic_value&); template class M, template class V> detail::enable_if_t, // T is container - detail::has_resize_method, // T::resize(N) works - detail::negation< // but not toml::array + detail::is_container, // T is a container + detail::has_push_back_method, // container.push_back(elem) works + detail::negation< // but not toml::array detail::is_exact_toml_type>> >::value, T> get(const basic_value& 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(x);}); + try_reserve(container, ary.size()); + + for(const auto& elem : ary) + { + container.push_back(get(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 class M, template class V> +detail::enable_if_t::value, T> +get(const basic_value& v) +{ + using value_type = typename T::value_type; + T container; + for(const auto& elem : v.as_array()) + { + container.push_front(get(elem)); + } + container.reverse(); + return container; +} + +// ============================================================================ +// array-like types, without push_back(). most likely [std|boost]::array. template class M, template class V> detail::enable_if_t, // T is container - detail::negation>, // no T::resize() exists - detail::negation< // but not toml::array + detail::is_container, // T is a container + detail::negation>, // w/o push_back + detail::negation< // T is not toml::array detail::is_exact_toml_type>> >::value, T> get(const basic_value& v) diff --git a/toml/traits.hpp b/toml/traits.hpp index 4fc1bda..31037f4 100644 --- a/toml/traits.hpp +++ b/toml/traits.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #if __cplusplus >= 201703L #if __has_include() #include @@ -43,17 +44,23 @@ struct has_mapped_type_impl template static std::true_type check(typename T::mapped_type*); template static std::false_type check(...); }; -struct has_resize_method_impl +struct has_reserve_method_impl { - constexpr static std::size_t dummy=0; - template static std::true_type check(decltype(std::declval().resize(dummy))*); template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval().reserve(std::declval()))*); +}; +struct has_push_back_method_impl +{ + template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval().push_back(std::declval()))*); }; - struct is_comparable_impl { - template static std::true_type check(decltype(std::declval() < std::declval())*); template static std::false_type check(...); + template static std::true_type check( + decltype(std::declval() < std::declval())*); }; struct has_from_toml_method_impl @@ -91,7 +98,9 @@ struct has_key_type : decltype(has_key_type_impl::check(nullptr)){}; template struct has_mapped_type : decltype(has_mapped_type_impl::check(nullptr)){}; template -struct has_resize_method : decltype(has_resize_method_impl::check(nullptr)){}; +struct has_reserve_method : decltype(has_reserve_method_impl::check(nullptr)){}; +template +struct has_push_back_method : decltype(has_push_back_method_impl::check(nullptr)){}; template struct is_comparable : decltype(is_comparable_impl::check(nullptr)){}; @@ -149,6 +158,10 @@ template struct is_std_tuple : std::false_type{}; template struct is_std_tuple> : std::true_type{}; +template struct is_std_forward_list : std::false_type{}; +template +struct is_std_forward_list> : std::true_type{}; + template struct is_chrono_duration: std::false_type{}; template struct is_chrono_duration>: std::true_type{}; diff --git a/toml/utility.hpp b/toml/utility.hpp index bac1249..c287b8e 100644 --- a/toml/utility.hpp +++ b/toml/utility.hpp @@ -36,30 +36,25 @@ inline std::unique_ptr make_unique(Ts&& ... args) namespace detail { - -template -inline void resize_impl(T& container, std::size_t N, std::true_type) +template +void try_reserve_impl(Container& container, std::size_t N, std::true_type) { - container.resize(N); - return ; + container.reserve(N); + return; } - -template -inline void resize_impl(T& container, std::size_t N, std::false_type) +template +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 -inline void resize(T& container, std::size_t N) +template +void try_reserve(Container& container, std::size_t N) { - if(container.size() == N) {return;} - - return detail::resize_impl(container, N, detail::has_resize_method()); + if(N <= container.size()) {return;} + detail::try_reserve_impl(container, N, detail::has_reserve_method{}); + return; } namespace detail