1 /* Copyright 2006-2014 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/flyweight for library home page.
9 #ifndef BOOST_FLYWEIGHT_REFCOUNTED_HPP
10 #define BOOST_FLYWEIGHT_REFCOUNTED_HPP
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
18 #include <boost/detail/atomic_count.hpp>
19 #include <boost/detail/workaround.hpp>
20 #include <boost/flyweight/refcounted_fwd.hpp>
21 #include <boost/flyweight/tracking_tag.hpp>
22 #include <boost/utility/swap.hpp>
24 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
28 /* Refcounting tracking policy.
29 * The implementation deserves some explanation; values are equipped with two
31 * - a regular count of active references
33 * It looks like a value can be erased when the number of references reaches
34 * zero, but this condition alone can lead to data races:
35 * - Thread A detaches the last reference to x and is preempted.
36 * - Thread B looks for x, finds it and attaches a reference to it.
37 * - Thread A resumes and proceeds with erasing x, leaving a dangling
38 * reference in thread B.
39 * Here is where the deleter count comes into play. This count is
40 * incremented when the reference count changes from 0 to 1, and decremented
41 * when a thread is about to check a value for erasure; it can be seen that a
42 * value is effectively erasable only when the deleter count goes down to 0
43 * (unless there are dangling references due to abnormal program termination,
44 * for instance if std::exit is called).
53 template<typename Value,typename Key>
54 class refcounted_value
57 explicit refcounted_value(const Value& x_):
58 x(x_),ref(0),del_ref(0)
61 refcounted_value(const refcounted_value& r):
62 x(r.x),ref(0),del_ref(0)
65 refcounted_value& operator=(const refcounted_value& r)
71 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
72 explicit refcounted_value(Value&& x_):
73 x(std::move(x_)),ref(0),del_ref(0)
76 refcounted_value(refcounted_value&& r):
77 x(std::move(r.x)),ref(0),del_ref(0)
80 refcounted_value& operator=(refcounted_value&& r)
87 operator const Value&()const{return x;}
88 operator const Key&()const{return x;}
90 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
92 template<typename,typename> friend class refcounted_handle;
95 long count()const{return ref;}
96 long add_ref()const{return ++ref;}
97 bool release()const{return (--ref==0);}
99 void add_deleter()const{++del_ref;}
100 bool release_deleter()const{return (--del_ref==0);}
104 mutable boost::detail::atomic_count ref;
105 mutable long del_ref;
108 template<typename Handle,typename TrackingHelper>
109 class refcounted_handle
112 explicit refcounted_handle(const Handle& h_):h(h_)
114 if(TrackingHelper::entry(*this).add_ref()==1){
115 TrackingHelper::entry(*this).add_deleter();
119 refcounted_handle(const refcounted_handle& x):h(x.h)
121 TrackingHelper::entry(*this).add_ref();
124 refcounted_handle& operator=(refcounted_handle x)
132 if(TrackingHelper::entry(*this).release()){
133 TrackingHelper::erase(*this,check_erase);
137 operator const Handle&()const{return h;}
139 void swap(refcounted_handle& x)
145 static bool check_erase(const refcounted_handle& x)
147 return TrackingHelper::entry(x).release_deleter();
153 template<typename Handle,typename TrackingHelper>
155 refcounted_handle<Handle,TrackingHelper>& x,
156 refcounted_handle<Handle,TrackingHelper>& y)
161 } /* namespace flyweights::detail */
163 #if BOOST_WORKAROUND(BOOST_MSVC,<=1500)
164 /* swap lookup by boost::swap fails under obscure circumstances */
166 } /* namespace flyweights */
168 template<typename Handle,typename TrackingHelper>
170 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& x,
171 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& y)
173 ::boost::flyweights::detail::swap(x,y);
176 namespace flyweights{
179 struct refcounted:tracking_marker
183 template<typename Value,typename Key>
186 typedef detail::refcounted_value<Value,Key> type;
192 template<typename Handle,typename TrackingHelper>
195 typedef detail::refcounted_handle<Handle,TrackingHelper> type;
200 } /* namespace flyweights */
202 } /* namespace boost */