Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/flyweight/refcounted.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* Copyright 2006-2024 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/flyweight for library home page.
0007  */
0008 
0009 #ifndef BOOST_FLYWEIGHT_REFCOUNTED_HPP
0010 #define BOOST_FLYWEIGHT_REFCOUNTED_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
0017 #include <algorithm>
0018 #include <boost/config/workaround.hpp>
0019 #include <boost/core/invoke_swap.hpp>
0020 #include <boost/flyweight/refcounted_fwd.hpp>
0021 #include <boost/flyweight/tracking_tag.hpp>
0022 #include <boost/smart_ptr/detail/atomic_count.hpp>
0023 
0024 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0025 #include <utility>
0026 #endif
0027 
0028 /* Refcounting tracking policy.
0029  * The implementation deserves some explanation; values are equipped with two
0030  * reference counts:
0031  *   - a regular count of active references
0032  *   - a deleter count
0033  * It looks like a value can be erased when the number of references reaches
0034  * zero, but this condition alone can lead to data races:
0035  *   - Thread A detaches the last reference to x and is preempted.
0036  *   - Thread B looks for x, finds it and attaches a reference to it.
0037  *   - Thread A resumes and proceeds with erasing x, leaving a dangling
0038  *     reference in thread B.
0039  * Here is where the deleter count comes into play. This count is
0040  * incremented when the reference count changes from 0 to 1, and decremented
0041  * when a thread is about to check a value for erasure; it can be seen that a
0042  * value is effectively erasable only when the deleter count goes down to 0
0043  * (unless there are dangling references due to abnormal program termination,
0044  * for instance if std::exit is called).
0045  */
0046 
0047 namespace boost{
0048 
0049 namespace flyweights{
0050 
0051 namespace detail{
0052 
0053 template<typename Value,typename Key>
0054 class refcounted_value
0055 {
0056 public:
0057   explicit refcounted_value(const Value& x_):
0058     x(x_),ref(0),del_ref(0)
0059   {}
0060   
0061   refcounted_value(const refcounted_value& r):
0062     x(r.x),ref(0),del_ref(0)
0063   {}
0064 
0065   refcounted_value& operator=(const refcounted_value& r)
0066   {
0067     x=r.x;
0068     return *this;
0069   }
0070 
0071 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0072   explicit refcounted_value(Value&& x_):
0073     x(std::move(x_)),ref(0),del_ref(0)
0074   {}
0075 
0076   refcounted_value(refcounted_value&& r):
0077     x(std::move(r.x)),ref(0),del_ref(0)
0078   {}
0079 
0080   refcounted_value& operator=(refcounted_value&& r)
0081   {
0082     x=std::move(r.x);
0083     return *this;
0084   }
0085 #endif
0086   
0087   operator const Value&()const{return x;}
0088   operator const Key&()const{return x;}
0089     
0090 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
0091 private:
0092   template<typename,typename> friend class refcounted_handle;
0093 #endif
0094 
0095   long count()const{return ref;}
0096   long add_ref()const{return ++ref;}
0097   bool release()const{return (--ref==0);}
0098 
0099   void add_deleter()const{++del_ref;}
0100   bool release_deleter()const{return (--del_ref==0);}
0101 
0102 private:
0103   Value                               x;
0104   mutable boost::detail::atomic_count ref;
0105   mutable long                        del_ref;
0106 };
0107 
0108 template<typename Handle,typename TrackingHelper>
0109 class refcounted_handle
0110 {
0111 public:
0112   explicit refcounted_handle(const Handle& h_):h(h_)
0113   {
0114     if(TrackingHelper::entry(*this).add_ref()==1){
0115       TrackingHelper::entry(*this).add_deleter();
0116     }
0117   }
0118   
0119   refcounted_handle(const refcounted_handle& x):h(x.h)
0120   {
0121     TrackingHelper::entry(*this).add_ref();
0122   }
0123 
0124   refcounted_handle& operator=(refcounted_handle x)
0125   {
0126     this->swap(x);
0127     return *this;
0128   }
0129 
0130   ~refcounted_handle()
0131   {
0132     if(TrackingHelper::entry(*this).release()){
0133       TrackingHelper::erase(*this,check_erase);
0134     }
0135   }
0136 
0137   operator const Handle&()const{return h;}
0138 
0139   void swap(refcounted_handle& x)
0140   {
0141     boost::core::invoke_swap(h,x.h);
0142   }
0143 
0144 private:
0145   static bool check_erase(const refcounted_handle& x)
0146   {
0147     return TrackingHelper::entry(x).release_deleter();
0148   }
0149 
0150   Handle h;
0151 };
0152 
0153 template<typename Handle,typename TrackingHelper>
0154 void swap(
0155   refcounted_handle<Handle,TrackingHelper>& x,
0156   refcounted_handle<Handle,TrackingHelper>& y)
0157 {
0158   x.swap(y);
0159 }
0160 
0161 } /* namespace flyweights::detail */
0162 
0163 #if BOOST_WORKAROUND(BOOST_MSVC,<=1500)
0164 /* swap lookup by boost::core::invoke_swap fails under obscure circumstances */
0165 
0166 } /* namespace flyweights */
0167 
0168 template<typename Handle,typename TrackingHelper>
0169 void swap(
0170   ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& x,
0171   ::boost::flyweights::detail::refcounted_handle<Handle,TrackingHelper>& y)
0172 {
0173   ::boost::flyweights::detail::swap(x,y);
0174 }
0175 
0176 namespace flyweights{
0177 #endif
0178 
0179 struct refcounted:tracking_marker
0180 {
0181   struct entry_type
0182   {
0183     template<typename Value,typename Key>
0184     struct apply
0185     {
0186       typedef detail::refcounted_value<Value,Key> type;
0187     };
0188   };
0189 
0190   struct handle_type
0191   {
0192     template<typename Handle,typename TrackingHelper>
0193     struct apply
0194     {
0195       typedef detail::refcounted_handle<Handle,TrackingHelper> type;
0196     };
0197   };
0198 };
0199 
0200 } /* namespace flyweights */
0201 
0202 } /* namespace boost */
0203 
0204 #endif