OSDN Git Service

余計なGTAGSをコミットしないようにした。
[simplecms/utakata.git] / smart_ptr.h
1 #ifndef ___HGL___smart_ptr___
2 #define ___HGL___smart_ptr___
3
4 #include "ref_delete.h"
5
6 /**
7    smart_ptr_base
8    スマートポインタの基底クラス。
9    特に何をするわけでもない。
10 */
11 class smart_ptr_base {
12 public:
13     virtual ~smart_ptr_base(){}
14 };
15
16 /**
17    smart_ptr
18    スマートポインタ。
19    smart_ptr<CHoge> h(new CHoge);
20    とやれば、後はコピーしても解体責任を委譲したりして、
21    ちゃんとdeleteしてくれるようなクラス。
22    また、配列もとれるようにして、配列であっても
23    通常のポインタであっても、ちゃんとdeleteとdelete[]を
24    分けてくれる。
25
26    配列を生成する際には、
27
28    smart_ptr<CHoge> h;
29    h.addArray(true,10);
30    のように生成するか、
31    もしくは、CHogeの派生クラスSHogeを生成したりする場合は、
32    h.addArray(new SHoge[10],true,10);
33
34    のようにする。
35 */
36 template<class T>
37 class smart_ptr // : public smart_ptr_base
38 {
39 public:
40
41     //暗黙の型変換を行わない。
42     //このコンストラクタでは、配列の生成は出来ないことになっている。
43     template<class S> explicit 
44     smart_ptr(S* p, bool owner = true, ref_delete_base* ref = NULL) : 
45         obj_(NULL),ref_obj_(NULL),index_(0) {
46         if (p != NULL) {
47             init(p,owner,1, ref);
48         }
49     }
50
51     //デフォルトコンストラクタ
52     smart_ptr() : obj_(NULL),ref_obj_(NULL),index_(0) {
53     }
54     
55     //コピーコンストラクタ
56     smart_ptr(const smart_ptr<T>& p) : 
57         obj_(NULL),ref_obj_(NULL),index_(0) {
58         //参照カウントを増やしつつ、コピー。
59         inc(p);
60     }
61
62     //参照数を減らすだけ。
63     virtual ~smart_ptr() {dec();}
64
65     //明示的に削除するための構文
66     virtual void release() {dec();}
67
68     //ここからは、ポインタの振りをするための仕掛け。
69     T& operator*() const {return *get();}
70     T* operator->() const {return get();}
71
72     //擬似的な配列操作のため。
73     smart_ptr<T>& operator++() {incIndex();return *this;}
74     smart_ptr<T>& operator++(int n) {incIndex();return *this;}
75     smart_ptr<T>& operator--() {decIndex();return *this;}
76     smart_ptr<T>& operator--(int n) {decIndex();return *this;}
77
78     //配列からの取得のため。
79     T& operator[](int n) const {return *get(n + 1);}
80
81     smart_ptr<T>& operator=(const smart_ptr<T>& obj) {
82         //コピーコンストラクタ。
83         //前のオブジェクトの参照カウントを減らした後、
84         //コピーする
85         if (this != &obj) {
86             dec();
87             inc(obj);
88         }
89         return *this;
90     }
91
92     /**
93        get
94        保持するメモリから、指定された場所のメモリを取得する。
95        @param int n デフォルトは1
96        @access public
97        @return 指定された位置のテンプレートで指定されたオブジェクト
98     */
99     T* get(int n = 1) const {
100         //配列、単一変数どちらにでも対応するため、
101         //引数で場所を取る。
102         
103
104         if (ref_obj_ == NULL) {
105             return NULL;
106         }
107
108         if (index_ + n > ref_obj_->getMaxNum() || index_ + n < 0) {
109             return NULL;
110         }
111
112         //取得すべきメモリは、
113         //オブジェクトの先頭アドレス+オブジェクトのサイズ*(インデックス+引数)
114         //なお、この際に、index_ = 0かつ、n = 1である場合、
115         //先頭アドレス+オブジェクトサイズということになり、どう考えてもアクセス違反になる。
116         return (T*)((unsigned char*)obj_ + (ref_obj_->getObjSize() * (index_ + n - 1)));
117     }
118
119     //==============================================
120     //疑似イテレーターとして使用するための関数群
121     //==============================================
122
123     /**
124        isEnd
125        インデックスが、限界に達していないかどうか
126        ここで言う限界とは、MaxNumで、つまり添え字+1をさす。
127        @access public
128        @return bool 達している場合はtrue
129     */
130     bool isEnd() {
131         if (ref_obj_ != NULL) {
132             return ref_obj_->getMaxNum()-1 < index_?true:false;
133         } else {
134             return true;
135         }
136     }
137
138     /**
139        isBegin
140        インデックスが、先頭であるかどうか
141        @access public
142        @return bool 先頭である場合はtrue
143     */
144     bool isBegin() {
145         return index_ == 0?true:false;
146     }
147
148     /**
149        オブジェクトがNULLかどうか
150        @access public
151        @return bool
152     */
153     bool isNull() const {
154         return ref_obj_==NULL&&obj_==NULL?true:false;
155     }
156     
157     /**
158        end
159        インデックスを、最後尾に位置させる
160        @access public
161        @return void
162     */
163     void end() {
164         if (ref_obj_ != NULL) {
165             index_ = ref_obj_->getMaxNum()-1;
166         } else {
167             index_ = 0;
168         }
169     }
170
171     /**
172        begin
173        インデックスを、先頭に位置させる
174        @access public
175        @return void
176     */
177     void begin() {
178         index_ = 0;
179     }
180
181     //=============================================
182     //追加生成関数群
183     //=============================================
184
185     /**
186      * @brief アップキャストを行う。SはTの派生クラスであること。
187      * また、その特性上同一性チェックが困難であるので、こればかりは仕方がない。
188      * @param const smart_ptr<S>& スマートポインタ
189      * @return smart_ptr<T>& アップキャスト後の自身。
190      */
191     template<class S>
192     smart_ptr<T>& upcast(const smart_ptr<S>& p) {
193         
194         if (reinterpret_cast<void*>(this) != 
195             reinterpret_cast<void*>(const_cast<smart_ptr<S>*>(&p)) ) {
196             //pがさすオブジェクトをこのオブジェクトもさすことになるので、
197             //まずはdec
198             dec();
199             
200             //あとはincとほぼ同じ処理になる。
201             obj_ = p.getObj();
202             ref_obj_ = p.getRefObj();
203             index_ = p.getIndex();
204
205             if (ref_obj_ != NULL) {
206                 ref_obj_->inc_ref();
207             }
208         }
209
210         return *this;
211     }
212
213     /**
214      * @brief 指定した型の追加生成構文
215      * コンストラクタで何も指定しない場合、これを実行することで、再生成を行う。
216      */
217     void add() {
218         dec();
219         init(new T, true, 1);
220     }
221
222     /**
223        add
224        新しく生成させる。
225        関数テンプレートを使ってはいるが、必ずTとおなじ、
226        もしくはTの派生クラスであること。
227        @param S* p 対象とするオブジェクト
228        @param bool owner 所有権の有無
229        @access public
230        @return void
231     */
232     template<class S>
233     void add(S* _p, bool owner = true) {
234         dec();
235         if (_p != NULL) {
236             init(_p,owner,1);
237         }
238     }
239
240     /**
241      * @brief デリータを指定した追加生成構文。
242      * これは配列では使用できない。
243      */
244     template<class S>
245     void add(S* _p, bool owner, ref_delete_base* ref) {
246         dec();
247         if (_p != NULL && ref != NULL) {
248             init(_p, owner, 1, ref);
249         }
250     }
251
252     /**
253        addArray
254        配列オブジェクト生成関数
255        現在のオブジェクトの型を、指定個数作成する場合。
256        @param bool owner 所有権の有無
257        @param int n 個数
258        @access public
259        @return void
260     */
261     void addArray(bool owner, int n) { 
262         dec();
263         if (n > 1) {
264             init(new T[n], owner, n);
265         } else if (n == 1) {
266             init(new T, owner, 1);
267         }
268     }
269
270     /**
271        addArray
272        配列オブジェクト生成関数
273        こちらは、配列オブジェクトを生成する際に使用される関数。
274        @param S p 対象とするオブジェクト
275        @param bool owner 所有権の有無
276        @param int n 個数
277        @access public
278        @return void
279     */
280     template<class S>
281     void addArray(S _p, bool owner, int n) { 
282         dec();
283         if (n > 1) {
284             init(new S[n], owner, n);
285         }
286     }
287
288     /**
289        getIndex
290        現在のインデックスを返す
291        @access public
292        @return int 現在のインデックス
293     */
294     int getIndex() const {return index_;}
295
296     /**
297        getRefObj
298        削除オブジェクトを返す
299        @access public
300        @return ref_delete_base* 削除オブジェクトのポインタ
301     */
302     ref_delete_base* getRefObj() const {return ref_obj_;}
303     
304     /**
305        getObj
306        オブジェクトを返す
307        @access public
308        @return T* オブジェクトのポインタ
309     */
310     T* getObj() const {return obj_;}
311
312 private:
313
314     /**
315        init
316        スマートポインタの初期化補助関数
317        渡されたオブジェクトを元にして、所有権、
318        参照カウント、オブジェクトの個数を設定する。
319        @param template _p 保持するべきオブジェクト
320        @param bool owner 所有権の湯有無
321        @param int n オブジェクトの個数
322        @param ref_delete_base* ref デフォルトはNULL。外部からのコピーならば非NULL
323        @access protected
324        @return void
325     */
326     template<class S>
327     void init(S* _p, bool owner, int n, ref_delete_base* ref = NULL) {
328         
329         index_ = 0;
330         obj_ = _p;
331
332         if (ref_obj_ != NULL) {
333             //このとき、すでにdec_refとかはやってあることが前提。
334             ref_obj_ = NULL;
335         }
336
337         if (ref != NULL) {
338             ref_obj_ = ref;
339         } else if (owner) {
340             if (n == 1) {
341                 //非配列オブジェクト
342                 ref_obj_ = new ref_noarray_object<S>(_p);
343             } else if (n > 1){
344                 ref_obj_ = new ref_array_object<S>(_p);
345             }
346         } else {
347             //非所有権オブジェクト
348             ref_obj_ = new ref_null_object<S>(_p);
349         }
350
351         //オブジェクトの情報を追加
352         ref_obj_->setRef(1);
353         ref_obj_->setMaxNum(n);
354         ref_obj_->setObjSize(sizeof(S));
355         ref_obj_->setOwner(owner);
356
357     }
358
359     /**
360        inc
361        渡されたsmart_ptrの参照数を一つ増やす。
362        @param const smart_ptr<T>& p 参照カウントを増やすオブジェクト
363        @access protected
364        @return void
365     */
366     void inc(const smart_ptr<T>& p) {
367         index_    = p.getIndex();
368         ref_obj_   = p.getRefObj();
369         obj_      = p.getObj();
370         
371         if (ref_obj_ != NULL) {
372             ref_obj_->inc_ref();
373         }
374     }
375
376     /**
377        dec
378        自分の分の参照カウントを減らす。
379        実行されたら、ref_obj_およびobj_は
380        NULLになる。
381        @access protected
382        @return void
383     */
384     void dec() {
385         //dec_refは、オブジェクトを削除したかどうかを返す。
386         //削除されている場合は、参照オブジェクトを削除しなければならない。
387         if (ref_obj_ != NULL) {
388             if (ref_obj_->dec_ref()) {
389                 delete ref_obj_;
390             }
391         }
392         ref_obj_ = NULL;
393         obj_ = NULL;
394     }
395
396     /**
397        incIndex
398        インデックスカウントを増やす
399        @access protected
400        @return void
401     */
402     void incIndex() {index_++;}
403
404     /**
405        decIndex
406        インデックスカウントを減らす
407        @access protected
408        @return void
409     */
410     void decIndex() {index_--;}
411
412     //========================================
413     //コピーの際に使用するconst関数群
414     //========================================
415
416 private:
417
418     T* obj_;      //保持すべきオブジェクト。参照カウントオブジェクトと同一
419
420     ref_delete_base* ref_obj_;     //参照カウントオブジェクト
421
422     int index_;       //現在のインデックス
423
424 };
425
426 #endif