object.h revision 11986
113531Sjairo.balart@metempsy.com#if !defined(__OBJECT_H)
213531Sjairo.balart@metempsy.com#define __OBJECT_H
313531Sjairo.balart@metempsy.com
413531Sjairo.balart@metempsy.com#include <atomic>
513531Sjairo.balart@metempsy.com#include "constructor_stats.h"
613531Sjairo.balart@metempsy.com
713531Sjairo.balart@metempsy.com/// Reference counted object base class
813531Sjairo.balart@metempsy.comclass Object {
913531Sjairo.balart@metempsy.compublic:
1013531Sjairo.balart@metempsy.com    /// Default constructor
1113531Sjairo.balart@metempsy.com    Object() { print_default_created(this); }
1213531Sjairo.balart@metempsy.com
1313531Sjairo.balart@metempsy.com    /// Copy constructor
1413531Sjairo.balart@metempsy.com    Object(const Object &) : m_refCount(0) { print_copy_created(this); }
1513531Sjairo.balart@metempsy.com
1613531Sjairo.balart@metempsy.com    /// Return the current reference count
1713531Sjairo.balart@metempsy.com    int getRefCount() const { return m_refCount; };
1813531Sjairo.balart@metempsy.com
1913531Sjairo.balart@metempsy.com    /// Increase the object's reference count by one
2013531Sjairo.balart@metempsy.com    void incRef() const { ++m_refCount; }
2113531Sjairo.balart@metempsy.com
2213531Sjairo.balart@metempsy.com    /** \brief Decrease the reference count of
2313531Sjairo.balart@metempsy.com     * the object and possibly deallocate it.
2413531Sjairo.balart@metempsy.com     *
2513531Sjairo.balart@metempsy.com     * The object will automatically be deallocated once
2613531Sjairo.balart@metempsy.com     * the reference count reaches zero.
2713531Sjairo.balart@metempsy.com     */
2813531Sjairo.balart@metempsy.com    void decRef(bool dealloc = true) const {
2913531Sjairo.balart@metempsy.com        --m_refCount;
3013531Sjairo.balart@metempsy.com        if (m_refCount == 0 && dealloc)
3113531Sjairo.balart@metempsy.com            delete this;
3213531Sjairo.balart@metempsy.com        else if (m_refCount < 0)
3313531Sjairo.balart@metempsy.com            throw std::runtime_error("Internal error: reference count < 0!");
3413531Sjairo.balart@metempsy.com    }
3513531Sjairo.balart@metempsy.com
3613531Sjairo.balart@metempsy.com    virtual std::string toString() const = 0;
3713531Sjairo.balart@metempsy.comprotected:
3813531Sjairo.balart@metempsy.com    /** \brief Virtual protected deconstructor.
3913531Sjairo.balart@metempsy.com     * (Will only be called by \ref ref)
4013531Sjairo.balart@metempsy.com     */
4113531Sjairo.balart@metempsy.com    virtual ~Object() { print_destroyed(this); }
4213531Sjairo.balart@metempsy.comprivate:
4313531Sjairo.balart@metempsy.com    mutable std::atomic<int> m_refCount { 0 };
4413531Sjairo.balart@metempsy.com};
4513531Sjairo.balart@metempsy.com
4613531Sjairo.balart@metempsy.com// Tag class used to track constructions of ref objects.  When we track constructors, below, we
4713531Sjairo.balart@metempsy.com// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
4813531Sjairo.balart@metempsy.com// ref_tag.  This lets us check that the total number of ref<Anything> constructors/destructors is
4913531Sjairo.balart@metempsy.com// correct without having to check each individual ref<Whatever> type individually.
5013531Sjairo.balart@metempsy.comclass ref_tag {};
5113531Sjairo.balart@metempsy.com
5213531Sjairo.balart@metempsy.com/**
5313531Sjairo.balart@metempsy.com * \brief Reference counting helper
5413531Sjairo.balart@metempsy.com *
5513531Sjairo.balart@metempsy.com * The \a ref refeference template is a simple wrapper to store a
5613531Sjairo.balart@metempsy.com * pointer to an object. It takes care of increasing and decreasing
5713531Sjairo.balart@metempsy.com * the reference count of the object. When the last reference goes
5813531Sjairo.balart@metempsy.com * out of scope, the associated object will be deallocated.
5913531Sjairo.balart@metempsy.com *
6013531Sjairo.balart@metempsy.com * \ingroup libcore
6113531Sjairo.balart@metempsy.com */
6213531Sjairo.balart@metempsy.comtemplate <typename T> class ref {
6313531Sjairo.balart@metempsy.compublic:
6413531Sjairo.balart@metempsy.com    /// Create a nullptr reference
6513531Sjairo.balart@metempsy.com    ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
6613531Sjairo.balart@metempsy.com
6713826Sgiacomo.travaglini@arm.com    /// Construct a reference from a pointer
6813826Sgiacomo.travaglini@arm.com    ref(T *ptr) : m_ptr(ptr) {
6913826Sgiacomo.travaglini@arm.com        if (m_ptr) ((Object *) m_ptr)->incRef();
7013826Sgiacomo.travaglini@arm.com
7113826Sgiacomo.travaglini@arm.com        print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
7213826Sgiacomo.travaglini@arm.com
7313531Sjairo.balart@metempsy.com    }
7413760Sjairo.balart@metempsy.com
7513531Sjairo.balart@metempsy.com    /// Copy constructor
7613531Sjairo.balart@metempsy.com    ref(const ref &r) : m_ptr(r.m_ptr) {
7713531Sjairo.balart@metempsy.com        if (m_ptr)
7813531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->incRef();
7913531Sjairo.balart@metempsy.com
8013531Sjairo.balart@metempsy.com        print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
8113531Sjairo.balart@metempsy.com    }
8213531Sjairo.balart@metempsy.com
8313531Sjairo.balart@metempsy.com    /// Move constructor
8413531Sjairo.balart@metempsy.com    ref(ref &&r) : m_ptr(r.m_ptr) {
8513531Sjairo.balart@metempsy.com        r.m_ptr = nullptr;
8613531Sjairo.balart@metempsy.com
8713531Sjairo.balart@metempsy.com        print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
8813760Sjairo.balart@metempsy.com    }
8913531Sjairo.balart@metempsy.com
9013531Sjairo.balart@metempsy.com    /// Destroy this reference
9113531Sjairo.balart@metempsy.com    ~ref() {
9213531Sjairo.balart@metempsy.com        if (m_ptr)
9313531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->decRef();
9413531Sjairo.balart@metempsy.com
9513531Sjairo.balart@metempsy.com        print_destroyed(this); track_destroyed((ref_tag*) this);
9613531Sjairo.balart@metempsy.com    }
9713531Sjairo.balart@metempsy.com
9813531Sjairo.balart@metempsy.com    /// Move another reference into the current one
9913531Sjairo.balart@metempsy.com    ref& operator=(ref&& r) {
10013531Sjairo.balart@metempsy.com        print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
10113580Sgabeblack@google.com
10213531Sjairo.balart@metempsy.com        if (*this == r)
10313531Sjairo.balart@metempsy.com            return *this;
10413580Sgabeblack@google.com        if (m_ptr)
10513531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->decRef();
10613531Sjairo.balart@metempsy.com        m_ptr = r.m_ptr;
10713531Sjairo.balart@metempsy.com        r.m_ptr = nullptr;
10813531Sjairo.balart@metempsy.com        return *this;
10913760Sjairo.balart@metempsy.com    }
11013531Sjairo.balart@metempsy.com
11113531Sjairo.balart@metempsy.com    /// Overwrite this reference with another reference
11213531Sjairo.balart@metempsy.com    ref& operator=(const ref& r) {
11313531Sjairo.balart@metempsy.com        print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
11413531Sjairo.balart@metempsy.com
11513531Sjairo.balart@metempsy.com        if (m_ptr == r.m_ptr)
11613531Sjairo.balart@metempsy.com            return *this;
11713531Sjairo.balart@metempsy.com        if (m_ptr)
11813531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->decRef();
11913531Sjairo.balart@metempsy.com        m_ptr = r.m_ptr;
12013531Sjairo.balart@metempsy.com        if (m_ptr)
12113531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->incRef();
12213531Sjairo.balart@metempsy.com        return *this;
12313531Sjairo.balart@metempsy.com    }
12413531Sjairo.balart@metempsy.com
12513531Sjairo.balart@metempsy.com    /// Overwrite this reference with a pointer to another object
12613531Sjairo.balart@metempsy.com    ref& operator=(T *ptr) {
12713531Sjairo.balart@metempsy.com        print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
12813531Sjairo.balart@metempsy.com
12913531Sjairo.balart@metempsy.com        if (m_ptr == ptr)
13013531Sjairo.balart@metempsy.com            return *this;
13113531Sjairo.balart@metempsy.com        if (m_ptr)
13213760Sjairo.balart@metempsy.com            ((Object *) m_ptr)->decRef();
13313531Sjairo.balart@metempsy.com        m_ptr = ptr;
13413531Sjairo.balart@metempsy.com        if (m_ptr)
13513531Sjairo.balart@metempsy.com            ((Object *) m_ptr)->incRef();
13613531Sjairo.balart@metempsy.com        return *this;
13713531Sjairo.balart@metempsy.com    }
13813531Sjairo.balart@metempsy.com
13913531Sjairo.balart@metempsy.com    /// Compare this reference with another reference
14013531Sjairo.balart@metempsy.com    bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
14113531Sjairo.balart@metempsy.com
14213531Sjairo.balart@metempsy.com    /// Compare this reference with another reference
14313531Sjairo.balart@metempsy.com    bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
14413531Sjairo.balart@metempsy.com
14513531Sjairo.balart@metempsy.com    /// Compare this reference with a pointer
14613531Sjairo.balart@metempsy.com    bool operator==(const T* ptr) const { return m_ptr == ptr; }
14713531Sjairo.balart@metempsy.com
14813531Sjairo.balart@metempsy.com    /// Compare this reference with a pointer
14913531Sjairo.balart@metempsy.com    bool operator!=(const T* ptr) const { return m_ptr != ptr; }
15013531Sjairo.balart@metempsy.com
15113531Sjairo.balart@metempsy.com    /// Access the object referenced by this reference
15213531Sjairo.balart@metempsy.com    T* operator->() { return m_ptr; }
15313531Sjairo.balart@metempsy.com
15413531Sjairo.balart@metempsy.com    /// Access the object referenced by this reference
15513760Sjairo.balart@metempsy.com    const T* operator->() const { return m_ptr; }
15613531Sjairo.balart@metempsy.com
15713531Sjairo.balart@metempsy.com    /// Return a C++ reference to the referenced object
15813531Sjairo.balart@metempsy.com    T& operator*() { return *m_ptr; }
15913760Sjairo.balart@metempsy.com
16013531Sjairo.balart@metempsy.com    /// Return a const C++ reference to the referenced object
16113531Sjairo.balart@metempsy.com    const T& operator*() const { return *m_ptr; }
16213531Sjairo.balart@metempsy.com
16313531Sjairo.balart@metempsy.com    /// Return a pointer to the referenced object
16413531Sjairo.balart@metempsy.com    operator T* () { return m_ptr; }
16513760Sjairo.balart@metempsy.com
16613531Sjairo.balart@metempsy.com    /// Return a const pointer to the referenced object
16713531Sjairo.balart@metempsy.com    T* get() { return m_ptr; }
16813531Sjairo.balart@metempsy.com
16913760Sjairo.balart@metempsy.com    /// Return a pointer to the referenced object
17013531Sjairo.balart@metempsy.com    const T* get() const { return m_ptr; }
17113531Sjairo.balart@metempsy.comprivate:
17213531Sjairo.balart@metempsy.com    T *m_ptr;
17313531Sjairo.balart@metempsy.com};
17413531Sjairo.balart@metempsy.com
17513760Sjairo.balart@metempsy.com#endif /* __OBJECT_H */
17613760Sjairo.balart@metempsy.com