blob: c382b7bfaabca7bcc870a2a8e0f28114a444927c [file] [log] [blame]
/*=============================================================================
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
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/fusion/support/category_of.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/fusion/include/deque.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/identity.hpp>
#include <vector>
#include <string>
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// This file contains some container utils for stl containers.
///////////////////////////////////////////////////////////////////////////
namespace detail
{
BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type)
BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator)
BOOST_MPL_HAS_XXX_TRAIT_DEF(size_type)
BOOST_MPL_HAS_XXX_TRAIT_DEF(reference)
}
template <typename T, typename Enable = void>
struct is_container
: mpl::bool_<
detail::has_value_type<T>::value &&
detail::has_iterator<T>::value &&
detail::has_size_type<T>::value &&
detail::has_reference<T>::value>
{};
///////////////////////////////////////////////////////////////////////////
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(), std::move(val));
return true;
}
};
template <typename Container, typename T>
inline bool push_back(Container& c, T&& val)
{
return push_back_container<Container>::call(c, std::move(val));
}
template <typename Container>
inline bool push_back(Container&, unused_type)
{
return true;
}
template <typename T>
inline bool push_back(unused_type, T const&)
{
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
{
// Not all containers have "reserve"
template <typename Container_>
static void reserve(Container_& c, std::size_t size) {}
template <typename T>
static void reserve(std::vector<T>& c, std::size_t size)
{
c.reserve(size);
}
template <typename Iterator>
static bool call(Container& c, Iterator first, Iterator last)
{
reserve(c, c.size() + std::distance(first, last));
c.insert(c.end(), first, last);
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 boost::detail::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