You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
274 lines
9.3 KiB
274 lines
9.3 KiB
// Copyright (c) 2001-2011 Hartmut Kaiser |
|
// |
|
// 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_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM) |
|
#define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM |
|
|
|
#if defined(_MSC_VER) |
|
#pragma once |
|
#endif |
|
|
|
#include <boost/spirit/include/phoenix_core.hpp> |
|
#include <boost/spirit/home/support/unused.hpp> |
|
#include <boost/spirit/home/support/attributes_fwd.hpp> |
|
#include <boost/spirit/home/karma/detail/attributes.hpp> |
|
#include <boost/spirit/home/support/container.hpp> |
|
|
|
#include <boost/ref.hpp> |
|
#include <boost/optional.hpp> |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
namespace boost { namespace spirit { namespace traits |
|
{ |
|
/////////////////////////////////////////////////////////////////////////// |
|
// This file contains attribute extraction utilities. The utilities |
|
// provided also accept spirit's unused_type; all no-ops. Compiler |
|
// optimization will easily strip these away. |
|
/////////////////////////////////////////////////////////////////////////// |
|
|
|
namespace detail |
|
{ |
|
/////////////////////////////////////////////////////////////////////// |
|
// extract first and second element of a fusion sequence |
|
template <typename T> |
|
struct add_const_ref |
|
: add_reference<typename add_const<T>::type> |
|
{}; |
|
|
|
template <typename T, int N> |
|
struct value_at_c |
|
: add_const_ref<typename fusion::result_of::value_at_c<T, N>::type> |
|
{}; |
|
} |
|
|
|
// This is the default case: the plain attribute values |
|
template <typename Attribute, typename Exposed, typename Enable/*= void*/> |
|
struct extract_from_attribute |
|
{ |
|
typedef typename traits::one_element_sequence<Attribute>::type |
|
is_one_element_sequence; |
|
|
|
typedef typename mpl::eval_if< |
|
is_one_element_sequence |
|
, detail::value_at_c<Attribute, 0> |
|
, mpl::identity<Attribute const&> |
|
>::type type; |
|
|
|
template <typename Context> |
|
static type call(Attribute const& attr, Context&, mpl::false_) |
|
{ |
|
return attr; |
|
} |
|
|
|
// This handles the case where the attribute is a single element fusion |
|
// sequence. We silently extract the only element and treat it as the |
|
// attribute to generate output from. |
|
template <typename Context> |
|
static type call(Attribute const& attr, Context& ctx, mpl::true_) |
|
{ |
|
return extract_from<Exposed>(fusion::at_c<0>(attr), ctx); |
|
} |
|
|
|
template <typename Context> |
|
static type call(Attribute const& attr, Context& ctx) |
|
{ |
|
return call(attr, ctx, is_one_element_sequence()); |
|
} |
|
}; |
|
|
|
// This handles optional attributes. |
|
template <typename Attribute, typename Exposed> |
|
struct extract_from_attribute<boost::optional<Attribute>, Exposed> |
|
{ |
|
typedef Attribute const& type; |
|
|
|
template <typename Context> |
|
static type call(boost::optional<Attribute> const& attr, Context& ctx) |
|
{ |
|
return extract_from<Exposed>(boost::get<Attribute>(attr), ctx); |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename Exposed> |
|
struct extract_from_attribute<boost::optional<Attribute const>, Exposed> |
|
{ |
|
typedef Attribute const& type; |
|
|
|
template <typename Context> |
|
static type call(boost::optional<Attribute const> const& attr, Context& ctx) |
|
{ |
|
return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx); |
|
} |
|
}; |
|
|
|
// This handles attributes wrapped inside a boost::ref(). |
|
template <typename Attribute, typename Exposed> |
|
struct extract_from_attribute<reference_wrapper<Attribute>, Exposed> |
|
{ |
|
typedef Attribute const& type; |
|
|
|
template <typename Context> |
|
static type call(reference_wrapper<Attribute> const& attr, Context& ctx) |
|
{ |
|
return extract_from<Exposed>(attr.get(), ctx); |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename Attribute, typename Exposed, typename Enable> |
|
struct extract_from_container |
|
{ |
|
typedef typename traits::container_value<Attribute const>::type |
|
value_type; |
|
typedef typename is_convertible<value_type, Exposed>::type |
|
is_convertible_to_value_type; |
|
|
|
typedef typename mpl::if_< |
|
mpl::or_< |
|
is_same<value_type, Exposed>, is_same<Attribute, Exposed> > |
|
, Exposed const&, Exposed |
|
>::type type; |
|
|
|
// handle case where container value type is convertible to result type |
|
// we simply return the front element of the container |
|
template <typename Context, typename Pred> |
|
static type call(Attribute const& attr, Context&, mpl::true_, Pred) |
|
{ |
|
// return first element from container |
|
typedef typename traits::container_iterator<Attribute const>::type |
|
iterator_type; |
|
|
|
iterator_type it = traits::begin(attr); |
|
type result = *it; |
|
++it; |
|
return result; |
|
} |
|
|
|
// handle strings |
|
template <typename Iterator> |
|
static void append_to_string(Exposed& result, Iterator begin, Iterator end) |
|
{ |
|
for (Iterator i = begin; i != end; ++i) |
|
push_back(result, *i); |
|
} |
|
|
|
template <typename Context> |
|
static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_) |
|
{ |
|
typedef typename char_type_of<Attribute>::type char_type; |
|
|
|
Exposed result; |
|
append_to_string(result, traits::get_begin<char_type>(attr) |
|
, traits::get_end<char_type>(attr)); |
|
return result; |
|
} |
|
|
|
// everything else gets just passed through |
|
template <typename Context> |
|
static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_) |
|
{ |
|
return type(attr); |
|
} |
|
|
|
template <typename Context> |
|
static type call(Attribute const& attr, Context& ctx) |
|
{ |
|
typedef typename mpl::and_< |
|
traits::is_string<Exposed>, traits::is_string<Attribute> |
|
>::type handle_strings; |
|
|
|
// return first element from container |
|
return call(attr, ctx, is_convertible_to_value_type() |
|
, handle_strings()); |
|
} |
|
}; |
|
|
|
template <typename Attribute> |
|
struct extract_from_container<Attribute, Attribute> |
|
{ |
|
typedef Attribute const& type; |
|
|
|
template <typename Context> |
|
static type call(Attribute const& attr, Context&) |
|
{ |
|
return attr; |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
namespace detail |
|
{ |
|
// overload for non-container attributes |
|
template <typename Exposed, typename Attribute, typename Context> |
|
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type |
|
extract_from(Attribute const& attr, Context& ctx, mpl::false_) |
|
{ |
|
return extract_from_attribute<Attribute, Exposed>::call(attr, ctx); |
|
} |
|
|
|
// overload for containers (but not for variants or optionals |
|
// holding containers) |
|
template <typename Exposed, typename Attribute, typename Context> |
|
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type |
|
extract_from(Attribute const& attr, Context& ctx, mpl::true_) |
|
{ |
|
return extract_from_container<Attribute, Exposed>::call(attr, ctx); |
|
} |
|
} |
|
|
|
template <typename Exposed, typename Attribute, typename Context> |
|
inline typename spirit::result_of::extract_from<Exposed, Attribute>::type |
|
extract_from(Attribute const& attr, Context& ctx |
|
#if (defined(__GNUC__) && (__GNUC__ < 4)) || \ |
|
(defined(__APPLE__) && defined(__INTEL_COMPILER)) |
|
, typename enable_if<traits::not_is_unused<Attribute> >::type* |
|
#endif |
|
) |
|
{ |
|
typedef typename mpl::and_< |
|
traits::is_container<Attribute> |
|
, traits::not_is_variant<Attribute> |
|
, traits::not_is_optional<Attribute> |
|
>::type is_not_wrapped_container; |
|
|
|
return detail::extract_from<Exposed>(attr, ctx |
|
, is_not_wrapped_container()); |
|
} |
|
|
|
template <typename Exposed, typename Context> |
|
inline unused_type extract_from(unused_type, Context&) |
|
{ |
|
return unused; |
|
} |
|
}}} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
namespace boost { namespace spirit { namespace result_of |
|
{ |
|
template <typename Exposed, typename Attribute> |
|
struct extract_from |
|
: mpl::if_< |
|
mpl::and_< |
|
traits::is_container<Attribute> |
|
, traits::not_is_variant<Attribute> |
|
, traits::not_is_optional<Attribute> > |
|
, traits::extract_from_container<Attribute, Exposed> |
|
, traits::extract_from_attribute<Attribute, Exposed> >::type |
|
{}; |
|
|
|
template <typename Exposed> |
|
struct extract_from<Exposed, unused_type> |
|
{ |
|
typedef unused_type type; |
|
}; |
|
|
|
template <typename Exposed> |
|
struct extract_from<Exposed, unused_type const> |
|
{ |
|
typedef unused_type type; |
|
}; |
|
}}} |
|
|
|
#endif
|
|
|