Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/flyweight/refcounted.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/flyweight/refcounted.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,184 @@ +/* Copyright 2006-2013 Joaquin M Lopez Munoz. + * 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) + * + * See http://www.boost.org/libs/flyweight for library home page. + */ + +#ifndef BOOST_FLYWEIGHT_REFCOUNTED_HPP +#define BOOST_FLYWEIGHT_REFCOUNTED_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ +#include <algorithm> +#include <boost/detail/atomic_count.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/flyweight/refcounted_fwd.hpp> +#include <boost/flyweight/tracking_tag.hpp> +#include <boost/utility/swap.hpp> + +/* Refcounting tracking policy. + * The implementation deserves some explanation; values are equipped with two + * reference counts: + * - a regular count of active references + * - a deleter count + * It looks like a value can be erased when the number of references reaches + * zero, but this condition alone can lead to data races: + * - Thread A detaches the last reference to x and is preempted. + * - Thread B looks for x, finds it and attaches a reference to it. + * - Thread A resumes and proceeds with erasing x, leaving a dangling + * reference in thread B. + * Here is where the deleter count comes into play. This count is + * incremented when the reference count changes from 0 to 1, and decremented + * when a thread is about to check a value for erasure; it can be seen that a + * value is effectively erasable only when the deleter count goes down to 0 + * (unless there are dangling references due to abnormal program termination, + * for instance if std::exit is called). + */ + +namespace boost{ + +namespace flyweights{ + +namespace detail{ + +template<typename Value,typename Key> +class refcounted_value +{ +public: + explicit refcounted_value(const Value& x_): + x(x_),ref(0),del_ref(0) + {} + + refcounted_value(const refcounted_value& r): + x(r.x),ref(0),del_ref(0) + {} + + refcounted_value& operator=(const refcounted_value& r) + { + x=r.x; + return *this; + } + + operator const Value&()const{return x;} + operator const Key&()const{return x;} + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +private: + template<typename,typename> friend class refcounted_handle; +#endif + + long count()const{return ref;} + long add_ref()const{return ++ref;} + bool release()const{return (--ref==0);} + + void add_deleter()const{++del_ref;} + bool release_deleter()const{return (--del_ref==0);} + +private: + Value x; + mutable boost::detail::atomic_count ref; + mutable long del_ref; +}; + +template<typename Handle,typename TrackingHelper> +class refcounted_handle +{ +public: + explicit refcounted_handle(const Handle& h_):h(h_) + { + if(TrackingHelper::entry(*this).add_ref()==1){ + TrackingHelper::entry(*this).add_deleter(); + } + } + + refcounted_handle(const refcounted_handle& x):h(x.h) + { + TrackingHelper::entry(*this).add_ref(); + } + + refcounted_handle& operator=(refcounted_handle x) + { + this->swap(x); + return *this; + } + + ~refcounted_handle() + { + if(TrackingHelper::entry(*this).release()){ + TrackingHelper::erase(*this,check_erase); + } + } + + operator const Handle&()const{return h;} + + void swap(refcounted_handle& x) + { + std::swap(h,x.h); + } + +private: + static bool check_erase(const refcounted_handle& x) + { + return TrackingHelper::entry(x).release_deleter(); + } + + Handle h; +}; + +template<typename Handle,typename TrackingHelper> +void swap( + refcounted_handle<Handle,TrackingHelper>& x, + refcounted_handle<Handle,TrackingHelper>& y) +{ + x.swap(y); +} + +} /* namespace flyweights::detail */ + +#if BOOST_WORKAROUND(BOOST_MSVC,<=1500) +/* swap lookup by boost::swap fails under obscure circumstances */ + +} /* namespace flyweights */ + +template<typename Handle,typename TrackingHelper> +void swap( + ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& x, + ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& y) +{ + ::boost::flyweights::detail::swap(x,y); +} + +namespace flyweights{ +#endif + +struct refcounted:tracking_marker +{ + struct entry_type + { + template<typename Value,typename Key> + struct apply + { + typedef detail::refcounted_value<Value,Key> type; + }; + }; + + struct handle_type + { + template<typename Handle,typename TrackingHelper> + struct apply + { + typedef detail::refcounted_handle<Handle,TrackingHelper> type; + }; + }; +}; + +} /* namespace flyweights */ + +} /* namespace boost */ + +#endif