OSDN Git Service

memberwise_swap を追加
[gintenlib/gintenlib.git] / gintenlib / clonable_ptr.hpp
1 #ifndef GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_
2 #define GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_
3
4 /*
5
6       <gintenlib/clonable_ptr.hpp>
7
8   clonable_ptr : 深いコピーが可能な参照カウント式スマートポインタ
9
10   宣言:
11     template<typename T>
12     struct clonable_ptr
13     {
14       typedef T element_type;
15       typedef T value_type;
16       typedef T* pointer;
17       typedef typename boost::add_reference<T>::type reference;
18       
19       // デフォルトコンストラクタ
20       clonable_ptr();
21       
22       // ポインタから作るコンストラクタ
23       template<typename U>
24       explicit clonable_ptr( U* p );
25       
26       // copy constructor
27       clonable_ptr( const clonable_ptr& src );
28       template<typename U>
29       clonable_ptr( const clonable_ptr<U>& src );
30       
31       // デストラクタ
32       ~clonable_ptr() {}
33       
34       // nothrow swap
35       void swap( clonable_ptr& other );
36       friend void swap( clonable_ptr& one, clonable_ptr& another );
37       
38       // operator=
39       clonable_ptr& operator=( const clonable_ptr& rhs );
40       template<typename U>
41       clonable_ptr& operator=( const clonable_ptr<U>& rhs );
42       
43       // reset
44       void reset();
45       template<typename U>
46       void reset( U* p );
47       
48       
49       // スマートポインタ関連のあれこれ
50       T* get() const;
51       friend T* get_pointer( const clonable_ptr& );
52       T* operator->() const;
53       T& operator*() const;
54       
55       operator unspecified_bool_type() const;
56       bool operator!() const;
57       
58       
59       // 参照カウントの数を返す
60       int use_count() const;
61       // 参照するオブジェクトが、このポインタのみから参照されている場合 true
62       bool unique() const;
63       
64       // オブジェクトの複製を作り出して返す
65       clonable_ptr<typename boost::remove_const<T>::type> clone() const;
66       // unique でなければ参照するオブジェクトを複製して unique にする
67       void to_unique();
68       
69       // shared_ptr への変換
70       shared_ptr<T> to_shared() const;
71       friend shared_ptr<T> to_shared( const clonable_ptr& target );
72       
73     
74     };
75     
76     // 比較
77     template<typename T1, typename T2>
78     inline bool operator==( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
79     template<typename T1, typename T2>
80     inline bool operator!=( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
81     template<typename T1, typename T2>
82     inline bool operator<( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
83     
84     // pointer casts
85     template<typename T1, typename T2>
86     friend clonable_ptr<T1> static_pointer_cast( const clonable_ptr<T2>& src );
87     template<typename T1, typename T2>
88     friend clonable_ptr<T1> dynamic_pointer_cast( const clonable_ptr<T2>& src );
89     template<typename T1, typename T2>
90     friend clonable_ptr<T1> const_pointer_cast( const clonable_ptr<T2>& src );
91
92   機能:
93     対象の「深いコピー」を生成できる参照カウント式スマートポインタ。
94     主に対象の型を正確に記憶し複製する程度の機能を持ちます。
95     特に便利なのが to_unique メンバ関数で、このポインタの存在理由の大半がこれに集約されます。
96     コピーにコストのかかるオブジェクトを扱うとき、普段は浅いコピーでコピーコストを削減、
97     オブジェクトに変更を加えるときはその前に to_unique を呼び出す、なんて使い方が一般的かと。
98     もちろん、「対象のオブジェクトの正確なコピーを作れる」という点に着目した使い方もアリです。
99     高機能ですが、コピー不能なオブジェクトはそもそも格納できないので、そこだけは注意が必要。
100     また、仮想関数とテンプレートを使った実装なので、コンパイル後のサイズは大きくなります。
101     便利だけど頼りすぎず、他の上手い実装があればそちらを優先してやってください。
102
103 */
104
105 #include "pointer_facade.hpp"
106 #include "reference_counter.hpp"
107 #include "shared_ptr.hpp" // for to_shared
108
109 #include <boost/intrusive_ptr.hpp>
110 #include <boost/type_traits/remove_const.hpp>
111 #include <utility>  // for std::pair
112
113 namespace gintenlib
114 {
115   namespace detail_
116   {
117     // カウントされるオブジェクト
118     struct clonable_counted_base
119       : reference_counter<clonable_counted_base>
120     {
121       // virtual destructor
122       virtual ~clonable_counted_base(){}
123       
124       // 本体、複製を作る
125       typedef std::pair<clonable_counted_base*, void*> cloned_type;
126       virtual cloned_type clone() const = 0;
127       
128     };  // clonable_counted_base
129     
130     // make_clonable 用 impl
131     template< typename T >
132     struct clonable_counted_impl_obj
133       : clonable_counted_base
134     {
135       // 制作
136       explicit clonable_counted_impl_obj( const T& src )
137         : obj(src) {}
138       
139       // 解放
140       // virtual ~clonable_counted_impl_obj() {}
141       
142       // 複製制作
143       typedef typename boost::remove_const<T>::type T_;
144       typedef clonable_counted_impl_obj<T_> impl_type;
145       
146       using clonable_counted_base::cloned_type;
147       virtual cloned_type clone() const
148       {
149         impl_type* pt = new impl_type(obj);
150         return std::make_pair( pt, pt->get() );
151       }
152       
153       // 保持するオブジェクトのアドレスを取得
154       T* get() { return &obj; }
155       
156      private:
157       T obj;
158      
159     };  // clonable_counted_impl_obj
160     
161     // ポインタで渡された場合に対応
162     template< typename T >
163     struct clonable_counted_impl_p
164       : clonable_counted_base
165     {
166       explicit clonable_counted_impl_p( T* p_ )
167         : p( p_ ) {}
168       
169       // 解放処理
170       virtual ~clonable_counted_impl_p()
171       {
172         boost::checked_delete(p);
173       }
174       
175       // 複製制作
176       using clonable_counted_base::cloned_type;
177       typedef typename boost::remove_const<T>::type T_;
178       typedef clonable_counted_impl_obj<T_> impl_type;
179       virtual cloned_type clone() const
180       {
181         impl_type* pt = new impl_type(*p);
182         return std::make_pair( pt, pt->get() );
183       }
184       
185       // 保持するポインタのアドレスを取得
186       T* get() const { return p; }
187       
188      private:
189       T* p;
190     
191     };  // clonable_counted_impl_p
192     
193     
194     // cloning_ptr 用の参照カウンタ
195     struct clonable_count
196     {
197       // デフォルト初期化
198       clonable_count() {}
199       
200       // T 型のオブジェクト p_ に関連付けられたカウンタを作る
201       template<typename T>
202       explicit clonable_count( T* p_ )
203         : p( p_ ? new clonable_counted_impl_p<T>(p_) : 0 ) {}
204       
205       // clonable_counted_base* からの構築
206       clonable_count( clonable_counted_base* p_ )
207         : p( p_ ) {}
208       
209       // デストラクタは自動定義された奴でおk
210       // ~clonable_count(){}
211       
212       // no throw swap
213       void swap( clonable_count& other )
214       {
215         p.swap( other.p );
216       }
217       friend void swap( clonable_count& one, clonable_count& another )
218       {
219         one.swap( another );
220       }
221       
222       // 複製制作
223       typedef std::pair<clonable_count, void*> cloned_type;
224       // clonable_count は clonable_counted_base* から暗黙変換できる
225       cloned_type clone() const
226       {
227         return p ? cloned_type( p->clone() ) : cloned_type( 0, 0 );
228       }
229       
230       // 内部のカウントを使用する
231       int use_count() const { return p ? p->use_count() : 0; }
232       // ユニークか否か
233       bool unique() const { return use_count() == 1; }
234       
235      private:
236       boost::intrusive_ptr<clonable_counted_base> p;
237     
238     };  // clonable_count
239     
240     class clonable_ptr_tag {};
241     
242   } // namespace detail_
243   
244   
245   
246   template<typename T>
247   struct clonable_ptr
248     : pointer_facade< clonable_ptr<T>, T, detail_::clonable_ptr_tag >
249   {
250    private:
251     typedef clonable_ptr this_type;
252     typedef detail_::clonable_count clonable_count;
253     
254    public:
255     // デフォルトコンストラクタ
256     clonable_ptr() : p(), count() {}
257     
258     // ポインタから作るコンストラクタ
259     template<typename U>
260     explicit clonable_ptr( U* p_ )
261       : p( p_ ), count( p_ ) {}
262     
263     // copy constructor では clone しない
264     clonable_ptr( const clonable_ptr& src )
265       : p( src.p ), count( src.count ) {}
266     template<typename U>
267     clonable_ptr( const clonable_ptr<U>& src )
268       : p( src.p ), count( src.count ) {}
269     
270     // デストラクタの処理は clonable_count に任せる
271     // ~clonable_ptr() {}
272     
273     // swap
274     void swap( this_type& other )
275     {
276       using std::swap;
277       swap( p, other.p );
278       swap( count, other.count );
279     }
280     friend void swap( this_type& one, this_type& another )
281     {
282       one.swap( another );
283     }
284     
285     // 代入演算
286     this_type& operator=( const this_type& rhs )
287     {
288       this_type(rhs).swap( *this );
289       return *this;
290     }
291     template<typename U>
292     this_type& operator=( const clonable_ptr<U>& rhs )
293     {
294       this_type(rhs).swap( *this );
295       return *this;
296     }
297     
298     // reset
299     void reset()
300     { 
301       this_type().swap( *this );
302     }
303     template<typename U>
304     void reset( U* p_ )
305     { 
306       this_type(p_).swap( *this );
307     }
308     
309     // get() さえ定義すれば後は pointer_facade により自動
310     T* get() const { return p; }
311     
312     
313     // 本体
314     
315     // 複製制作
316     typedef typename boost::remove_const<T>::type T_;
317     typedef clonable_ptr<T_> cloned_type;
318     cloned_type clone() const
319     {
320       return cloned_type( count.clone() );
321     }
322     // 参照カウント計算
323     int use_count() const { return count.use_count(); }
324     bool unique() const { return count.unique(); }
325     // unique じゃなければ複製して unique に
326     void to_unique()
327     {
328       if( p != 0 && !unique() )
329       {
330         clone().swap(*this);
331       }
332     }
333     
334     // to_shared
335     struct to_shared_helper
336     {
337       to_shared_helper( const clonable_count& count_ )
338         : count( count_ ) {}
339       
340       // デストラクタで適宜やってくれるので
341       // operator() では何も行わない
342       void operator()( T* ) const {}
343       
344      private:
345       clonable_count count;
346       
347     };
348     // shared_ptr に変換
349     shared_ptr<T> to_shared() const
350     {
351       return p ? shared_ptr<T>( p, to_shared_helper(count) ) : shared_ptr<T>();
352     }
353     friend shared_ptr<T> to_shared( const this_type& target )
354     {
355       return target.to_shared();
356     }
357     
358    private:
359     T* p;
360     clonable_count count;
361     
362     template<typename U> friend class clonable_ptr;
363     
364     // 裏技コンストラクタ
365     clonable_ptr( const clonable_count& count_, T* p_ )
366       : p(p_), count(count_) {}
367     explicit clonable_ptr( const clonable_count::cloned_type& pair )
368       : p( static_cast<T*>( pair.second ) ), count( pair.first ) {}
369     
370     // pointer casts
371     template<typename T1, typename T2>
372     friend clonable_ptr<T1> static_pointer_cast( const clonable_ptr<T2>& src );
373     template<typename T1, typename T2>
374     friend clonable_ptr<T1> dynamic_pointer_cast( const clonable_ptr<T2>& src );
375     template<typename T1, typename T2>
376     friend clonable_ptr<T1> const_pointer_cast( const clonable_ptr<T2>& src );
377     
378   };  // clonable_ptr<T>
379   
380   // xxx_pointer_cast
381   template<typename T, typename S>
382   inline clonable_ptr<T> static_pointer_cast( const clonable_ptr<S>& src )
383   {
384     return clonable_ptr<T>( src.count, static_cast<T*>(src.p) );
385   }
386   template<typename T, typename S>
387   inline clonable_ptr<T> dynamic_pointer_cast( const clonable_ptr<S>& src )
388   {
389     T* p = dynamic_cast<T*>(src.p);
390     return p ? clonable_ptr<T>( src.count, p ) : clonable_ptr<T>();
391   }
392   template<typename T, typename S>
393   inline clonable_ptr<T> const_pointer_cast( const clonable_ptr<S>& src )
394   {
395     return clonable_ptr<T>( src.count, const_cast<T*>(src.p) );
396   }
397
398 } // namespace gintenlib
399
400 #endif  // #ifndef GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_