Compare commits

...

5 Commits
main ... visit

Author SHA1 Message Date
ToruNiina
bfe5e50acf test: add missing include files 2020-02-07 21:00:11 +09:00
ToruNiina
05077dee0c test: add test_visit 2020-02-07 15:58:15 +09:00
ToruNiina
b9f1726e26 feat: add multi-argument toml::visit(visitor, ...) 2020-02-07 15:57:34 +09:00
ToruNiina
c583e38ebf fix: include visit.hpp from serializer 2020-02-07 15:57:09 +09:00
ToruNiina
388e9db32b refactor: move visit() from value.hpp to visit.hpp 2020-01-31 22:48:37 +09:00
5 changed files with 308 additions and 72 deletions

View File

@@ -34,6 +34,7 @@ set(TEST_NAMES
test_error_detection
test_format_error
test_extended_conversions
test_visit
)
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)

172
tests/test_visit.cpp Normal file
View File

@@ -0,0 +1,172 @@
#define BOOST_TEST_MODULE "test_visit"
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif
#include <toml.hpp>
#include <map>
#include <deque>
using test_value_types = std::tuple<
toml::value,
toml::basic_value<toml::preserve_comments>,
toml::basic_value<toml::discard_comments, std::map, std::deque>,
toml::basic_value<toml::preserve_comments, std::map, std::deque>
>;
template<typename Value>
struct visitor1
{
std::string operator()(const toml::boolean&) const {return "boolean";}
std::string operator()(const toml::integer&) const {return "integer";}
std::string operator()(const toml::floating&) const {return "floating";}
std::string operator()(const toml::string&) const {return "string";}
std::string operator()(const toml::local_time&) const {return "local_time";}
std::string operator()(const toml::local_date&) const {return "local_date";}
std::string operator()(const toml::local_datetime&) const {return "local_datetime";}
std::string operator()(const toml::offset_datetime&) const {return "offset_datetime";}
std::string operator()(const typename Value::array_type&) const {return "array";}
std::string operator()(const typename Value::table_type&) const {return "table";}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_one, value_type, test_value_types)
{
{
const value_type v(true);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "boolean");
}
{
const value_type v(42);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "integer");
}
{
const value_type v(3.14);
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "floating");
}
{
const value_type v("foo");
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "string");
}
{
const value_type v(toml::local_date(2018, toml::month_t::Apr, 22));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_date");
}
{
const value_type v(toml::local_time(12, 34, 56));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_time");
}
{
const value_type v(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56)));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "local_datetime");
}
{
const value_type v(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0)));
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "offset_datetime");
}
{
const value_type v{1,2,3,4,5};
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "array");
}
{
const value_type v{
{"foo", 42}, {"bar", "baz"}
};
BOOST_TEST(toml::visit(visitor1<value_type>{}, v) == "table");
}
}
template<typename Value>
struct visitor2
{
template<typename T1, typename T2>
std::string operator()(const T1& v1, const T2& v2) const
{
visitor1<Value> vis;
return vis(v1) + "+" + vis(v2);
}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_two, value_type, test_value_types)
{
std::vector<value_type> vs;
vs.push_back(value_type(true));
vs.push_back(value_type(42));
vs.push_back(value_type(3.14));
vs.push_back(value_type("foo"));
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
vs.push_back(value_type(toml::local_time(12, 34, 56)));
vs.push_back(value_type(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56))));
vs.push_back(value_type(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0))));
vs.push_back(value_type{1,2,3,4,5});
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
for(const auto& v1 : vs)
{
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
for(const auto& v2 : vs)
{
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
BOOST_TEST(toml::visit(visitor2<value_type>{}, v1, v2) ==
t1 + "+" + t2);
}
}
}
template<typename Value>
struct visitor3
{
template<typename T1, typename T2, typename T3>
std::string operator()(const T1& v1, const T2& v2, const T3& v3) const
{
visitor1<Value> vis;
return vis(v1) + "+" + vis(v2) + "+" + vis(v3);
}
};
BOOST_AUTO_TEST_CASE_TEMPLATE(test_visit_three, value_type, test_value_types)
{
std::vector<value_type> vs;
vs.push_back(value_type(true));
vs.push_back(value_type(42));
vs.push_back(value_type(3.14));
vs.push_back(value_type("foo"));
vs.push_back(value_type(toml::local_date(2018, toml::month_t::Apr, 22)));
vs.push_back(value_type(toml::local_time(12, 34, 56)));
vs.push_back(value_type(toml::local_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56))));
vs.push_back(value_type(toml::offset_datetime(
toml::local_date(2018, toml::month_t::Apr, 22),
toml::local_time(12, 34, 56),
toml::time_offset(9, 0))));
vs.push_back(value_type{1,2,3,4,5});
vs.push_back(value_type{{"foo", 42}, {"bar", "baz"}});
for(const auto& v1 : vs)
{
const auto t1 = toml::visit(visitor1<value_type>{}, v1);
for(const auto& v2 : vs)
{
const auto t2 = toml::visit(visitor1<value_type>{}, v2);
for(const auto& v3 : vs)
{
const auto t3 = toml::visit(visitor1<value_type>{}, v3);
BOOST_TEST(toml::visit(visitor3<value_type>{}, v1, v2, v3) ==
t1 + "+" + t2 + "+" + t3);
}
}
}
}

View File

@@ -4,6 +4,7 @@
#define TOML11_SERIALIZER_HPP
#include "value.hpp"
#include "lexer.hpp"
#include "visit.hpp"
#include <limits>
#include <cstdio>

View File

@@ -1995,77 +1995,5 @@ inline std::string format_error(const std::string& err_msg,
}, std::move(hints), colorize);
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, const toml::boolean&>
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(std::move(v.as_boolean ()));}
case value_t::integer : {return visitor(std::move(v.as_integer ()));}
case value_t::floating : {return visitor(std::move(v.as_floating ()));}
case value_t::string : {return visitor(std::move(v.as_string ()));}
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
case value_t::array : {return visitor(std::move(v.as_array ()));}
case value_t::table : {return visitor(std::move(v.as_table ()));}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
}// toml
#endif// TOML11_VALUE

134
toml/visit.hpp Normal file
View File

@@ -0,0 +1,134 @@
// Copyright Toru Niina 2019.
// Distributed under the MIT License.
#ifndef TOML11_VISIT_HPP
#define TOML11_VISIT_HPP
#include "value.hpp"
namespace toml
{
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, const toml::boolean&>
visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(v.as_boolean ());}
case value_t::integer : {return visitor(v.as_integer ());}
case value_t::floating : {return visitor(v.as_floating ());}
case value_t::string : {return visitor(v.as_string ());}
case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
case value_t::local_date : {return visitor(v.as_local_date ());}
case value_t::local_time : {return visitor(v.as_local_time ());}
case value_t::array : {return visitor(v.as_array ());}
case value_t::table : {return visitor(v.as_table ());}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
template<typename Visitor, typename C,
template<typename ...> class T, template<typename ...> class A>
detail::return_type_of_t<Visitor, toml::boolean&&>
visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
{
switch(v.type())
{
case value_t::boolean : {return visitor(std::move(v.as_boolean ()));}
case value_t::integer : {return visitor(std::move(v.as_integer ()));}
case value_t::floating : {return visitor(std::move(v.as_floating ()));}
case value_t::string : {return visitor(std::move(v.as_string ()));}
case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
case value_t::local_date : {return visitor(std::move(v.as_local_date ()));}
case value_t::local_time : {return visitor(std::move(v.as_local_time ()));}
case value_t::array : {return visitor(std::move(v.as_array ()));}
case value_t::table : {return visitor(std::move(v.as_table ()));}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
namespace detail
{
template<typename Result, typename Visitor, typename Value>
struct visitor
{
template<typename ... Ts>
Result operator()(Ts&& ... args)
{
return vis(value, args ...);
}
Visitor vis;
Value value;
};
template<typename Result, typename Visitor, typename Value>
visitor<Result, Visitor, Value> make_visitor(Visitor&& vis, Value&& val)
{
return visitor<Result, Visitor, Value>{
std::forward<Visitor>(vis), std::forward<Value>(val)
};
}
} // detail
template<typename Visitor, typename Value, typename ... Values>
auto visit(Visitor&& visitor, Value&& v, Values&& ... vs)
-> detail::enable_if_t<detail::conjunction<
detail::is_basic_value<Value>, detail::is_basic_value<Values> ...
>::value, decltype(visitor(std::forward<Value >(v ).as_boolean(),
std::forward<Values>(vs).as_boolean()...))>
{
using result_t = decltype(visitor(v.as_boolean(), vs.as_boolean()...));
using detail::make_visitor;
switch(v.type())
{
case value_t::boolean : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_boolean ()), std::forward<Values>(vs)...);}
case value_t::integer : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_integer ()), std::forward<Values>(vs)...);}
case value_t::floating : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_floating ()), std::forward<Values>(vs)...);}
case value_t::string : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_string ()), std::forward<Values>(vs)...);}
case value_t::offset_datetime: {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_offset_datetime()), std::forward<Values>(vs)...);}
case value_t::local_datetime : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_datetime ()), std::forward<Values>(vs)...);}
case value_t::local_date : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_date ()), std::forward<Values>(vs)...);}
case value_t::local_time : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_local_time ()), std::forward<Values>(vs)...);}
case value_t::array : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_array ()), std::forward<Values>(vs)...);}
case value_t::table : {return visit(make_visitor<result_t>(std::forward<Visitor>(visitor), v.as_table ()), std::forward<Values>(vs)...);}
case value_t::empty : break;
default: break;
}
throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
"does not have any valid basic_value.", v, "here"));
}
} // toml
#endif// TOML11_VISIT_HPP