annotate DEPENDENCIES/generic/include/boost/flyweight/refcounted.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@101 1 /* Copyright 2006-2014 Joaquin M Lopez Munoz.
Chris@16 2 * Distributed under the Boost Software License, Version 1.0.
Chris@16 3 * (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 4 * http://www.boost.org/LICENSE_1_0.txt)
Chris@16 5 *
Chris@16 6 * See http://www.boost.org/libs/flyweight for library home page.
Chris@16 7 */
Chris@16 8
Chris@16 9 #ifndef BOOST_FLYWEIGHT_REFCOUNTED_HPP
Chris@16 10 #define BOOST_FLYWEIGHT_REFCOUNTED_HPP
Chris@16 11
Chris@101 12 #if defined(_MSC_VER)
Chris@16 13 #pragma once
Chris@16 14 #endif
Chris@16 15
Chris@16 16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
Chris@16 17 #include <algorithm>
Chris@16 18 #include <boost/detail/atomic_count.hpp>
Chris@16 19 #include <boost/detail/workaround.hpp>
Chris@16 20 #include <boost/flyweight/refcounted_fwd.hpp>
Chris@16 21 #include <boost/flyweight/tracking_tag.hpp>
Chris@16 22 #include <boost/utility/swap.hpp>
Chris@16 23
Chris@101 24 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
Chris@101 25 #include <utility>
Chris@101 26 #endif
Chris@101 27
Chris@16 28 /* Refcounting tracking policy.
Chris@16 29 * The implementation deserves some explanation; values are equipped with two
Chris@16 30 * reference counts:
Chris@16 31 * - a regular count of active references
Chris@16 32 * - a deleter count
Chris@16 33 * It looks like a value can be erased when the number of references reaches
Chris@16 34 * zero, but this condition alone can lead to data races:
Chris@16 35 * - Thread A detaches the last reference to x and is preempted.
Chris@16 36 * - Thread B looks for x, finds it and attaches a reference to it.
Chris@16 37 * - Thread A resumes and proceeds with erasing x, leaving a dangling
Chris@16 38 * reference in thread B.
Chris@16 39 * Here is where the deleter count comes into play. This count is
Chris@16 40 * incremented when the reference count changes from 0 to 1, and decremented
Chris@16 41 * when a thread is about to check a value for erasure; it can be seen that a
Chris@16 42 * value is effectively erasable only when the deleter count goes down to 0
Chris@16 43 * (unless there are dangling references due to abnormal program termination,
Chris@16 44 * for instance if std::exit is called).
Chris@16 45 */
Chris@16 46
Chris@16 47 namespace boost{
Chris@16 48
Chris@16 49 namespace flyweights{
Chris@16 50
Chris@16 51 namespace detail{
Chris@16 52
Chris@16 53 template<typename Value,typename Key>
Chris@16 54 class refcounted_value
Chris@16 55 {
Chris@16 56 public:
Chris@16 57 explicit refcounted_value(const Value& x_):
Chris@16 58 x(x_),ref(0),del_ref(0)
Chris@16 59 {}
Chris@16 60
Chris@16 61 refcounted_value(const refcounted_value& r):
Chris@16 62 x(r.x),ref(0),del_ref(0)
Chris@16 63 {}
Chris@16 64
Chris@16 65 refcounted_value& operator=(const refcounted_value& r)
Chris@16 66 {
Chris@16 67 x=r.x;
Chris@16 68 return *this;
Chris@16 69 }
Chris@101 70
Chris@101 71 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
Chris@101 72 explicit refcounted_value(Value&& x_):
Chris@101 73 x(std::move(x_)),ref(0),del_ref(0)
Chris@101 74 {}
Chris@101 75
Chris@101 76 refcounted_value(refcounted_value&& r):
Chris@101 77 x(std::move(r.x)),ref(0),del_ref(0)
Chris@101 78 {}
Chris@101 79
Chris@101 80 refcounted_value& operator=(refcounted_value&& r)
Chris@101 81 {
Chris@101 82 x=std::move(r.x);
Chris@101 83 return *this;
Chris@101 84 }
Chris@101 85 #endif
Chris@16 86
Chris@16 87 operator const Value&()const{return x;}
Chris@16 88 operator const Key&()const{return x;}
Chris@16 89
Chris@16 90 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
Chris@16 91 private:
Chris@16 92 template<typename,typename> friend class refcounted_handle;
Chris@16 93 #endif
Chris@16 94
Chris@16 95 long count()const{return ref;}
Chris@16 96 long add_ref()const{return ++ref;}
Chris@16 97 bool release()const{return (--ref==0);}
Chris@16 98
Chris@16 99 void add_deleter()const{++del_ref;}
Chris@16 100 bool release_deleter()const{return (--del_ref==0);}
Chris@16 101
Chris@16 102 private:
Chris@16 103 Value x;
Chris@16 104 mutable boost::detail::atomic_count ref;
Chris@16 105 mutable long del_ref;
Chris@16 106 };
Chris@16 107
Chris@16 108 template<typename Handle,typename TrackingHelper>
Chris@16 109 class refcounted_handle
Chris@16 110 {
Chris@16 111 public:
Chris@16 112 explicit refcounted_handle(const Handle& h_):h(h_)
Chris@16 113 {
Chris@16 114 if(TrackingHelper::entry(*this).add_ref()==1){
Chris@16 115 TrackingHelper::entry(*this).add_deleter();
Chris@16 116 }
Chris@16 117 }
Chris@16 118
Chris@16 119 refcounted_handle(const refcounted_handle& x):h(x.h)
Chris@16 120 {
Chris@16 121 TrackingHelper::entry(*this).add_ref();
Chris@16 122 }
Chris@16 123
Chris@16 124 refcounted_handle& operator=(refcounted_handle x)
Chris@16 125 {
Chris@16 126 this->swap(x);
Chris@16 127 return *this;
Chris@16 128 }
Chris@16 129
Chris@16 130 ~refcounted_handle()
Chris@16 131 {
Chris@16 132 if(TrackingHelper::entry(*this).release()){
Chris@16 133 TrackingHelper::erase(*this,check_erase);
Chris@16 134 }
Chris@16 135 }
Chris@16 136
Chris@16 137 operator const Handle&()const{return h;}
Chris@16 138
Chris@16 139 void swap(refcounted_handle& x)
Chris@16 140 {
Chris@16 141 std::swap(h,x.h);
Chris@16 142 }
Chris@16 143
Chris@16 144 private:
Chris@16 145 static bool check_erase(const refcounted_handle& x)
Chris@16 146 {
Chris@16 147 return TrackingHelper::entry(x).release_deleter();
Chris@16 148 }
Chris@16 149
Chris@16 150 Handle h;
Chris@16 151 };
Chris@16 152
Chris@16 153 template<typename Handle,typename TrackingHelper>
Chris@16 154 void swap(
Chris@16 155 refcounted_handle<Handle,TrackingHelper>& x,
Chris@16 156 refcounted_handle<Handle,TrackingHelper>& y)
Chris@16 157 {
Chris@16 158 x.swap(y);
Chris@16 159 }
Chris@16 160
Chris@16 161 } /* namespace flyweights::detail */
Chris@16 162
Chris@16 163 #if BOOST_WORKAROUND(BOOST_MSVC,<=1500)
Chris@16 164 /* swap lookup by boost::swap fails under obscure circumstances */
Chris@16 165
Chris@16 166 } /* namespace flyweights */
Chris@16 167
Chris@16 168 template<typename Handle,typename TrackingHelper>
Chris@16 169 void swap(
Chris@16 170 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& x,
Chris@16 171 ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& y)
Chris@16 172 {
Chris@16 173 ::boost::flyweights::detail::swap(x,y);
Chris@16 174 }
Chris@16 175
Chris@16 176 namespace flyweights{
Chris@16 177 #endif
Chris@16 178
Chris@16 179 struct refcounted:tracking_marker
Chris@16 180 {
Chris@16 181 struct entry_type
Chris@16 182 {
Chris@16 183 template<typename Value,typename Key>
Chris@16 184 struct apply
Chris@16 185 {
Chris@16 186 typedef detail::refcounted_value<Value,Key> type;
Chris@16 187 };
Chris@16 188 };
Chris@16 189
Chris@16 190 struct handle_type
Chris@16 191 {
Chris@16 192 template<typename Handle,typename TrackingHelper>
Chris@16 193 struct apply
Chris@16 194 {
Chris@16 195 typedef detail::refcounted_handle<Handle,TrackingHelper> type;
Chris@16 196 };
Chris@16 197 };
Chris@16 198 };
Chris@16 199
Chris@16 200 } /* namespace flyweights */
Chris@16 201
Chris@16 202 } /* namespace boost */
Chris@16 203
Chris@16 204 #endif