]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/flyweight/include/boost/flyweight/refcounted.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / flyweight / include / boost / flyweight / refcounted.hpp
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)
5 *
6 * See http://www.boost.org/libs/flyweight for library home page.
7 */
8
9 #ifndef BOOST_FLYWEIGHT_REFCOUNTED_HPP
10 #define BOOST_FLYWEIGHT_REFCOUNTED_HPP
11
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17 #include <algorithm>
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>
23
24 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
25 #include <utility>
26 #endif
27
28 /* Refcounting tracking policy.
29 * The implementation deserves some explanation; values are equipped with two
30 * reference counts:
31 * - a regular count of active references
32 * - a deleter count
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).
45 */
46
47 namespace boost{
48
49 namespace flyweights{
50
51 namespace detail{
52
53 template<typename Value,typename Key>
54 class refcounted_value
55 {
56 public:
57 explicit refcounted_value(const Value& x_):
58 x(x_),ref(0),del_ref(0)
59 {}
60
61 refcounted_value(const refcounted_value& r):
62 x(r.x),ref(0),del_ref(0)
63 {}
64
65 refcounted_value& operator=(const refcounted_value& r)
66 {
67 x=r.x;
68 return *this;
69 }
70
71 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
72 explicit refcounted_value(Value&& x_):
73 x(std::move(x_)),ref(0),del_ref(0)
74 {}
75
76 refcounted_value(refcounted_value&& r):
77 x(std::move(r.x)),ref(0),del_ref(0)
78 {}
79
80 refcounted_value& operator=(refcounted_value&& r)
81 {
82 x=std::move(r.x);
83 return *this;
84 }
85 #endif
86
87 operator const Value&()const{return x;}
88 operator const Key&()const{return x;}
89
90 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
91 private:
92 template<typename,typename> friend class refcounted_handle;
93 #endif
94
95 long count()const{return ref;}
96 long add_ref()const{return ++ref;}
97 bool release()const{return (--ref==0);}
98
99 void add_deleter()const{++del_ref;}
100 bool release_deleter()const{return (--del_ref==0);}
101
102 private:
103 Value x;
104 mutable boost::detail::atomic_count ref;
105 mutable long del_ref;
106 };
107
108 template<typename Handle,typename TrackingHelper>
109 class refcounted_handle
110 {
111 public:
112 explicit refcounted_handle(const Handle& h_):h(h_)
113 {
114 if(TrackingHelper::entry(*this).add_ref()==1){
115 TrackingHelper::entry(*this).add_deleter();
116 }
117 }
118
119 refcounted_handle(const refcounted_handle& x):h(x.h)
120 {
121 TrackingHelper::entry(*this).add_ref();
122 }
123
124 refcounted_handle& operator=(refcounted_handle x)
125 {
126 this->swap(x);
127 return *this;
128 }
129
130 ~refcounted_handle()
131 {
132 if(TrackingHelper::entry(*this).release()){
133 TrackingHelper::erase(*this,check_erase);
134 }
135 }
136
137 operator const Handle&()const{return h;}
138
139 void swap(refcounted_handle& x)
140 {
141 std::swap(h,x.h);
142 }
143
144 private:
145 static bool check_erase(const refcounted_handle& x)
146 {
147 return TrackingHelper::entry(x).release_deleter();
148 }
149
150 Handle h;
151 };
152
153 template<typename Handle,typename TrackingHelper>
154 void swap(
155 refcounted_handle<Handle,TrackingHelper>& x,
156 refcounted_handle<Handle,TrackingHelper>& y)
157 {
158 x.swap(y);
159 }
160
161 } /* namespace flyweights::detail */
162
163 #if BOOST_WORKAROUND(BOOST_MSVC,<=1500)
164 /* swap lookup by boost::swap fails under obscure circumstances */
165
166 } /* namespace flyweights */
167
168 template<typename Handle,typename TrackingHelper>
169 void swap(
170 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& x,
171 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& y)
172 {
173 ::boost::flyweights::detail::swap(x,y);
174 }
175
176 namespace flyweights{
177 #endif
178
179 struct refcounted:tracking_marker
180 {
181 struct entry_type
182 {
183 template<typename Value,typename Key>
184 struct apply
185 {
186 typedef detail::refcounted_value<Value,Key> type;
187 };
188 };
189
190 struct handle_type
191 {
192 template<typename Handle,typename TrackingHelper>
193 struct apply
194 {
195 typedef detail::refcounted_handle<Handle,TrackingHelper> type;
196 };
197 };
198 };
199
200 } /* namespace flyweights */
201
202 } /* namespace boost */
203
204 #endif