source: soft/giet_vm/mover/include/libelfpp/dpp/ref @ 160

Last change on this file since 160 was 160, checked in by karaoui, 12 years ago

giet-vm new version

File size: 18.5 KB
Line 
1/* -*- c++ -*-
2
3   C++ smart pointer classes
4
5   This file is part of the dpp library of C++ template classes
6
7   doc: http://diaxen.ssji.net/dpp/index.html
8   repo: https://www.ssji.net/svn/projets/trunk/libdpp
9
10   This program is free software: you can redistribute it and/or
11   modify it under the terms of the GNU Lesser General Public License
12   as published by the Free Software Foundation, either version 3 of
13   the License, or (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public
21   License along with this program.  If not, see
22   <http://www.gnu.org/licenses/>.
23
24   (c) 2008-2011 Alexandre Becoulet <alexandre.becoulet@free.fr>
25
26*/
27
28#ifndef DPP_REFS_HH_
29#define DPP_REFS_HH_
30
31#include <cassert>
32#include <cstdlib>
33#include <typeinfo>
34
35/** @file @module{Smart pointer} */
36
37// #define _DPP_USE_GCC_ATOMIC
38
39namespace dpp {
40
41  template <class X> class ref;
42  template <class X> class const_ref;
43  template <class X> class clone_ref;
44  template <class X, bool clonable> class ref_base;
45
46  /** @internal
47      @module{Smart pointer}
48  */
49  template <class X, /* object type with optional constness */
50            class Xnoconst /* bare object type */ >
51  class ref_
52  {
53    template <class, class> friend class ref_;
54    template <class> friend class ref;
55    template <class> friend class const_ref;
56    template <class> friend class clone_ref;
57
58/** @deprecated
59    Dynamically allocate and construct object of given type with passed
60    constructor arguments.
61*/
62#define DPP_REFNEW(type, ...)                   \
63    (dpp::ref<type>::create(__VA_ARGS__))
64
65  public:
66    /** @This set the internal pointer to 0. */
67    void invalidate()
68    {
69      if (_obj)
70        _drop();
71      _obj = 0;
72    }
73
74    /** @This tests if @ref ref points to a valid object. */
75    bool valid() const
76    {
77      return _obj != 0;
78    }
79
80    X & operator*() const
81    {
82      assert(_obj);
83      return *_obj;
84    }
85
86    X * operator->() const
87    {
88      assert(_obj);
89      return _obj;
90    }
91
92    /** @This returns ref internal object pointer */
93    X * ptr() const
94    {
95      return _obj;
96    }
97
98    /** @This returns object references count */
99    int count() const
100    {
101      return _obj ? _obj->_ref_count : 0;
102    }
103
104    /** @This tests if pointed objects are the same */
105    bool operator==(const ref_ &r) const
106    {
107      return _obj == r._obj;
108    }
109
110    /** @This tests if pointed objects are not the same */
111    bool operator!=(const ref_ &r) const
112    {
113      return _obj != r._obj;
114    }
115
116    /** @This tests if pointed objects are the same */
117    bool operator==(const X *p) const
118    {
119      return _obj == p;
120    }
121
122    /** @This tests if pointed objects are the same */
123    bool operator!=(const X *p) const
124    {
125      return _obj != p;
126    }
127
128    /** @This returns a @ref ref to a new dynamically allocated copy
129        of object. Object is deep copyed, new object has the same
130        derived type as source object.
131
132        While this is not need for objects dynamically allocated with
133        the @ref ref::create function, other objects have to call the
134        @ref ref_base::set_clone function from their constructor to
135        make the @ref clone function work.
136
137        The @ref clone_ref class can be used for automatic cloning on
138        smart pointer copy.
139
140        @example test/test_ref.cc:clone
141    */
142    ref<Xnoconst> clone() const
143    {
144      if (!_obj)
145        return ref<Xnoconst>();
146      return ref<Xnoconst>(_obj->template _clone<Xnoconst>());
147    }
148
149  private:
150
151    /** @internal */
152    void assign(const X &r)
153    {
154      if (_obj)
155        _drop();
156      _obj = &r;
157      if (_obj)
158        _inc();
159    }
160
161    /** @internal */
162    void assign(const ref_ &r)
163    {
164      if (_obj)
165        _drop();
166      _obj = r._obj;
167      if (_obj)
168        _inc();
169    }
170
171    /** @internal */
172    void _inc() const
173    {
174      _obj->ref_inc();
175    }
176
177    /** @internal */
178    void _drop() const
179    {
180      _obj->ref_drop();
181    }
182
183    /** @internal */
184    X *_obj;
185  };
186
187
188  /**
189      @short Smart pointer class
190      @module{Smart pointer}
191      @header dpp/ref
192      @main
193      @order 3
194
195      @This implements an object reference class, it may hold a
196      reference to objects of type @tt X which inherit from the @ref
197      ref_base class.
198
199      This class can hold references to both statically and
200      dynamically allocated objects. When the object has been
201      dynamically allocated using the @ref create function, it will be
202      destroyed when the last reference to the object is dropped.
203
204      @see {const_ref, ref_base}
205  */
206  template <class X>
207  class ref : public ref_<X, X>
208  {
209    template <class, class> friend class ref_;
210    template <class> friend class ref;
211    template <class> friend class clone_ref;
212    typedef ref_<X, X> base;
213
214    explicit ref(X * obj)
215    {
216      base::_obj = obj;
217    }
218
219  public:
220
221    /** @multiple
222        @This dynamically allocates and construct object. Parameters
223        are passed to constructor. */
224    static ref create()
225    {
226      X *obj = new X();
227      obj->template _set_clone<X>();
228      obj->_dynamic = true;
229      obj->_ref_count = 1;
230      return ref(obj);
231    }
232
233    template <typename A0>
234    static ref create(const A0 &a0)
235    {
236      X *obj = new X(a0);
237      obj->template _set_clone<X>();
238      obj->_dynamic = true;
239      obj->_ref_count = 1;
240      return ref(obj);
241    }
242
243    template <typename A0, typename A1>
244    static ref create(const A0 &a0, const A1 &a1)
245    {
246      X *obj = new X(a0, a1);
247      obj->template _set_clone<X>();
248      obj->_dynamic = true;
249      obj->_ref_count = 1;
250      return ref(obj);
251    }
252
253    template <typename A0, typename A1, typename A2>
254    static ref create(const A0 &a0, const A1 &a1, const A2 &a2)
255    {
256      X *obj = new X(a0, a1, a2);
257      obj->template _set_clone<X>();
258      obj->_dynamic = true;
259      obj->_ref_count = 1;
260      return ref(obj);
261    }
262
263    template <typename A0, typename A1, typename A2,
264              typename A3>
265    static ref create(const A0 &a0, const A1 &a1, const A2 &a2,
266                      const A3 &a3)
267    {
268      X *obj = new X(a0, a1, a2, a3);
269      obj->template _set_clone<X>();
270      obj->_dynamic = true;
271      obj->_ref_count = 1;
272      return ref(obj);
273    }
274
275    template <typename A0, typename A1, typename A2,
276              typename A3, typename A4>
277    static ref create(const A0 &a0, const A1 &a1, const A2 &a2,
278                      const A3 &a3, const A4 &a4)
279    {
280      X *obj = new X(a0, a1, a2, a3, a4);
281      obj->template _set_clone<X>();
282      obj->_dynamic = true;
283      obj->_ref_count = 1;
284      return ref(obj);
285    }
286
287    template <typename A0, typename A1, typename A2,
288              typename A3, typename A4, typename A5>
289    static ref create(const A0 &a0, const A1 &a1, const A2 &a2,
290                      const A3 &a3, const A4 &a4, const A5 &a5)
291    {
292      X *obj = new X(a0, a1, a2, a3, a4, a5);
293      obj->template _set_clone<X>();
294      obj->_dynamic = true;
295      obj->_ref_count = 1;
296      return ref(obj);
297    }
298
299    /** @This performs a dynamic cast to @ref ref of given type */
300    template <class T>
301    ref<T> dynamiccast() const
302    {
303      T *r = dynamic_cast<T*>(base::_obj);
304      if (r)
305        base::_inc();
306      return ref<T>(r);
307    }
308
309    /** @This performs a static cast to @ref ref of given type */
310    template <class T>
311    ref<T> staticcast() const
312    {
313      if (base::_obj)
314        base::_inc();
315      return ref<T>(static_cast<T*>(base::_obj));
316    }
317
318    /** Construct an empty ref */
319    ref()
320    {
321      base::_obj = 0;
322    }
323
324    /** Construct ref from ref */
325    ref(const ref &r)
326    {
327      if ((base::_obj = r._obj))
328        base::_inc();
329    }
330
331    /** Construct ref from derived class ref */
332    template <class T>
333    ref(const ref_<T, T> &r)
334    {
335      if ((base::_obj = r._obj))
336        base::_inc();
337    }
338
339    /** Construct ref from object reference */
340    ref(X &obj)
341    {
342      base::_obj = &obj;
343      base::_inc();
344    }
345
346    /** Drop a ref */
347    ~ref()
348    {
349      if (base::_obj)
350        base::_drop();
351    }
352
353    /** Initialize ref from ref */
354    ref & operator=(const ref &r)
355    {
356      base::assign(r);
357      return *this;
358    }
359
360    /** Initialize ref from object reference */
361    ref & operator=(X & obj)
362    {
363      base::assign(obj);
364      return *this;
365    }
366
367  };
368
369  /**
370      @short Const smart pointer class
371      @module{Smart pointer}
372      @header dpp/ref
373      @main
374      @order 2
375
376      @This class is the same as the @ref ref class but hold a @b
377      const pointer to the object.
378
379      @see {ref, ref_base}
380  */
381  template <class X>
382  class const_ref : public ref_<const X, X>
383  {
384    template <class, class> friend class ref_;
385    typedef ref_<const X, X> base;
386
387    explicit const_ref(const X * obj)
388    {
389      base::_obj = obj;
390    }
391
392  public:
393
394    /** Construct an empty ref */
395    const_ref()
396    {
397      base::_obj = 0;
398    }
399
400    /** Construct const ref from const ref */
401    const_ref(const const_ref &r)
402    {
403      if ((base::_obj = r._obj))
404        base::_inc();
405    }
406
407    /** Construct const ref from derived class ref */
408    template <class T>
409    const_ref(const ref_<T, T> &r)
410    {
411      if ((base::_obj = r._obj))
412        base::_inc();
413    }
414
415    /** Construct const ref from derived class const ref */
416    template <class T>
417    const_ref(const ref_<const T, T> &r)
418    {
419      if ((base::_obj = r._obj))
420        base::_inc();
421    }
422
423    /** Construct ref from const object reference */
424    const_ref(const X &obj)
425    {
426      base::_obj = &obj;
427      base::_inc();
428    }
429
430    /** Drop a ref */
431    ~const_ref()
432    {
433      if (base::_obj)
434        base::_drop();
435    }
436
437    /** @This performs a dynamic cast to @ref const_ref of given type */
438    template <class T>
439    const_ref<T> dynamiccast() const
440    {
441      const T *r = dynamic_cast<const T*>(base::_obj);
442      if (r)
443        base::_inc();
444      return const_ref<T>(r);
445    }
446
447    /** @This performs a static cast to @ref const_ref of given type */
448    template <class T>
449    const_ref<T> staticcast() const
450    {
451      if (base::_obj)
452        base::_inc();
453      return const_ref<T>(static_cast<const T*>(base::_obj));
454    }
455
456    /** Initialize const ref from const ref */
457    const_ref & operator=(const const_ref &r)
458    {
459      base::assign(r);
460      return *this;
461    }
462
463    /** Initialize ref from object reference */
464    const_ref & operator=(const X & obj)
465    {
466      base::assign(obj);
467      return *this;
468    }
469
470  };
471
472  /**
473      @short Automatic cloning smart pointer class
474      @module{Smart pointer}
475      @header dpp/ref
476      @main
477      @order 1
478
479      @This implements a special kind of smart pointer which clones the
480      pointed object when copied. It is intended to be used for class
481      members when the expected behavior is to clone the pointed
482      object along with the reference holder object.
483
484      The copy constructor and copy assignment operator will clone the
485      associated object instead of just copying the
486      pointer. Constructors and assignment operators which take other
487      kind of references don't perform clone.
488
489      @example test/test_ref.cc:clone1
490
491      @see {ref, ref_base}
492  */
493  template <class X>
494  class clone_ref : public ref_<X, X>
495  {
496    template <class, class> friend class ref_;
497    typedef ref_<X, X> base;
498
499  public:
500
501    /** Construct an empty ref */
502    clone_ref()
503    {
504      base::_obj = 0;
505    }
506
507    /** Construct ref from derived class ref */
508    template <class T>
509    clone_ref(const ref_<T, T> &r)
510    {
511      base::_obj = r._obj;
512      if (base::_obj)
513        base::_inc();
514    }
515
516    /** Construct clone_ref and clone pointed object */
517    clone_ref(const clone_ref &r)
518    {
519      base::_obj = r._obj ? r._obj->template _clone<X>() : 0;
520    }
521
522    /** Construct clone_ref and clone pointed object */
523    template <class T>
524    clone_ref(const clone_ref &r)
525    {
526      base::_obj = r._obj ? r._obj->template _clone<X>() : 0;
527    }
528
529    /** Construct clone_ref from object reference */
530    clone_ref(X &obj)
531    {
532      base::_obj = &obj;
533      base::_inc();
534    }
535
536    /** Drop a clone_ref */
537    ~clone_ref()
538    {
539      if (base::_obj)
540        base::_drop();
541    }
542
543    /** @This performs a dynamic cast to @ref ref of given type */
544    template <class T>
545    ref<T> dynamiccast() const
546    {
547      T *r = dynamic_cast<T*>(base::_obj);
548      if (r)
549        base::_inc();
550      return ref<T>(r);
551    }
552
553    /** @This performs a static cast to @ref ref of given type */
554    template <class T>
555    ref<T> staticcast() const
556    {
557      if (base::_obj)
558        base::_inc();
559      return ref<T>(static_cast<T*>(base::_obj));
560    }
561
562    /** Initialize clone_ref by cloning object */
563    clone_ref & operator=(const clone_ref &r)
564    {
565      if (base::_obj)
566        base::_drop();
567      base::_obj = r._obj ? r._obj->_clone() : 0;
568      return *this;
569    }
570
571    /** Initialize ref from ref */
572    clone_ref & operator=(const ref<X> &r)
573    {
574      base::assign(r);
575      return *this;
576    }
577
578    /** Initialize ref from object reference */
579    clone_ref & operator=(X & obj)
580    {
581      base::assign(obj);
582      return *this;
583    }
584
585  };
586
587  /** @internal
588      @module{Smart pointer}
589  */
590  template <class X, bool cloneable>
591  class ref_base_
592  {
593    template <class> friend class ref;
594
595    template <class D>
596    void _set_clone()
597    {
598      /* not cloneable, no clone callback registered here */
599    }
600  };
601
602  /** @internal
603      @module{Smart pointer}
604      This class contains cloning code.
605  */
606  template <class X>
607  class ref_base_ <X, true>
608  {
609    template <class, class> friend class ref_;
610    template <class> friend class ref;
611    template <class> friend class clone_ref;
612    template <class, bool> friend class ref_base;
613
614    ref_base_()
615      : _ref_clone(0)
616    {
617    }
618
619    /** Clone object pointed by ref */
620    template <class D>
621    D * _clone() const
622    {
623      assert(_ref_clone || !"no clone handler defined for this object");
624      return static_cast<D*>(_ref_clone(static_cast<const D*>(this)));
625    }
626
627    template <class D /* derived class */>
628    static X * _clone_hndl(const X *x)
629    {
630      assert(typeid(D) == typeid(*x) && "clone handler does not match actual object type");
631      const D * src = static_cast<const D*>(x);
632      D * obj = new D(*src);
633      obj->_ref_clone = src->_ref_clone;
634      obj->_dynamic = true;
635      obj->_ref_count = 1;
636      obj->cloned(*src);
637      return obj;
638    }
639
640    /** set specialized clone callback */
641    template <class D>
642    void _set_clone()
643    {
644      _ref_clone = &_clone_hndl<D>;
645    }
646
647    /** pointer to clone function specialized for _derived_ class */
648    X * (*_ref_clone)(const X *);
649  };
650
651  /**
652      @short Reference counting object base class
653      @module{Smart pointer}
654      @header dpp/ref
655      @showvalue
656
657      @This is the referenced object base class, any class which
658      inherits from this class can be pointed to by a @ref ref smart
659      pointer.
660
661      @tt X template parameter must be the same as inheriting class.
662
663      The @tt cloneable parameter must be set to true in order to use
664      the @ref ref::clone method. The default value is @tt false to
665      support classes with no copy constructor and optimize pointer size.
666
667      When the DPP_REF_LIVE_REFS_ASSERT macro is defined, the base
668      class destructor assert that no more live reference to the
669      object does exist.
670  */
671  template <class X, bool cloneable = false>
672  class ref_base : public ref_base_<X, cloneable>
673  {
674    template <class, class> friend class ref_;
675    template <class> friend class ref;
676    template <class> friend class const_ref;
677    template <class, bool> friend class ref_base_;
678
679  public:
680
681    ref_base()
682      : _ref_count(0),
683        _dynamic(0)
684    {
685    }
686
687    ref_base(const ref_base &r)
688      : _ref_count(0),
689        _dynamic(0)
690    {
691    }
692
693    ref_base & operator=(const ref_base &r)
694    {
695      return *this;
696    }
697
698    virtual ~ref_base()
699    {
700#ifdef DPP_REF_LIVE_REFS_ASSERT
701      assert(_ref_count == 0 || !"Can not destruct object which has live references");
702#endif
703    }
704
705    /** Setup a clone handler for this object. This function may be
706        called from derived class constructor to make objects
707        cloneable. Objects which are dynamically allocated using the
708        @ref ref::create function do not require this call. */
709    template <class Derived>
710    void set_clone()
711    {
712      ref_base_<X, cloneable>::template _set_clone<Derived>();
713    }
714
715    /** @This is called when this object has just been cloned. The
716        call is performed on most derived class (see @ref set_clone
717        function). This default implementation is empty. */
718    void cloned(const X &src)
719    {
720    }
721
722    /** @This is called when the reference counter has just been
723        increased. The call is performed on reference to @tt X class so
724        a virtual prototype must be declared in the @tt X class to
725        override this function from further derived classes.
726        This default implementation is empty.
727        @see ref_decreased @see ref_inc
728    */
729    void ref_increased(int ref_count) const
730    {
731    }
732
733    /** Same as @ref ref_increased but called when the counter has
734        been decreased. This default implementation is empty.
735        @see ref_dec
736    */
737    void ref_decreased(int ref_count) const
738    {
739    }
740
741    /** @This increases references count on object. It should only be
742        used on rare cases when smart pointer classes can not be used
743        to track all references to the object. @see ref_drop */
744    void ref_inc() const
745    {
746#ifdef _DPP_USE_GCC_ATOMIC
747# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
748      __sync_add_and_fetch(&const_cast<ref_base*>(this)->_raw, 1);
749# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
750      __sync_add_and_fetch(&const_cast<ref_base*>(this)->_raw, 2);
751# else
752#  error __BYTE_ORDER__ not defined
753# endif
754#else
755      const_cast<ref_base*>(this)->_ref_count++;
756#endif
757
758      static_cast<const X*>(this)->ref_increased(_ref_count);
759    }
760
761    /** @This decreases references count on object. Dynamically
762        allocated objects are deleted if counter reaches 0. It should
763        only be used on rare cases when smart pointer classes can not
764        be used to track all references to the object. @see ref_inc */
765    void ref_drop() const
766    {
767      assert(_ref_count > 0);
768
769#ifdef _DPP_USE_GCC_ATOMIC
770# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
771      __sync_sub_and_fetch(&const_cast<ref_base*>(this)->_raw, 1);
772# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
773      __sync_sub_and_fetch(&const_cast<ref_base*>(this)->_raw, 2);
774# endif
775#else
776      const_cast<ref_base*>(this)->_ref_count--;
777#endif
778
779      static_cast<const X*>(this)->ref_decreased(_ref_count);
780
781      // free dynamically allocated objects only
782      if (_dynamic && _ref_count == 0)
783        delete this;
784    }
785
786  private:
787
788    /** reference counter value */
789    union {
790      struct {
791        int _ref_count:31;
792        int _dynamic:1;
793      };
794      int _raw;
795    };
796  };
797
798}
799
800#endif
801
Note: See TracBrowser for help on using the repository browser.