OSDN Git Service

reference_counter に代わるライブラリ intrusive_ptr_hook を追加
authorSubaruG <subaru_g@users.sourceforge.jp>
Fri, 2 Apr 2010 12:14:53 +0000 (21:14 +0900)
committerSubaruG <subaru_g@users.sourceforge.jp>
Fri, 2 Apr 2010 12:14:53 +0000 (21:14 +0900)
gintenlib/intrusive_ptr_hook.hpp [new file with mode: 0644]
gintenlib/reference_counter.hpp
tests/intrusive_ptr_hook.cc [new file with mode: 0644]

diff --git a/gintenlib/intrusive_ptr_hook.hpp b/gintenlib/intrusive_ptr_hook.hpp
new file mode 100644 (file)
index 0000000..2b70227
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef GINTENLIB_INCLUDED_INTRUSIVE_PTR_HOOK_HPP_
+#define GINTENLIB_INCLUDED_INTRUSIVE_PTR_HOOK_HPP_
+
+/*
+
+      <gintenlib/intrusive_ptr_hook.hpp>
+
+  intrusive_ptr_hook : boost::intrusive_ptr 用オブジェクト生成(削除子指定版)
+
+  宣言:
+    template<typename Derived, typename Deleter = deleter, typename Counter = int>
+    class intrusive_ptr_hook
+    {
+     protected:
+      // 型定義
+      typedef Counter counter_type;
+      typedef Deleter      deleter;
+    
+      // デフォルトコンストラクタ
+      intrusive_ptr_hook();
+      // コピーコンストラクタ(コピーしない)
+      intrusive_ptr_hook( this_type const& );
+      // 削除子指定
+      explicit intrusive_ptr_hook( Deleter const& d );
+      // 初期カウント指定
+      explicit intrusive_ptr_hook( counter_type initial_count );
+      // 初期カウント指定&削除子指定
+      intrusive_ptr_hook( counter_type initial_count, Deleter const& d );
+      
+      // operator=(何もしない)
+      this_type& operator=( const this_type& );
+      
+      // メンバアクセス
+      counter_type use_count() const;
+      deleter& get_deleter();
+      deleter const& get_deleter() const;
+    
+      // ADLによって呼び出される参照カウントアクセス関数群
+      // カウントの増減
+      friend void intrusive_ptr_add_ref( Derived const* p );
+      friend void intrusive_ptr_release( Derived const* p );
+      // カウントチェック(独自拡張)
+      friend void intrusive_ptr_use_count( Derived const* p );
+      
+    };
+    
+    template< typename T, bool b >
+    inline void intrusive_ptr_add_ref( const reference_counter<T, b>* ptr );
+    template< typename T, bool b >
+    inline void intrusive_ptr_release( const reference_counter<T, b>* ptr );
+    
+  使用法:
+    class hoge
+      : public gintenlib::intrusive_ptr_hook<hoge>
+    {
+      // 実装
+    };
+    
+  仕様:
+    ・ADL
+        intrusive_ptr_add_ref, intrusive_ptr_release, intrusive_ptr_use_count は
+        ADLによってのみ呼び出されます。gintenlib::intrusive_ptr_xxx とは呼べません。
+        intrusive_ptr_hook を継承することが原因で、継承先のクラスのADL対象に
+        gintenlib 名前空間が加わることはありません。
+    ・例外仕様
+        Deleter のコピーコンストラクタにおいて例外が投げられない限り、例外安全です。
+    ・マルチスレッド対応
+        カウンタによって対処します(現在検討中)。
+    ・コピー関連の動作
+        コピー、代入操作は、一貫して「何も行わない」方針を採っています。
+        コピー初期化される場合は、カウンタ、削除子、共にデフォルト値で初期化されます。
+        代入される場合は、カウンタ、削除子、共にまったく影響を受けません。
+
+*/
+
+#include "deleter.hpp"
+
+#include <cassert>
+#include <boost/compressed_pair.hpp>
+
+namespace gintenlib
+{
+ namespace intrusive_ptr_hook_  // ADL 回避用
+ {
+  template<typename Derived, typename Deleter = deleter, typename Counter = int>
+  class intrusive_ptr_hook
+  {
+    typedef intrusive_ptr_hook this_type;
+    
+   protected:
+    // 型定義
+    typedef Counter counter_type;
+    typedef Deleter      deleter;
+    
+    
+    // デフォルトコンストラクタ
+    intrusive_ptr_hook()
+      : pair_( counter_type(), deleter() ) {}
+    // コピーコンストラクタ(コピーしない)
+    intrusive_ptr_hook( this_type const& )
+      : pair_( counter_type(), deleter() ) {}
+    // 削除子指定
+    explicit intrusive_ptr_hook( Deleter const& d )
+      : pair_( counter_type(), d ) {}
+    // 初期カウント指定
+    explicit intrusive_ptr_hook( counter_type initial_count )
+      : pair_( initial_count, deleter() ) {}
+    // 初期カウント指定&削除子指定
+    intrusive_ptr_hook( counter_type initial_count, Deleter const& d )
+      : pair_( initial_count, d ) {}
+    
+    // operator=(何もしない)
+    this_type& operator=( const this_type& )
+    {
+      return *this;
+    }
+    
+    // メンバアクセス
+    counter_type use_count() const { return count_(); }
+    
+    deleter& get_deleter() { return deleter_(); }
+    deleter const& get_deleter() const { return deleter_(); }
+    
+    
+   private:
+    // メンバ
+    typedef boost::compressed_pair<counter_type, deleter> pair_type;
+    mutable pair_type pair_;
+    
+    counter_type& count_() const { return pair_.first(); }
+    deleter& deleter_() const { return pair_.second(); }
+    
+    // Derived からのメンバアクセス
+    static counter_type& get_count( Derived const& x )
+    {
+      return static_cast<this_type const&>(x).count_();
+    }
+    static deleter const& get_deleter( Derived const& x )
+    {
+      return static_cast<this_type const&>(x).get_deleter();
+    }
+    
+    
+    // カウントの増減
+    // ADLによって呼び出される
+    friend void intrusive_ptr_add_ref( Derived const* p )
+    {
+      using namespace std;
+      assert( p != 0 );
+      
+      counter_type& count = get_count(*p);
+      assert( count >= 0 );
+      
+      ++count;
+      
+    }
+    friend void intrusive_ptr_release( Derived const* p )
+    {
+      using namespace std;
+      assert( p != 0 );
+      
+      counter_type& count = get_count(*p);
+      assert( count > 0 );
+      
+      --count;
+      
+      if( count == 0 )
+      {
+        // p の破棄処理の途中で deleter が削除されると困るのでコピーする
+        deleter d = get_deleter(*p);
+        // 削除本体
+        d(p);
+      }
+    }
+    // カウントチェック(独自拡張)
+    friend counter_type intrusive_ptr_use_count( Derived const* p )
+    {
+      using namespace std;
+      assert( p != 0 );
+      
+      counter_type const count = get_count(*p);
+      assert( count >= 0 );
+      
+      return count;
+    }
+
+    
+  };  // intrusive_ptr_hook<Derived, Deleter>
+ }  // namespace intrusive_ptr_hook_
+ using namespace intrusive_ptr_hook_;
+  
+}   // namespace gintenlib
+
+
+#endif  // #ifndef GINTENLIB_INCLUDED_INTRUSIVE_PTR_HOOK_HPP_
index 2405c80..5c1ae62 100644 (file)
@@ -6,6 +6,10 @@
       <gintenlib/reference_counter.hpp>
 
   reference_counter : boost::intrusive_ptr 用オブジェクト生成
+  
+  【注】同様の機能を提供するライブラリに、 intrusive_ptr_hook があります。
+        intrusive_ptr_hook は削除子の指定が可能となっている改良であり、
+        基本的には intrusive_ptr_hook を使うことを推奨します。
 
   宣言:
     template<typename Derived, bool multiplely_successable = false >
diff --git a/tests/intrusive_ptr_hook.cc b/tests/intrusive_ptr_hook.cc
new file mode 100644 (file)
index 0000000..cbd8904
--- /dev/null
@@ -0,0 +1,58 @@
+// ヘッダ
+#include "../gintenlib/intrusive_ptr_hook.hpp"
+
+// boost の単体テストフレームワーク
+#include <boost/test/minimal.hpp>
+
+// これがないとテストしようがない
+#include <boost/intrusive_ptr.hpp>
+
+// 通常版
+struct simple
+  : gintenlib::intrusive_ptr_hook<simple>
+{
+  static int instances;
+  
+  simple() { ++instances; }
+  ~simple() throw () { --instances; }
+  
+  int use_count() const
+  {
+    return intrusive_ptr_use_count( this );
+  }
+  
+};
+int simple::instances = 0;
+
+void simple_test()
+{
+  BOOST_CHECK( simple::instances == 0 );
+  {
+    // 通常の生成と破棄
+    simple const x;
+    BOOST_CHECK( simple::instances == 1 );
+    BOOST_CHECK( x.use_count() == 0 );
+  }
+  BOOST_CHECK( simple::instances == 0 );
+  {
+    // 本番
+    boost::intrusive_ptr<simple const> p1( new simple ), p2( new simple );
+    BOOST_CHECK( simple::instances == 2 );
+    BOOST_CHECK( p1->use_count() == 1 );
+    BOOST_CHECK( p2->use_count() == 1 );
+    // 移動させてカウントを変化させる
+    p2 = p1;
+    BOOST_CHECK( simple::instances == 1 );
+    BOOST_CHECK( p1->use_count() == 2 );
+    BOOST_CHECK( p2->use_count() == 2 );
+  }
+  BOOST_CHECK( simple::instances == 0 );
+}
+
+int test_main( int, char** )
+{
+  simple_test();
+  
+  return 0;
+}
+