blob: ed1ceb1afa407253251201defcc781f59c090aad [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// accumulator_set.hpp
//
// Copyright 2005 Eric Niebler. 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)
#ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
#include <boost/version.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/protect.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/parameter/parameters.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/accumulators/accumulators_fwd.hpp>
#include <boost/accumulators/framework/depends_on.hpp>
#include <boost/accumulators/framework/accumulator_concept.hpp>
#include <boost/accumulators/framework/parameters/accumulator.hpp>
#include <boost/accumulators/framework/parameters/sample.hpp>
#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
#include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp>
#include <boost/fusion/include/any.hpp>
#include <boost/fusion/include/find_if.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/filter_view.hpp>
namespace boost { namespace accumulators
{
namespace detail
{
///////////////////////////////////////////////////////////////////////////////
// accumulator_visitor
// wrap a boost::parameter argument pack in a Fusion extractor object
template<typename Args>
struct accumulator_visitor
{
explicit accumulator_visitor(Args const &a)
: args(a)
{
}
template<typename Accumulator>
void operator ()(Accumulator &accumulator) const
{
accumulator(this->args);
}
private:
accumulator_visitor &operator =(accumulator_visitor const &);
Args const &args;
};
template<typename Args>
inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
{
return accumulator_visitor<Args>(args);
}
typedef
parameter::parameters<
parameter::required<tag::accumulator>
, parameter::optional<tag::sample>
// ... and others which are not specified here...
>
accumulator_params;
///////////////////////////////////////////////////////////////////////////////
// accumulator_set_base
struct accumulator_set_base
{
};
///////////////////////////////////////////////////////////////////////////////
// is_accumulator_set
template<typename T>
struct is_accumulator_set
: is_base_and_derived<accumulator_set_base, T>
{
};
} // namespace detail
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
#endif
///////////////////////////////////////////////////////////////////////////////
/// \brief A set of accumulators.
///
/// accumulator_set resolves the dependencies between features and ensures that
/// the accumulators in the set are updated in the proper order.
///
/// acccumulator_set provides a general mechanism to visit the accumulators
/// in the set in order, with or without a filter. You can also fetch a reference
/// to an accumulator that corresponds to a feature.
///
template<typename Sample, typename Features, typename Weight>
struct accumulator_set
: detail::accumulator_set_base
{
typedef Sample sample_type; ///< The type of the samples that will be accumulated
typedef Features features_type; ///< An MPL sequence of the features that should be accumulated.
typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void.
/// INTERNAL ONLY
///
typedef
typename detail::make_accumulator_tuple<
Features
, Sample
, Weight
>::type
accumulators_mpl_vector;
// generate a fusion::list of accumulators
/// INTERNAL ONLY
///
typedef
typename detail::meta::make_acc_list<
accumulators_mpl_vector
>::type
accumulators_type;
/// INTERNAL ONLY
///
//BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
///////////////////////////////////////////////////////////////////////////////
/// default-construct all contained accumulators
accumulator_set()
: accumulators(
detail::make_acc_list(
accumulators_mpl_vector()
, detail::accumulator_params()(*this)
)
)
{
// Add-ref the Features that the user has specified
this->template visit_if<detail::contains_feature_of_<Features> >(
detail::make_add_ref_visitor(detail::accumulator_params()(*this))
);
}
/// \overload
///
/// \param a1 Optional named parameter to be passed to all the accumulators
template<typename A1>
explicit accumulator_set(A1 const &a1)
: accumulators(
detail::make_acc_list(
accumulators_mpl_vector()
, detail::accumulator_params()(*this, a1)
)
)
{
// Add-ref the Features that the user has specified
this->template visit_if<detail::contains_feature_of_<Features> >(
detail::make_add_ref_visitor(detail::accumulator_params()(*this))
);
}
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
accumulator_set(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
: accumulators( \
detail::make_acc_list( \
accumulators_mpl_vector() \
, detail::accumulator_params()( \
*this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
) \
) \
{ \
/* Add-ref the Features that the user has specified */ \
this->template visit_if<detail::contains_feature_of_<Features> >( \
detail::make_add_ref_visitor(detail::accumulator_params()(*this)) \
); \
}
/// INTERNAL ONLY
///
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
/// \overload
///
template<typename A1, typename A2, ...>
accumulator_set(A1 const &a1, A2 const &a2, ...);
#endif
// ... other overloads generated by Boost.Preprocessor below ...
///////////////////////////////////////////////////////////////////////////////
/// Visitation
/// \param func UnaryFunction which is invoked with each accumulator in turn.
template<typename UnaryFunction>
void visit(UnaryFunction const &func)
{
fusion::for_each(this->accumulators, func);
}
///////////////////////////////////////////////////////////////////////////////
/// Conditional visitation
/// \param func UnaryFunction which is invoked with each accumulator in turn,
/// provided the accumulator satisfies the MPL predicate FilterPred.
template<typename FilterPred, typename UnaryFunction>
void visit_if(UnaryFunction const &func)
{
fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
fusion::for_each(filtered_accs, func);
}
///////////////////////////////////////////////////////////////////////////////
/// The return type of the operator() overloads is void.
typedef void result_type;
///////////////////////////////////////////////////////////////////////////////
/// Accumulation
/// \param a1 Optional named parameter to be passed to all the accumulators
void operator ()()
{
this->visit(
detail::make_accumulator_visitor(
detail::accumulator_params()(*this)
)
);
}
template<typename A1>
void operator ()(A1 const &a1)
{
this->visit(
detail::make_accumulator_visitor(
detail::accumulator_params()(*this, a1)
)
);
}
// ... other overloads generated by Boost.Preprocessor:
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \
template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
{ \
this->visit( \
detail::make_accumulator_visitor( \
detail::accumulator_params()( \
*this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
) \
); \
}
/// INTERNAL ONLY
///
BOOST_PP_REPEAT_FROM_TO(
2
, BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
, _
)
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
/// \overload
///
template<typename A1, typename A2, ...>
void operator ()(A1 const &a1, A2 const &a2, ...);
#endif
///////////////////////////////////////////////////////////////////////////////
/// Extraction
template<typename Feature>
struct apply
: fusion::result_of::value_of<
typename fusion::result_of::find_if<
accumulators_type
, detail::matches_feature<Feature>
>::type
>
{
};
///////////////////////////////////////////////////////////////////////////////
/// Extraction
template<typename Feature>
typename apply<Feature>::type &extract()
{
return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
}
/// \overload
template<typename Feature>
typename apply<Feature>::type const &extract() const
{
return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
}
///////////////////////////////////////////////////////////////////////////////
/// Drop
template<typename Feature>
void drop()
{
// You can only drop the features that you have specified explicitly
typedef typename apply<Feature>::type the_accumulator;
BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>));
typedef
typename feature_of<typename as_feature<Feature>::type>::type
the_feature;
(*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
.drop(detail::accumulator_params()(*this));
// Also drop accumulators that this feature depends on
typedef typename the_feature::dependencies dependencies;
this->template visit_if<detail::contains_feature_of_<dependencies> >(
detail::make_drop_visitor(detail::accumulator_params()(*this))
);
}
private:
accumulators_type accumulators;
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
///////////////////////////////////////////////////////////////////////////////
// find_accumulator
// find an accumulator in an accumulator_set corresponding to a feature
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type &
find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet))
{
return acc.template extract<Feature>();
}
/// \overload
template<typename Feature, typename AccumulatorSet>
typename mpl::apply<AccumulatorSet, Feature>::type const &
find_accumulator(AccumulatorSet const &acc)
{
return acc.template extract<Feature>();
}
///////////////////////////////////////////////////////////////////////////////
// extract_result
// extract a result from an accumulator set
/// INTERNAL ONLY
///
#define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
template< \
typename Feature \
, typename AccumulatorSet \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
> \
typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
extract_result( \
AccumulatorSet const &acc \
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
) \
{ \
return find_accumulator<Feature>(acc).result( \
detail::accumulator_params()( \
acc \
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
) \
); \
}
BOOST_PP_REPEAT(
BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
, BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
, _
)
}} // namespace boost::accumulators
#endif