/////////////////////////////////////////////////////////////////////////////// // droppable_accumulator.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_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005 #define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005 #include #include #include #include #include // for feature_of #include // for accumulator namespace boost { namespace accumulators { template struct droppable_accumulator; namespace detail { /////////////////////////////////////////////////////////////////////////////// // add_ref_visitor // a fusion function object for add_ref'ing accumulators template struct add_ref_visitor { explicit add_ref_visitor(Args const &args) : args_(args) { } template void operator ()(Accumulator &acc) const { typedef typename Accumulator::feature_tag::dependencies dependencies; acc.add_ref(this->args_); // Also add_ref accumulators that this feature depends on this->args_[accumulator].template visit_if >( *this ); } private: add_ref_visitor &operator =(add_ref_visitor const &); Args const &args_; }; template add_ref_visitor make_add_ref_visitor(Args const &args) { return add_ref_visitor(args); } /////////////////////////////////////////////////////////////////////////////// // drop_visitor // a fusion function object for dropping accumulators template struct drop_visitor { explicit drop_visitor(Args const &args) : args_(args) { } template void operator ()(Accumulator &acc) const { if(typename Accumulator::is_droppable()) { typedef typename Accumulator::feature_tag::dependencies dependencies; acc.drop(this->args_); // Also drop accumulators that this feature depends on this->args_[accumulator].template visit_if >( *this ); } } private: drop_visitor &operator =(drop_visitor const &); Args const &args_; }; template drop_visitor make_drop_visitor(Args const &args) { return drop_visitor(args); } } ////////////////////////////////////////////////////////////////////////// // droppable_accumulator_base template struct droppable_accumulator_base : Accumulator { typedef droppable_accumulator_base base; typedef mpl::true_ is_droppable; typedef typename Accumulator::result_type result_type; template droppable_accumulator_base(Args const &args) : Accumulator(args) , ref_count_(0) { } droppable_accumulator_base(droppable_accumulator_base const &that) : Accumulator(*static_cast(&that)) , ref_count_(that.ref_count_) { } template void operator ()(Args const &args) { if(!this->is_dropped()) { this->Accumulator::operator ()(args); } } template void add_ref(Args const &) { ++this->ref_count_; } template void drop(Args const &args) { BOOST_ASSERT(0 < this->ref_count_); if(1 == this->ref_count_) { static_cast *>(this)->on_drop(args); } --this->ref_count_; } bool is_dropped() const { return 0 == this->ref_count_; } private: int ref_count_; }; ////////////////////////////////////////////////////////////////////////// // droppable_accumulator // this can be specialized for any type that needs special handling template struct droppable_accumulator : droppable_accumulator_base { template droppable_accumulator(Args const &args) : droppable_accumulator::base(args) { } droppable_accumulator(droppable_accumulator const &that) : droppable_accumulator::base(*static_cast(&that)) { } }; ////////////////////////////////////////////////////////////////////////// // with_cached_result template struct with_cached_result : Accumulator { typedef typename Accumulator::result_type result_type; template with_cached_result(Args const &args) : Accumulator(args) , cache() { } with_cached_result(with_cached_result const &that) : Accumulator(*static_cast(&that)) , cache() { if(that.has_result()) { this->set(that.get()); } } ~with_cached_result() { // Since this is a base class of droppable_accumulator_base, // this destructor is called before any of droppable_accumulator_base's // members get cleaned up, including is_dropped, so the following // call to has_result() is valid. if(this->has_result()) { this->get().~result_type(); } } template void on_drop(Args const &args) { // cache the result at the point this calcuation was dropped BOOST_ASSERT(!this->has_result()); this->set(this->Accumulator::result(args)); } template result_type result(Args const &args) const { return this->has_result() ? this->get() : this->Accumulator::result(args); } private: with_cached_result &operator =(with_cached_result const &); void set(result_type const &r) { ::new(this->cache.address()) result_type(r); } result_type const &get() const { return *static_cast(this->cache.address()); } bool has_result() const { typedef with_cached_result this_type; typedef droppable_accumulator_base derived_type; return static_cast(this)->is_dropped(); } aligned_storage cache; }; namespace tag { template struct as_droppable { typedef droppable type; }; template struct as_droppable > { typedef droppable type; }; ////////////////////////////////////////////////////////////////////////// // droppable template struct droppable : as_feature::type { typedef typename as_feature::type feature_type; typedef typename feature_type::dependencies tmp_dependencies_; typedef typename mpl::transform< typename feature_type::dependencies , as_droppable >::type dependencies; struct impl { template struct apply { typedef droppable_accumulator< typename mpl::apply2::type > type; }; }; }; } // make droppable work template struct as_feature > { typedef tag::droppable::type> type; }; // make droppable work with non-void weights (should become // droppable template struct as_weighted_feature > { typedef tag::droppable::type> type; }; // for the purposes of feature-based dependency resolution, // droppable provides the same feature as Foo template struct feature_of > : feature_of { }; // Note: Usually, the extractor is pulled into the accumulators namespace with // a using directive, not the tag. But the droppable<> feature doesn't have an // extractor, so we can put the droppable tag in the accumulators namespace // without fear of a name conflict. using tag::droppable; }} // namespace boost::accumulators #endif