Subject: [PATCH] [flyweight] implemented reader-writer locking for boost.flyweight based on boost::shared_mutex

From: Tim Blechmann <[email-masked]>
Date: Fri, 4 Jul 2008 18:19:58 +0200

---
 .../boost/flyweight/assoc_container_factory.hpp    |   16 +++++++-
 .../boost/flyweight/detail/flyweight_core.hpp      |   13 +++---
 .../flyweight/detail/handle_factory_adaptor.hpp    |    6 ++-
 flyweight/boost/flyweight/hashed_factory.hpp       |   15 ++++++-
 flyweight/boost/flyweight/no_locking.hpp           |    4 +-
 flyweight/boost/flyweight/rw_locking.hpp           |   40 ++++++++++++++++++++
 flyweight/boost/flyweight/rw_locking_fwd.hpp       |   26 +++++++++++++
 flyweight/boost/flyweight/simple_locking.hpp       |   10 ++++-
 .../libs/flyweight/test/test_custom_factory.cpp    |    9 +++-
 flyweight/libs/flyweight/test/test_rw_locking.cpp  |   35 +++++++++++++++++
 flyweight/libs/flyweight/test/test_rw_locking.hpp  |   11 +++++
 .../libs/flyweight/test/test_rw_locking_main.cpp   |   18 +++++++++
 12 files changed, 187 insertions(+), 16 deletions(-)
 create mode 100644 flyweight/boost/flyweight/rw_locking.hpp
 create mode 100644 flyweight/boost/flyweight/rw_locking_fwd.hpp
 create mode 100644 flyweight/libs/flyweight/test/test_rw_locking.cpp
 create mode 100644 flyweight/libs/flyweight/test/test_rw_locking.hpp
 create mode 100644 flyweight/libs/flyweight/test/test_rw_locking_main.cpp

diff --git a/flyweight/boost/flyweight/assoc_container_factory.hpp b/flyweight/boost/flyweight/assoc_container_factory.hpp
index 9d66b50..5d63bad 100644
--- a/flyweight/boost/flyweight/assoc_container_factory.hpp
+++ b/flyweight/boost/flyweight/assoc_container_factory.hpp
@@ -33,13 +33,25 @@ public:
   typedef typename Container::iterator   handle_type;
   typedef typename Container::value_type entry_type;
   
-  handle_type insert(const entry_type& x)
+  template <typename mutex_type, typename upgrade_lock_type,
+            typename upgrade_to_unique_lock>
+  handle_type insert(const entry_type& x, mutex_type & mutex)
   {
+    upgrade_lock_type upgrade_lock(mutex);
+    handle_type it = cont.find(x);
+
+    if (it != cont.end())
+      return it;
+
+    upgrade_to_unique_lock write_lock(upgrade_lock);
+
     return cont.insert(x).first;
   }
 
-  void erase(handle_type h)
+  template <typename mutex_type, typename write_lock_type>
+  void erase(handle_type h, mutex_type & mutex)
   {
+    write_lock_type lock (mutex);
     cont.erase(h);
   }
 
diff --git a/flyweight/boost/flyweight/detail/flyweight_core.hpp b/flyweight/boost/flyweight/detail/flyweight_core.hpp
index 86c2c8a..a358e27 100644
--- a/flyweight/boost/flyweight/detail/flyweight_core.hpp
+++ b/flyweight/boost/flyweight/detail/flyweight_core.hpp
@@ -65,9 +65,8 @@ public:
   template<typename Checker>
   static void erase(const handle_type& h,Checker check)
   {
-    typedef typename core::lock_type lock_type;
-    lock_type lock(core::mutex());
-    if(check(h))core::factory().erase(h);
+    if(check(h))
+      core::factory().erase<typename core::mutex_type, typename core::write_lock_type>(h, core::mutex());
   }
 };
 
@@ -110,14 +109,16 @@ public:
     handle_type,entry_type
   >                                            factory_type;
   typedef typename LockingPolicy::mutex_type   mutex_type;
-  typedef typename LockingPolicy::lock_type    lock_type;
+  typedef typename LockingPolicy::upgrade_lock_type           upgrade_lock_type;
+  typedef typename LockingPolicy::upgrade_to_unique_lock_type upgrade_to_unique_lock_type;
+  typedef typename LockingPolicy::write_lock_type             write_lock_type;
 
   static bool init(){return &(factory())!=0;}
 
   static handle_type insert(const Value& x)
   {
-    lock_type lock(mutex());
-    return handle_type(factory().insert(entry_type(x)));
+    return handle_type(factory().template insert<mutex_type,
+                       upgrade_lock_type, upgrade_to_unique_lock_type>(entry_type(x), mutex()));
   }
     
   static const Value& value(const handle_type& h)
diff --git a/flyweight/boost/flyweight/detail/handle_factory_adaptor.hpp b/flyweight/boost/flyweight/detail/handle_factory_adaptor.hpp
index 3ff030d..ddc4b1f 100644
--- a/flyweight/boost/flyweight/detail/handle_factory_adaptor.hpp
+++ b/flyweight/boost/flyweight/detail/handle_factory_adaptor.hpp
@@ -30,9 +30,11 @@ struct handle_factory_adaptor:Factory
 public:
   typedef Handle handle_type;
 
-  handle_type insert(const Entry& x)
+  template <typename mutex_type, typename upgrade_lock_type, typename upgrade_to_unique_lock>
+  handle_type insert(const Entry& x, mutex_type & mutex)
   {
-    return static_cast<handle_type>(base().insert(x));
+    return static_cast<handle_type>(base().template insert<mutex_type,
+                                    upgrade_lock_type, upgrade_to_unique_lock>(x, mutex));
   }
 
 private:
diff --git a/flyweight/boost/flyweight/hashed_factory.hpp b/flyweight/boost/flyweight/hashed_factory.hpp
index 135d813..4e93ab8 100644
--- a/flyweight/boost/flyweight/hashed_factory.hpp
+++ b/flyweight/boost/flyweight/hashed_factory.hpp
@@ -67,13 +67,24 @@ class hashed_factory_class:public factory_marker
 public:
   typedef const Entry* handle_type;
   
-  handle_type insert(const Entry& x)
+  template <typename mutex_type, typename upgrade_lock_type,
+            typename upgrade_to_unique_lock>
+  handle_type insert(const Entry& x, mutex_type & mutex)
   {
+    upgrade_lock_type upgrade_lock(mutex);
+    typename container_type::const_iterator it = cont.find(x);
+
+    if (it != cont.end())
+      return &*it;
+
+    upgrade_to_unique_lock write_lock(upgrade_lock);
     return &*cont.insert(x).first;
   }
 
-  void erase(handle_type h)
+  template <typename mutex_type, typename write_lock_type>
+  void erase(handle_type h, mutex_type & mutex)
   {
+    write_lock_type lock (mutex);
     cont.erase(cont.iterator_to(*h));
   }
 
diff --git a/flyweight/boost/flyweight/no_locking.hpp b/flyweight/boost/flyweight/no_locking.hpp
index a5ec8b4..56a65cf 100644
--- a/flyweight/boost/flyweight/no_locking.hpp
+++ b/flyweight/boost/flyweight/no_locking.hpp
@@ -26,7 +26,9 @@ namespace flyweights{
 struct no_locking:locking_marker
 {
   struct             mutex_type{};
-  typedef mutex_type lock_type;
+  typedef mutex_type upgrade_lock_type;
+  typedef mutex_type upgrade_to_unique_lock_type;
+  typedef mutex_type write_lock_type;
 };
 
 } /* namespace flyweights */
diff --git a/flyweight/boost/flyweight/rw_locking.hpp b/flyweight/boost/flyweight/rw_locking.hpp
new file mode 100644
index 0000000..7556e7d
--- /dev/null
+++ b/flyweight/boost/flyweight/rw_locking.hpp
@@ -0,0 +1,40 @@
+/* Copyright 2006-2007 Joaquín M López Muñoz.
+ * 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_RW_LOCKING_HPP
+#define BOOST_FLYWEIGHT_RW_LOCKING_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 <boost/flyweight/rw_locking_fwd.hpp>
+#include <boost/flyweight/locking_tag.hpp>
+
+#include <boost/thread/shared_mutex.hpp>
+
+/* recursive locking policy based on boost::shared_mutex */
+
+namespace boost{
+
+namespace flyweights{
+
+struct rw_locking:locking_marker
+{
+  typedef boost::shared_mutex                        mutex_type;
+  typedef boost::upgrade_lock<mutex_type>            upgrade_lock_type;
+  typedef boost::upgrade_to_unique_lock<mutex_type>  upgrade_to_unique_lock_type;
+  typedef boost::unique_lock<mutex_type>             write_lock_type;
+};
+
+} /* namespace flyweights */
+
+} /* namespace boost */
+
+#endif
diff --git a/flyweight/boost/flyweight/rw_locking_fwd.hpp b/flyweight/boost/flyweight/rw_locking_fwd.hpp
new file mode 100644
index 0000000..50d0685
--- /dev/null
+++ b/flyweight/boost/flyweight/rw_locking_fwd.hpp
@@ -0,0 +1,26 @@
+/* Copyright 2006-2007 Joaquín M López Muñoz.
+ * 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_RW_LOCKING_FWD_HPP
+#define BOOST_FLYWEIGHT_RW_LOCKING_FWD_HPP
+
+#if defined(_MSC_VER)&&(_MSC_VER>=1200)
+#pragma once
+#endif
+
+namespace boost{
+
+namespace flyweights{
+
+struct rw_locking;
+
+} /* namespace flyweights */
+
+} /* namespace boost */
+
+#endif
diff --git a/flyweight/boost/flyweight/simple_locking.hpp b/flyweight/boost/flyweight/simple_locking.hpp
index 2e6aba6..0acbeb0 100644
--- a/flyweight/boost/flyweight/simple_locking.hpp
+++ b/flyweight/boost/flyweight/simple_locking.hpp
@@ -27,7 +27,15 @@ namespace flyweights{
 struct simple_locking:locking_marker
 {
   typedef detail::recursive_lightweight_mutex mutex_type;
-  typedef mutex_type::scoped_lock             lock_type;
+  typedef mutex_type::scoped_lock             upgrade_lock_type;
+
+  struct upgrade_to_unique_lock_type
+  {
+    upgrade_to_unique_lock_type(upgrade_lock_type const &)
+    {}
+  };
+  typedef mutex_type::scoped_lock             write_lock_type;
+
 };
 
 } /* namespace flyweights */
diff --git a/flyweight/libs/flyweight/test/test_custom_factory.cpp b/flyweight/libs/flyweight/test/test_custom_factory.cpp
index 76fb3c7..b4bae2f 100644
--- a/flyweight/libs/flyweight/test/test_custom_factory.cpp
+++ b/flyweight/libs/flyweight/test/test_custom_factory.cpp
@@ -41,8 +41,11 @@ class lu_factory_class:public factory_marker
 public:
   typedef typename container_type::iterator handle_type;
   
-  handle_type insert(const Entry& x)
+  template <typename mutex_type, typename upgrade_lock_type, typename upgrade_to_unique_lock_type>
+  handle_type insert(const Entry& x, mutex_type & mutex)
   {
+    upgrade_lock_type lock(mutex);
+    upgrade_to_unique_lock_type ulock(lock);
     handle_type h;
     for(h=cont.begin();h!=cont.end();++h){
       if(static_cast<const Value&>(h->x)==static_cast<const Value&>(x)){
@@ -59,8 +62,10 @@ public:
     return h;
   }
 
-  void erase(handle_type h)
+  template <typename mutex_type, typename write_lock_type>
+  void erase(handle_type h, mutex_type & mutex)
   {
+    write_lock_type lock(mutex);
     cont.erase(h);
   }
 
diff --git a/flyweight/libs/flyweight/test/test_rw_locking.cpp b/flyweight/libs/flyweight/test/test_rw_locking.cpp
new file mode 100644
index 0000000..cc2ff17
--- /dev/null
+++ b/flyweight/libs/flyweight/test/test_rw_locking.cpp
@@ -0,0 +1,35 @@
+/* Boost.Flyweight test of no_locking.
+ *
+ * Copyright 2006-2007 Joaquín M López Muñoz.
+ * 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.
+ */
+
+#include "test_no_locking.hpp"
+
+#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
+#include <boost/flyweight/flyweight.hpp>
+#include <boost/flyweight/hashed_factory.hpp>
+#include <boost/flyweight/rw_locking.hpp>
+#include <boost/flyweight/refcounted.hpp>
+#include <boost/flyweight/static_holder.hpp>
+#include "test_basic_template.hpp"
+
+using namespace boost::flyweights;
+
+struct rw_locking_flyweight_specifier
+{
+  template<typename T>
+  struct apply
+  {
+    typedef flyweight<T,rw_locking> type;
+  };
+};
+
+void test_rw_locking()
+{
+  BOOST_FLYWEIGHT_TEST_BASIC(rw_locking_flyweight_specifier)
+}
diff --git a/flyweight/libs/flyweight/test/test_rw_locking.hpp b/flyweight/libs/flyweight/test/test_rw_locking.hpp
new file mode 100644
index 0000000..ed57c24
--- /dev/null
+++ b/flyweight/libs/flyweight/test/test_rw_locking.hpp
@@ -0,0 +1,11 @@
+/* Boost.Flyweight test of no_locking.
+ *
+ * Copyright 2006-2007 Joaquín M López Muñoz.
+ * 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.
+ */
+
+void test_rw_locking();
diff --git a/flyweight/libs/flyweight/test/test_rw_locking_main.cpp b/flyweight/libs/flyweight/test/test_rw_locking_main.cpp
new file mode 100644
index 0000000..ffbefe5
--- /dev/null
+++ b/flyweight/libs/flyweight/test/test_rw_locking_main.cpp
@@ -0,0 +1,18 @@
+/* Boost.Flyweight test of no_locking.
+ *
+ * Copyright 2006-2007 Joaquín M López Muñoz.
+ * 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.
+ */
+
+#include <boost/detail/lightweight_test.hpp>
+#include "test_rw_locking.hpp"
+
+int main()
+{
+  test_rw_locking();
+  return boost::report_errors();
+}
-- 
1.5.6