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