Compare commits

...

9 Commits

Author SHA1 Message Date
ToruNiina
b1a55b1331 simplify SFINAE in to_toml 2018-05-05 13:09:40 +09:00
ToruNiina
170b0d6b3f use constexpr value instead of call constexpr func directory 2018-05-05 12:06:06 +09:00
ToruNiina
433636a06f simplify the implementation of from_toml 2018-05-05 11:59:34 +09:00
ToruNiina
9555817901 add get<pair>, get<tuple> 2018-05-05 11:46:09 +09:00
ToruNiina
e54deacf1a simplify SFINAE expressions in toml::get 2018-05-05 11:42:11 +09:00
ToruNiina
b6f53cae7a update test_traits
now is_container returns false when map-like class is passed
2018-05-05 11:40:13 +09:00
ToruNiina
f953a9cf23 add conjunction, disjunction, negation, index_seq 2018-05-05 11:37:18 +09:00
ToruNiina
117549bf70 change is_(map|container) and remove needless trait 2018-05-05 11:36:47 +09:00
ToruNiina
4287160254 add a badge 2018-03-28 19:21:17 +09:00
8 changed files with 250 additions and 149 deletions

View File

@@ -4,6 +4,7 @@ toml11
[![Build Status](https://travis-ci.org/ToruNiina/toml11.svg?branch=master)](https://travis-ci.org/ToruNiina/toml11) [![Build Status](https://travis-ci.org/ToruNiina/toml11.svg?branch=master)](https://travis-ci.org/ToruNiina/toml11)
[![Build status](https://ci.appveyor.com/api/projects/status/m2n08a926asvg5mg?svg=true)](https://ci.appveyor.com/project/ToruNiina/toml11) [![Build status](https://ci.appveyor.com/api/projects/status/m2n08a926asvg5mg?svg=true)](https://ci.appveyor.com/project/ToruNiina/toml11)
[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](https://doi.org/10.5281/zenodo.1209136)
c++11 header-only toml parser depending only on c++11 standard library. c++11 header-only toml parser depending only on c++11 standard library.

View File

@@ -170,3 +170,22 @@ BOOST_AUTO_TEST_CASE(test_from_toml_tie)
BOOST_CHECK_EQUAL(ut["val4"].cast<toml::value_t::String >(), "piyo"); BOOST_CHECK_EQUAL(ut["val4"].cast<toml::value_t::String >(), "piyo");
} }
BOOST_AUTO_TEST_CASE(test_from_toml_tuple)
{
toml::Array a;
a.emplace_back(2);
a.emplace_back(7);
a.emplace_back(1);
a.emplace_back(8);
a.emplace_back(2);
toml::value v(a);
std::tuple<int, int, int, int, int> t;
toml::from_toml(t, v);
BOOST_CHECK_EQUAL(std::get<0>(t), 2);
BOOST_CHECK_EQUAL(std::get<1>(t), 7);
BOOST_CHECK_EQUAL(std::get<2>(t), 1);
BOOST_CHECK_EQUAL(std::get<3>(t), 8);
BOOST_CHECK_EQUAL(std::get<4>(t), 2);
}

View File

@@ -74,16 +74,11 @@ BOOST_AUTO_TEST_CASE(test_is_xxx)
BOOST_CHECK(toml::detail::is_container<std_array_type>::value); BOOST_CHECK(toml::detail::is_container<std_array_type>::value);
BOOST_CHECK(toml::detail::is_container<std::set<dummy_type>>::value); BOOST_CHECK(toml::detail::is_container<std::set<dummy_type>>::value);
BOOST_CHECK(toml::detail::is_container<std::unordered_set<std::string>>::value); BOOST_CHECK(toml::detail::is_container<std::unordered_set<std::string>>::value);
BOOST_CHECK(toml::detail::is_container<std_map_type>::value);
BOOST_CHECK(toml::detail::is_container<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::is_container<dummy_container<dummy_type>>::value); BOOST_CHECK(toml::detail::is_container<dummy_container<dummy_type>>::value);
BOOST_CHECK(!toml::detail::is_container<std_map_type>::value);
BOOST_CHECK(!toml::detail::is_container<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::is_map<std_map_type>::value); BOOST_CHECK(toml::detail::is_map<std_map_type>::value);
BOOST_CHECK(toml::detail::is_map<std_unordered_map_type>::value); BOOST_CHECK(toml::detail::is_map<std_unordered_map_type>::value);
BOOST_CHECK(toml::detail::is_key_convertible<std_map_type>::value);
BOOST_CHECK(toml::detail::is_key_convertible<std_unordered_map_type>::value);
} }

View File

@@ -1,66 +1,14 @@
#ifndef TOML11_FROM_TOML #ifndef TOML11_FROM_TOML
#define TOML11_FROM_TOML #define TOML11_FROM_TOML
#include "value.hpp" #include "get.hpp"
namespace toml namespace toml
{ {
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T>
typename std::enable_if<(vT != toml::value_t::Unknown &&
vT != value_t::Empty), std::nullptr_t>::type = nullptr>
void from_toml(T& x, const toml::value& v) void from_toml(T& x, const toml::value& v)
{ {
if(v.type() != vT) x = toml::get<T>(v);
throw type_error("from_toml: value type: " + stringize(v.type()) +
std::string(" is not arguemnt type: ") + stringize(vT));
x = v.cast<vT>();
return;
}
template<typename T, toml::value_t vT = toml::detail::check_type<T>(),
typename std::enable_if<(vT == toml::value_t::Unknown) &&
(!toml::detail::is_map<T>::value) &&
toml::detail::is_container<T>::value, std::nullptr_t>::type = nullptr>
void from_toml(T& x, const toml::value& v)
{
// TODO the case of x is not dynamic container case
if(v.type() != value_t::Array)
throw type_error("from_toml: value type: " + stringize(v.type()) +
std::string(" is not argument type: Array"));
const auto& ar = v.cast<value_t::Array>();
try
{
toml::resize(x, ar.size());
}
catch(std::invalid_argument& iv)
{
throw toml::type_error("toml::from_toml: static array size is not enough");
}
auto iter = x.begin();
for(const auto& val : ar)
{
typename T::value_type v;
from_toml(v, val);
*iter = std::move(v);
++iter;
}
return;
}
template<typename T, toml::value_t vT = toml::detail::check_type<T>(),
typename std::enable_if<(vT == toml::value_t::Unknown) &&
toml::detail::is_map<T>::value, std::nullptr_t>::type = nullptr>
void from_toml(T& x, const toml::value& v)
{
if(v.type() != value_t::Table)
throw type_error("from_toml: value type: " + stringize(v.type()) +
std::string(" is not argument type: Table"));
x.clear();
const auto& tb = v.cast<value_t::Table>();
for(const auto& kv : tb)
{
x.insert(kv);
}
return; return;
} }

View File

@@ -6,55 +6,121 @@
namespace toml namespace toml
{ {
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<
typename std::enable_if<(vT != toml::value_t::Unknown && detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
vT != value_t::Empty), std::nullptr_t>::type = nullptr> inline T& get(value& v)
inline T get(const toml::value& v)
{ {
return static_cast<T>(v.cast<vT>()); constexpr value_t kind = detail::check_type<T>();
return v.cast<kind>();
}
template<typename T, typename std::enable_if<
detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
inline T const& get(const value& v)
{
constexpr value_t kind = detail::check_type<T>();
return v.cast<kind>();
}
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>,
detail::negation<std::is_same<T, bool>>, std::is_integral<T>
>::value, std::nullptr_t>::type = nullptr>
inline T get(const value& v)
{
return static_cast<T>(v.cast<value_t::Integer>());
}
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>, std::is_floating_point<T>
>::value, std::nullptr_t>::type = nullptr>
inline T get(const value& v)
{
return static_cast<T>(v.cast<value_t::Float>());
} }
// array-like type // array-like type
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<detail::conjunction<
typename std::enable_if<(vT == toml::value_t::Unknown) && detail::negation<detail::is_exact_toml_type<T>>, detail::is_container<T>
(!toml::detail::is_map<T>::value) && >::value, std::nullptr_t>::type = nullptr>
toml::detail::is_container<T>::value, std::nullptr_t>::type = nullptr> T get(const value& v)
T get(const toml::value& v)
{ {
if(v.type() != value_t::Array)
throw type_error("get: value type: " + stringize(v.type()) +
std::string(" is not argument type: Array"));
const auto& ar = v.cast<value_t::Array>(); const auto& ar = v.cast<value_t::Array>();
T tmp; T tmp;
try try
{ {
toml::resize(tmp, ar.size()); ::toml::resize(tmp, ar.size());
} }
catch(std::invalid_argument& iv) catch(std::invalid_argument& iv)
{ {
throw toml::type_error("toml::get: static array size is not enough"); throw type_error("toml::get: static array: size is not enough");
} }
std::transform(ar.cbegin(), ar.cend(), tmp.begin(), std::transform(ar.cbegin(), ar.cend(), tmp.begin(),
[](toml::value const& elem){return get<typename T::value_type>(elem);}); [](value const& elem){return get<typename T::value_type>(elem);});
return tmp; return tmp;
} }
// table-like case // table-like case
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<detail::conjunction<
typename std::enable_if<(vT == toml::value_t::Unknown) && detail::negation<detail::is_exact_toml_type<T>>, detail::is_map<T>
toml::detail::is_map<T>::value, std::nullptr_t>::type = nullptr> >::value, std::nullptr_t>::type = nullptr>
T get(const toml::value& v) T get(const toml::value& v)
{ {
if(v.type() != value_t::Table)
throw type_error("get: value type: " + stringize(v.type()) +
std::string(" is not argument type: Table"));
T tmp;
const auto& tb = v.cast<value_t::Table>(); const auto& tb = v.cast<value_t::Table>();
T tmp;
for(const auto& kv : tb){tmp.insert(kv);} for(const auto& kv : tb){tmp.insert(kv);}
return tmp; return tmp;
} }
// array -> pair
template<typename T, typename std::enable_if<detail::is_std_pair<T>::value,
std::nullptr_t>::type = nullptr>
T get(const value& v)
{
using first_type = typename T::first_type;
using second_type = typename T::second_type;
const auto& ar = v.cast<value_t::Array>();
if(ar.size() != 2)
{
throw std::out_of_range(
"toml::get<std::pair>: value does not have 2 elements.");
}
T tmp;
tmp.first = get<first_type >(ar.at(0));
tmp.second = get<second_type>(ar.at(1));
return tmp;
}
namespace detail
{
template<typename T, std::size_t ...I>
T get_tuple_impl(const toml::Array& a, index_sequence<I...>)
{
return std::make_tuple(
::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
}
} // detail
// array -> tuple
template<typename T, typename std::enable_if<detail::is_std_tuple<T>::value,
std::nullptr_t>::type = nullptr>
T get(const value& v)
{
const auto& ar = v.cast<value_t::Array>();
if(ar.size() != std::tuple_size<T>::value)
{
throw std::out_of_range(
"toml::get<std::tuple>: array value does not have " +
std::to_string(std::tuple_size<T>::value) +
std::string(" elements (array has ") + std::to_string(ar.size()) +
std::string(" elements)."));
}
return detail::get_tuple_impl<T>(ar,
detail::make_index_sequence<std::tuple_size<T>::value>{});
}
// get_or ----------------------------------------------------------------- // get_or -----------------------------------------------------------------
template<typename T> template<typename T>

View File

@@ -5,47 +5,76 @@
namespace toml namespace toml
{ {
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<
typename std::enable_if<(vT != toml::value_t::Unknown && detail::is_exact_toml_type<T>::value, std::nullptr_t>::type = nullptr>
vT != value_t::Empty), std::nullptr_t>::type = nullptr> inline value to_toml(const T& x)
inline toml::value to_toml(T&& x)
{ {
return toml::value(std::forward<T>(x)); return value(x);
} }
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<detail::conjunction<
typename std::enable_if<(vT == toml::value_t::Unknown) && detail::negation<detail::is_exact_toml_type<T>>, std::is_integral<T>
(!toml::detail::is_map<T>::value) && >::value, std::nullptr_t>::type = nullptr>
toml::detail::is_container<T>::value, std::nullptr_t>::type = nullptr> inline value to_toml(const T& x)
toml::value to_toml(T&& x)
{ {
toml::Array tmp; tmp.reserve(std::distance(std::begin(x), std::end(x))); return value(::toml::Integer(x));
}
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>, std::is_floating_point<T>
>::value, std::nullptr_t>::type = nullptr>
inline value to_toml(const T& x)
{
return value(::toml::Float(x));
}
inline value to_toml(const char* str)
{
return value(::toml::String(str));
}
template<typename T, typename std::enable_if<detail::conjunction<
detail::negation<detail::is_exact_toml_type<T>>, detail::is_container<T>
>::value, std::nullptr_t>::type = nullptr>
value to_toml(const T& x)
{
Array tmp;
tmp.reserve(std::distance(std::begin(x), std::end(x)));
for(auto iter = std::begin(x); iter != std::end(x); ++iter) for(auto iter = std::begin(x); iter != std::end(x); ++iter)
{
tmp.emplace_back(*iter); tmp.emplace_back(*iter);
return toml::value(std::move(tmp)); }
return value(std::move(tmp));
} }
template<typename T, toml::value_t vT = toml::detail::check_type<T>(), template<typename T, typename std::enable_if<detail::conjunction<
typename std::enable_if<(vT == toml::value_t::Unknown) && detail::negation<detail::is_exact_toml_type<T>>, detail::is_map<T>
toml::detail::is_map<T>::value, std::nullptr_t>::type = nullptr> >::value, std::nullptr_t>::type = nullptr>
toml::value to_toml(T&& x) value to_toml(const T& x)
{ {
toml::Table tmp; Table tmp;
for(auto iter = std::begin(x); iter != std::end(x); ++iter) for(auto iter = std::begin(x); iter != std::end(x); ++iter)
{
tmp.emplace(iter->first, to_toml(iter->second)); tmp.emplace(iter->first, to_toml(iter->second));
return toml::value(std::move(tmp)); }
return value(std::move(tmp));
} }
template<typename T> template<typename T>
inline toml::value to_toml(std::initializer_list<T> init) inline value to_toml(std::initializer_list<T> init)
{ {
return toml::value(std::move(init)); return value(std::move(init));
} }
inline toml::value inline value to_toml(std::initializer_list<std::pair<std::string, value>> init)
to_toml(std::initializer_list<std::pair<std::string, toml::value>> init)
{ {
return toml::value(std::move(init)); return value(std::move(init));
}
template<typename T>
inline value to_toml(const value& x)
{
return x;
} }
} // toml } // toml

View File

@@ -1,6 +1,8 @@
#ifndef TOML11_TRAITS #ifndef TOML11_TRAITS
#define TOML11_TRAITS #define TOML11_TRAITS
#include <type_traits> #include <type_traits>
#include <utility>
#include <tuple>
namespace toml namespace toml
{ {
@@ -58,14 +60,54 @@ struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){}
#undef decltype(...) #undef decltype(...)
#endif #endif
template<typename T> template<typename ...> struct conjunction : std::true_type{};
struct is_container : std::integral_constant<bool, template<typename T> struct conjunction<T> : T{};
has_iterator<T>::value && has_value_type<T>::value>{}; template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};
template<typename ...> struct disjunction : std::false_type{};
template<typename T> struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};
template<typename T> template<typename T>
struct is_map : std::integral_constant<bool, struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
has_iterator<T>::value && has_key_type<T>::value &&
has_mapped_type<T>::value>{}; template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};
template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
// to use toml::get<std::tuple<T1, T2, ...>> in C++11
template<std::size_t ... Ns> struct index_sequence{};
template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
typedef index_sequence<Ns..., N> type;
};
template<std::size_t N>
struct index_sequence_maker
{
typedef typename push_back_index_sequence<
typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;
}// detail }// detail
}//toml }//toml

View File

@@ -99,33 +99,6 @@ constexpr inline bool is_valid(value_t vt)
return vt != value_t::Unknown; return vt != value_t::Unknown;
} }
template<typename T> struct is_toml_array : std::false_type{};
template<> struct is_toml_array<toml::Array> : std::true_type {};
template<typename T> struct is_toml_table : std::false_type{};
template<> struct is_toml_table<toml::Table> : std::true_type {};
struct is_key_convertible_impl
{
template<typename T>
static std::is_convertible<typename T::key_type, toml::key>
check(typename T::key_type*);
template<typename T> static std::false_type check(...);
};
/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif
template<typename T>
struct is_key_convertible : decltype(is_key_convertible_impl::check<T>(nullptr)){};
#ifdef __INTEL_COMPILER
#undef decltype(...)
#endif
template<value_t t> struct toml_default_type{}; template<value_t t> struct toml_default_type{};
template<> struct toml_default_type<value_t::Boolean >{typedef Boolean type;}; template<> struct toml_default_type<value_t::Boolean >{typedef Boolean type;};
template<> struct toml_default_type<value_t::Integer >{typedef Integer type;}; template<> struct toml_default_type<value_t::Integer >{typedef Integer type;};
@@ -137,6 +110,33 @@ template<> struct toml_default_type<value_t::Table >{typedef Table type;};
template<> struct toml_default_type<value_t::Empty >{typedef void type;}; template<> struct toml_default_type<value_t::Empty >{typedef void type;};
template<> struct toml_default_type<value_t::Unknown >{typedef void type;}; template<> struct toml_default_type<value_t::Unknown >{typedef void type;};
template<typename T>
struct is_exact_toml_type : disjunction<
std::is_same<T, Boolean >,
std::is_same<T, Integer >,
std::is_same<T, Float >,
std::is_same<T, String >,
std::is_same<T, Datetime>,
std::is_same<T, Array >,
std::is_same<T, Table >
>{};
template<typename T>
struct is_map : conjunction<
has_iterator<T>,
has_value_type<T>,
has_key_type<T>,
has_mapped_type<T>
>{};
template<typename T>
struct is_container : conjunction<
negation<is_map<T>>,
negation<std::is_same<T, String>>,
has_iterator<T>,
has_value_type<T>
>{};
struct storage_base struct storage_base
{ {
storage_base(): type(toml::value_t::Empty){} storage_base(): type(toml::value_t::Empty){}
@@ -148,7 +148,8 @@ struct storage_base
template<typename T> template<typename T>
struct storage : public storage_base struct storage : public storage_base
{ {
static_assert(is_toml_array<T>::value || is_toml_table<T>::value, static_assert(std::is_same<T, toml::Array>::value ||
std::is_same<T, toml::Table>::value,
"toml::detail::storage is for toml::Array or toml::Table!"); "toml::detail::storage is for toml::Array or toml::Table!");
typedef T value_type; typedef T value_type;
@@ -591,21 +592,21 @@ template<typename T, typename std::enable_if<
value_traits<T>::is_toml_type, std::nullptr_t>::type> value_traits<T>::is_toml_type, std::nullptr_t>::type>
value::value(T&& v) : type_(toml::detail::check_type<T>()) value::value(T&& v) : type_(toml::detail::check_type<T>())
{ {
switch_assign<toml::detail::check_type<T>()>::invoke( constexpr value_t kind = toml::detail::check_type<T>();
*this, std::forward<T>(v)); switch_assign<kind>::invoke(*this, std::forward<T>(v));
} }
template<typename T, typename std::enable_if< template<typename T, typename std::enable_if<
value_traits<T>::is_toml_type, std::nullptr_t>::type> value_traits<T>::is_toml_type, std::nullptr_t>::type>
value& value::operator=(T&& v) value& value::operator=(T&& v)
{ {
constexpr value_t kind = toml::detail::check_type<T>();
if(should_be_cleaned(this->type_)) if(should_be_cleaned(this->type_))
{ {
switch_clean(this->type_); switch_clean(this->type_);
} }
this->type_ = toml::detail::check_type<T>(); this->type_ = kind;
switch_assign<toml::detail::check_type<T>()>::invoke( switch_assign<kind>::invoke(*this, std::forward<T>(v));
*this, std::forward<T>(v));
return *this; return *this;
} }