blob: 709c556f835735f34fc592d77c6e5a431542aa20 [file] [log] [blame]
// Copyright (c) 2001-2009 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_FUNCTOR_APR_01_2007_1038AM)
#define BOOST_SPIRIT_KARMA_FUNCTOR_APR_01_2007_1038AM
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once // MS compatible compilers support #pragma once
#endif
#include <boost/spirit/home/support/component.hpp>
#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/auxiliary/functor_holder.hpp>
#include <boost/spirit/home/support/auxiliary/meta_function_holder.hpp>
#include <boost/spirit/home/support/detail/values.hpp>
#include <boost/spirit/home/karma/delimit.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit
{
namespace karma
{
template <typename Functor, typename ParameterMF = Functor>
class functor_generator;
}
namespace result_of
{
template <typename Functor>
struct as_generator
{
typedef karma::functor_generator<Functor> type;
};
template <typename Functor, typename ParameterMF>
struct as_generator_mf
{
typedef karma::functor_generator<Functor, ParameterMF> type;
};
}
}} // boost::spirit
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace karma
{
///////////////////////////////////////////////////////////////////////////
// This struct may be used as a base class for a user defined functor
///////////////////////////////////////////////////////////////////////////
struct functor_base
{
///////////////////////////////////////////////////////////////////////
// The return value of a karma functor is always bool
///////////////////////////////////////////////////////////////////////
template <typename Parameter, typename OutputIterator>
struct result
{
typedef bool type;
};
// FIXME: It will be possible to specify the return value as a typedef, but for
// that Phoenix will have to be fixed.
// typedef bool result_type;
///////////////////////////////////////////////////////////////////////
// The expected parameter type of a functor has to be defined using a
// embedded apply metafunction. Normally this will be overloaded by
// the derived class, but the default is unused type.
///////////////////////////////////////////////////////////////////////
template <typename Context>
struct apply
{
typedef spirit::unused_type type;
};
};
///////////////////////////////////////////////////////////////////////////
// The functor generator template may be used to create new generators
// without having to dig into the implementation details of Karma
///////////////////////////////////////////////////////////////////////////
template <typename Functor, typename ParameterMF>
class functor_generator
: public proto::extends<
typename make_functor_holder<
functor_generator<Functor, ParameterMF> const*,
functor_generator<Functor, ParameterMF>
>::type,
functor_generator<Functor, ParameterMF>
>
{
private:
typedef functor_generator<Functor, ParameterMF> self_type;
typedef typename
make_functor_holder<self_type const*, self_type>::type
functor_tag;
typedef proto::extends<functor_tag, self_type> base_type;
public:
template <typename Context>
struct result
: mpl::apply<ParameterMF, Context>
{};
private:
// generate function just delegates to the functor supplied function
template <typename OutputIterator, typename Context, typename Parameter>
bool
generate (OutputIterator& sink, Context& ctx, Parameter const& p) const
{
// create an attribute if none is supplied
typedef typename result<Context>::type parameter_type;
typename mpl::if_<
is_same<typename remove_const<Parameter>::type, unused_type>,
parameter_type,
Parameter const&
>::type
param = spirit::detail::make_value<parameter_type>::call(p);
return functor(param, ctx, sink);
}
friend struct functor_director;
public:
explicit functor_generator()
: base_type(make_tag())
{
}
functor_generator(Functor const& functor_)
: base_type(make_tag()), functor(functor_)
{
}
functor_generator(Functor const& functor_, ParameterMF const& mf)
: base_type(make_tag()), functor(functor_), mf_(mf)
{
}
private:
functor_tag make_tag() const
{
functor_tag xpr = {{ this }};
return xpr;
}
Functor functor;
meta_function_holder<Functor, ParameterMF> mf_;
};
///////////////////////////////////////////////////////////////////////////
// The as_generator generator function may be used to create a functor
// generator from a function object (some callable item).
// The supplied functor needs to expose
//
// - an embedded result meta function:
//
// template <typename Parameter, typename OutputIterator>
// struct result
// {
// typedef bool type;
// };
//
// which declares 'bool' as the result type of the defined function
// operator and
//
// - an embedded apply meta function:
//
// template <typename Context>
// struct apply
// {
// typedef unspecified type;
// };
//
// which declares the given type as the expected attribute type for
// the generator to create.
///////////////////////////////////////////////////////////////////////////
template <typename Functor>
inline typename result_of::as_generator<Functor>::type
as_generator(Functor const& func)
{
return functor_generator<Functor>(func);
}
///////////////////////////////////////////////////////////////////////////
// The as_generator_mf generator function is equivalent to the function
// as_generator above except that the user has to explicitly specify a
// type exposing an embedded apply meta function declaring the expected
// parameter type for the generator to create.
///////////////////////////////////////////////////////////////////////////
template <typename ParameterMF, typename Functor>
inline typename result_of::as_generator_mf<Functor, ParameterMF>::type
as_generator_mf(Functor const& func, ParameterMF const& mf)
{
return functor_generator<Functor, ParameterMF>(func, mf);
}
template <typename ParameterMF, typename Functor>
inline typename result_of::as_generator_mf<Functor, ParameterMF>::type
as_generator_mf(Functor const& func)
{
return functor_generator<Functor, ParameterMF>(func, ParameterMF());
}
}}}
#endif