boost/spirit/home/x3/support/traits/container_traits.hpp
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
http://spirit.sourceforge.net/
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)
=============================================================================*/
#if !defined(BOOST_SPIRIT_X3_CONTAINER_FEBRUARY_06_2007_1001AM)
#define BOOST_SPIRIT_X3_CONTAINER_FEBRUARY_06_2007_1001AM
#include <boost/fusion/support/category_of.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/fusion/include/deque.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/make_void.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// This file contains some container utils for stl containers.
///////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename T, typename Enabler = void>
struct is_container_impl : mpl::false_ {};
template <typename T>
struct is_container_impl<T, void_t<
typename T::value_type, typename T::iterator,
typename T::size_type, typename T::reference> > : mpl::true_ {};
template <typename T, typename Enabler = void>
struct is_associative_impl : mpl::false_ {};
template <typename T>
struct is_associative_impl<T, void_t<typename T::key_type>>
: mpl::true_ {};
}
template <typename T>
using is_container = typename detail::is_container_impl<T>::type;
template <typename T>
using is_associative = typename detail::is_associative_impl<T>::type;
///////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename T>
struct remove_value_const : mpl::identity<T> {};
template <typename T>
struct remove_value_const<T const> : remove_value_const<T> {};
template <typename F, typename S>
struct remove_value_const<std::pair<F, S>>
{
typedef typename remove_value_const<F>::type first_type;
typedef typename remove_value_const<S>::type second_type;
typedef std::pair<first_type, second_type> type;
};
}
///////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct container_value
: detail::remove_value_const<typename Container::value_type>
{};
template <typename Container>
struct container_value<Container const> : container_value<Container> {};
// There is no single container value for fusion maps, but because output
// of this metafunc is used to check wheter parser's attribute can be
// saved to container, we simply return whole fusion::map as is
// so that check can be done in traits::is_substitute specialisation
template <typename T>
struct container_value<T
, typename enable_if<typename mpl::eval_if <
fusion::traits::is_sequence<T>
, fusion::traits::is_associative<T>
, mpl::false_ >::type >::type>
: mpl::identity<T> {};
template <>
struct container_value<unused_type> : mpl::identity<unused_type> {};
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct container_iterator
: mpl::identity<typename Container::iterator> {};
template <typename Container>
struct container_iterator<Container const>
: mpl::identity<typename Container::const_iterator> {};
template <>
struct container_iterator<unused_type>
: mpl::identity<unused_type const*> {};
template <>
struct container_iterator<unused_type const>
: mpl::identity<unused_type const*> {};
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename T>
bool push_back(Container& c, T&& val);
template <typename Container, typename Enable = void>
struct push_back_container
{
template <typename T>
static bool call(Container& c, T&& val)
{
c.insert(c.end(), static_cast<T&&>(val));
return true;
}
};
template <typename Container, typename T>
inline bool push_back(Container& c, T&& val)
{
return push_back_container<Container>::call(c, static_cast<T&&>(val));
}
template <typename Container>
inline bool push_back(Container&, unused_type)
{
return true;
}
template <typename T>
inline bool push_back(unused_type, T&&)
{
return true;
}
inline bool push_back(unused_type, unused_type)
{
return true;
}
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Iterator>
bool append(Container& c, Iterator first, Iterator last);
template <typename Container, typename Enable = void>
struct append_container
{
private:
template <typename Iterator>
static void insert(Container& c, Iterator first, Iterator last, mpl::false_)
{
c.insert(c.end(), first, last);
}
template <typename Iterator>
static void insert(Container& c, Iterator first, Iterator last, mpl::true_)
{
c.insert(first, last);
}
public:
template <typename Iterator>
static bool call(Container& c, Iterator first, Iterator last)
{
insert(c, first, last, is_associative<Container>{});
return true;
}
};
template <typename Container, typename Iterator>
inline bool append(Container& c, Iterator first, Iterator last)
{
return append_container<Container>::call(c, first, last);
}
template <typename Iterator>
inline bool append(unused_type, Iterator /* first */, Iterator /* last */)
{
return true;
}
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct is_empty_container
{
static bool call(Container const& c)
{
return c.empty();
}
};
template <typename Container>
inline bool is_empty(Container const& c)
{
return is_empty_container<Container>::call(c);
}
inline bool is_empty(unused_type)
{
return true;
}
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct begin_container
{
static typename container_iterator<Container>::type call(Container& c)
{
return c.begin();
}
};
template <typename Container>
inline typename container_iterator<Container>::type
begin(Container& c)
{
return begin_container<Container>::call(c);
}
inline unused_type const*
begin(unused_type)
{
return &unused;
}
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct end_container
{
static typename container_iterator<Container>::type call(Container& c)
{
return c.end();
}
};
template <typename Container>
inline typename container_iterator<Container>::type
end(Container& c)
{
return end_container<Container>::call(c);
}
inline unused_type const*
end(unused_type)
{
return &unused;
}
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Enable = void>
struct deref_iterator
{
typedef typename std::iterator_traits<Iterator>::reference type;
static type call(Iterator& it)
{
return *it;
}
};
template <typename Iterator>
typename deref_iterator<Iterator>::type
deref(Iterator& it)
{
return deref_iterator<Iterator>::call(it);
}
inline unused_type
deref(unused_type const*)
{
return unused;
}
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Enable = void>
struct next_iterator
{
static void call(Iterator& it)
{
++it;
}
};
template <typename Iterator>
void next(Iterator& it)
{
next_iterator<Iterator>::call(it);
}
inline void next(unused_type const*)
{
// do nothing
}
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Enable = void>
struct compare_iterators
{
static bool call(Iterator const& it1, Iterator const& it2)
{
return it1 == it2;
}
};
template <typename Iterator>
bool compare(Iterator& it1, Iterator& it2)
{
return compare_iterators<Iterator>::call(it1, it2);
}
inline bool compare(unused_type const*, unused_type const*)
{
return false;
}
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct build_container : mpl::identity<std::vector<T>> {};
template <typename T>
struct build_container<boost::fusion::deque<T> > : build_container<T> {};
template <>
struct build_container<unused_type> : mpl::identity<unused_type> {};
template <>
struct build_container<char> : mpl::identity<std::string> {};
}}}}
#endif