Skip to content

Commit

Permalink
Merge pull request #170 from octopus-prime/develop
Browse files Browse the repository at this point in the history
Cleaned up container_traits.
  • Loading branch information
djowel committed Feb 21, 2016
2 parents c8ed3fe + 8602d2b commit 3cee512
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 129 deletions.
47 changes: 26 additions & 21 deletions include/boost/spirit/home/x3/support/traits/container_traits.hpp
Expand Up @@ -61,6 +61,21 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
typedef typename remove_value_const<S>::type second_type;
typedef std::pair<first_type, second_type> type;
};

template <class Container>
struct has_reserve_method
{
template <class T>
static std::true_type test_signature(void (T::*)(std::size_t));

template <class T>
static decltype(test_signature(&T::reserve)) test(std::nullptr_t);

template <class T>
static std::false_type test(...);

using type = decltype(test<Container>(nullptr));
};
}

///////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -111,16 +126,10 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
template <typename Container, typename Enable = void>
struct push_back_container
{
template <typename T>
static void push_back(Container& c, T&& val)
{
c.insert(c.end(), std::move(val));
}

template <typename T>
static bool call(Container& c, T&& val)
{
push_back(c, std::move(val));
c.insert(c.end(), std::move(val));
return true;
}
};
Expand All @@ -138,7 +147,7 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
}

template <typename T>
inline bool push_back(unused_type, T const&)
inline bool push_back(unused_type, T&&)
{
return true;
}
Expand All @@ -155,27 +164,23 @@ namespace boost { namespace spirit { namespace x3 { namespace traits
template <typename Container, typename Enable = void>
struct append_container
{
// Not all containers have "reserve"
template <typename Container_>
static void reserve(Container_& c, std::size_t size) {}

template <typename T, typename Allocator>
static void reserve(std::vector<T, Allocator>& c, std::size_t size)
template <typename Iterator>
static void reserve(Container& c, Iterator first, Iterator last, std::false_type)
{
c.reserve(size);
// Not all containers have "reserve"
}
template <typename Container_, typename Iterator>
static void insert(Container_& c, Iterator first, Iterator last)

template <typename Iterator>
static void reserve(Container& c, Iterator first, Iterator last, std::true_type)
{
std::copy(first, last, std::inserter(c, c.end()));
c.reserve(c.size() + std::distance(first, last));
}

template <typename Iterator>
static bool call(Container& c, Iterator first, Iterator last)
{
reserve(c, c.size() + std::distance(first, last));
insert(c, first, last);
reserve(c, first, last, typename detail::has_reserve_method<Container>::type{});
c.insert(c.end(), first, last);
return true;
}
};
Expand Down
180 changes: 72 additions & 108 deletions test/x3/container_support.cpp
Expand Up @@ -5,6 +5,7 @@
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

#include <boost/detail/lightweight_test.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/std_pair.hpp>
Expand All @@ -24,175 +25,138 @@

namespace x3 = boost::spirit::x3;

x3::rule<class std_map_rule, std::map<std::string,std::string>> const std_map_rule("std_map");
x3::rule<class std_unordered_map_rule, std::unordered_map<std::string,std::string>> const std_unordered_map_rule("std_unordered_map");
x3::rule<class boost_unordered_map_rule, boost::unordered_map<std::string,std::string>> const boost_unordered_map_rule("boost_unordered_map");

x3::rule<class std_multimap_rule, std::multimap<std::string,std::string>> const std_multimap_rule("std_multimap");
x3::rule<class std_unordered_multimap_rule, std::unordered_multimap<std::string,std::string>> const std_unordered_multimap_rule("std_unordered_multimap");
x3::rule<class boost_unordered_multimap_rule, boost::unordered_multimap<std::string,std::string>> const boost_unordered_multimap_rule("boost_unordered_multimap");

x3::rule<class std_vector_rule, std::vector<std::string>> const std_vector_rule("std_vector");
x3::rule<class std_list_rule, std::list<std::string>> const std_list_rule("std_list");
x3::rule<class std_deque_rule, std::deque<std::string>> const std_deque_rule("std_deque");

x3::rule<class std_set_rule, std::set<std::string>> const std_set_rule("std_set");
x3::rule<class std_unordered_set_rule, std::unordered_set<std::string>> const std_unordered_set_rule("std_unordered_set");
x3::rule<class boost_unordered_set_rule, boost::unordered_set<std::string>> const boost_unordered_set_rule("boost_unordered_set");

x3::rule<class std_multiset_rule, std::multiset<std::string>> const std_multiset_rule("std_multiset");
x3::rule<class std_unordered_multiset_rule, std::unordered_multiset<std::string>> const std_unordered_multiset_rule("std_unordered_multiset");
x3::rule<class boost_unordered_multiset_rule, boost::unordered_multiset<std::string>> const boost_unordered_multiset_rule("boost_unordered_multiset");

x3::rule<class std_string_rule, std::string> const std_string_rule("std_string");

x3::rule<class pair_rule, std::pair<std::string,std::string>> const pair_rule("pair");
x3::rule<class string_rule, std::string> const string_rule("string");

auto const std_map_rule_def = pair_rule % x3::lit(',');
auto const std_unordered_map_rule_def = pair_rule % x3::lit(',');
auto const boost_unordered_map_rule_def = pair_rule % x3::lit(',');

auto const std_multimap_rule_def = pair_rule % x3::lit(',');
auto const std_unordered_multimap_rule_def = pair_rule % x3::lit(',');
auto const boost_unordered_multimap_rule_def = pair_rule % x3::lit(',');

auto const std_vector_rule_def = string_rule % x3::lit(',');
auto const std_list_rule_def = string_rule % x3::lit(',');
auto const std_deque_rule_def = string_rule % x3::lit(',');

auto const std_set_rule_def = string_rule % x3::lit(',');
auto const std_unordered_set_rule_def = string_rule % x3::lit(',');
auto const boost_unordered_set_rule_def = string_rule % x3::lit(',');

auto const std_multiset_rule_def = string_rule % x3::lit(',');
auto const std_unordered_multiset_rule_def = string_rule % x3::lit(',');
auto const boost_unordered_multiset_rule_def = string_rule % x3::lit(',');

auto const std_string_rule_def = string_rule % x3::lit(',');

auto const pair_rule_def = string_rule > x3::lit('=') > string_rule;
auto const string_rule_def = x3::lexeme[*x3::alnum];

BOOST_SPIRIT_DEFINE
(
std_map_rule, std_unordered_map_rule, boost_unordered_map_rule,
std_multimap_rule, std_unordered_multimap_rule, boost_unordered_multimap_rule,
std_vector_rule, std_list_rule, std_deque_rule,
std_set_rule, std_unordered_set_rule, boost_unordered_set_rule,
std_multiset_rule, std_unordered_multiset_rule, boost_unordered_multiset_rule,
std_string_rule,
pair_rule, string_rule
);
BOOST_SPIRIT_DEFINE(pair_rule, string_rule);

template <typename Container>
void test_map_support(const auto& rule)
void test_map_support(Container&& container)
{
using spirit_test::test_attr;
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("k1=v1,k2=v2,k2=v3", rule, container));
Container const compare {{"k1", "v1"}, {"k2", "v2"}};
auto const rule = pair_rule % x3::lit(',');

BOOST_TEST(container.size() == 2);

Container compare {{"k1", "v1"}, {"k2", "v2"}};
BOOST_TEST(container == compare);
BOOST_TEST(test_attr("k1=v1,k2=v2,k2=v3", rule, container));
BOOST_TEST(container.size() == 2);
BOOST_TEST(container == compare);
}

template <typename Container>
void test_multimap_support(const auto& rule)
void test_multimap_support(Container&& container)
{
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("k1=v1,k2=v2,k2=v3", rule, container));
Container const compare {{"k1", "v1"}, {"k2", "v2"}, {"k2", "v3"}};
auto const rule = pair_rule % x3::lit(',');

BOOST_TEST(test_attr("k1=v1,k2=v2,k2=v3", rule, container));
BOOST_TEST(container.size() == 3);

Container compare {{"k1", "v1"}, {"k2", "v2"}, {"k2", "v3"}};
BOOST_TEST(container == compare);
}

template <typename Container>
void test_sequence_support(const auto& rule)
void test_sequence_support(Container&& container)
{
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("e1,e2,e2", rule, container));
Container const compare {"e1", "e2", "e2"};
auto const rule = string_rule % x3::lit(',');

BOOST_TEST(test_attr("e1,e2,e2", rule, container));
BOOST_TEST(container.size() == 3);

Container compare {"e1", "e2", "e2"};
BOOST_TEST(container == compare);
}

template <typename Container>
void test_set_support(const auto& rule)
void test_set_support(Container&& container)
{
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("e1,e2,e2", rule, container));
Container const compare {"e1", "e2"};
auto const rule = string_rule % x3::lit(',');

BOOST_TEST(test_attr("e1,e2,e2", rule, container));
BOOST_TEST(container.size() == 2);

Container compare {"e1", "e2"};
BOOST_TEST(container == compare);
}

template <typename Container>
void test_multiset_support(const auto& rule)
void test_multiset_support(Container&& container)
{
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("e1,e2,e2", rule, container));
Container const compare {"e1", "e2", "e2"};
auto const rule = string_rule % x3::lit(',');

BOOST_TEST(test_attr("e1,e2,e2", rule, container));
BOOST_TEST(container.size() == 3);

Container compare {"e1", "e2", "e2"};
BOOST_TEST(container == compare);
}

template <typename Container>
void test_string_support(const auto& rule)
void test_string_support(Container&& container)
{
using spirit_test::test_attr;

Container container;
BOOST_TEST(test_attr("e1,e2,e2", rule, container));
Container const compare {"e1e2e2"};
auto const rule = string_rule % x3::lit(',');

BOOST_TEST(test_attr("e1,e2,e2", rule, container));
BOOST_TEST(container.size() == 6);

Container compare {"e1e2e2"};
BOOST_TEST(container == compare);
}

int
main()
{
test_map_support<std::map<std::string,std::string>>(std_map_rule);
test_map_support<std::unordered_map<std::string,std::string>>(std_unordered_map_rule);
test_map_support<boost::unordered_map<std::string,std::string>>(boost_unordered_map_rule);

test_multimap_support<std::multimap<std::string,std::string>>(std_multimap_rule);
test_multimap_support<std::unordered_multimap<std::string,std::string>>(std_unordered_multimap_rule);
test_multimap_support<boost::unordered_multimap<std::string,std::string>>(boost_unordered_multimap_rule);

test_sequence_support<std::vector<std::string>>(std_vector_rule);
test_sequence_support<std::list<std::string>>(std_list_rule);
test_sequence_support<std::deque<std::string>>(std_deque_rule);

test_set_support<std::set<std::string>>(std_set_rule);
test_set_support<std::unordered_set<std::string>>(std_unordered_set_rule);
test_set_support<boost::unordered_set<std::string>>(boost_unordered_set_rule);

test_multiset_support<std::multiset<std::string>>(std_multiset_rule);
test_multiset_support<std::unordered_multiset<std::string>>(std_unordered_multiset_rule);
test_multiset_support<boost::unordered_multiset<std::string>>(boost_unordered_multiset_rule);

test_string_support<std::string>(std_string_rule);
using x3::traits::detail::has_reserve_method;

static_assert(typename has_reserve_method<std::vector<int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<std::string>::type{}, "reserve problem");
static_assert(typename has_reserve_method<std::unordered_set<int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<boost::unordered_set<int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<std::unordered_multiset<int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<boost::unordered_multiset<int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<std::unordered_map<int,int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<boost::unordered_map<int,int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<std::unordered_multimap<int,int>>::type{}, "reserve problem");
static_assert(typename has_reserve_method<boost::unordered_multimap<int,int>>::type{}, "reserve problem");

static_assert(!typename has_reserve_method<std::deque<int>>::type{}, "reserve problem");
static_assert(!typename has_reserve_method<std::list<int>>::type{}, "reserve problem");
static_assert(!typename has_reserve_method<std::set<int>>::type{}, "reserve problem");
static_assert(!typename has_reserve_method<std::multiset<int>>::type{}, "reserve problem");
static_assert(!typename has_reserve_method<std::map<int,int>>::type{}, "reserve problem");
static_assert(!typename has_reserve_method<std::multimap<int,int>>::type{}, "reserve problem");

// ------------------------------------------------------------------

test_string_support(std::string());

test_sequence_support(std::vector<std::string>());
test_sequence_support(std::list<std::string>());
test_sequence_support(std::deque<std::string>());

test_set_support(std::set<std::string>());
test_set_support(std::unordered_set<std::string>());
test_set_support(boost::unordered_set<std::string>());

test_multiset_support(std::multiset<std::string>());
test_multiset_support(std::unordered_multiset<std::string>());
test_multiset_support(boost::unordered_multiset<std::string>());

test_map_support(std::map<std::string,std::string>());
test_map_support(std::unordered_map<std::string,std::string>());
test_map_support(boost::unordered_map<std::string,std::string>());

test_multimap_support(std::multimap<std::string,std::string>());
test_multimap_support(std::unordered_multimap<std::string,std::string>());
test_multimap_support(boost::unordered_multimap<std::string,std::string>());

return boost::report_errors();
}

0 comments on commit 3cee512

Please sign in to comment.