111986Sandreas.sandberg@arm.com#if !defined(__OBJECT_H)
211986Sandreas.sandberg@arm.com#define __OBJECT_H
311986Sandreas.sandberg@arm.com
411986Sandreas.sandberg@arm.com#include <atomic>
511986Sandreas.sandberg@arm.com#include "constructor_stats.h"
611986Sandreas.sandberg@arm.com
711986Sandreas.sandberg@arm.com/// Reference counted object base class
811986Sandreas.sandberg@arm.comclass Object {
911986Sandreas.sandberg@arm.compublic:
1011986Sandreas.sandberg@arm.com    /// Default constructor
1111986Sandreas.sandberg@arm.com    Object() { print_default_created(this); }
1211986Sandreas.sandberg@arm.com
1311986Sandreas.sandberg@arm.com    /// Copy constructor
1411986Sandreas.sandberg@arm.com    Object(const Object &) : m_refCount(0) { print_copy_created(this); }
1511986Sandreas.sandberg@arm.com
1611986Sandreas.sandberg@arm.com    /// Return the current reference count
1711986Sandreas.sandberg@arm.com    int getRefCount() const { return m_refCount; };
1811986Sandreas.sandberg@arm.com
1911986Sandreas.sandberg@arm.com    /// Increase the object's reference count by one
2011986Sandreas.sandberg@arm.com    void incRef() const { ++m_refCount; }
2111986Sandreas.sandberg@arm.com
2211986Sandreas.sandberg@arm.com    /** \brief Decrease the reference count of
2311986Sandreas.sandberg@arm.com     * the object and possibly deallocate it.
2411986Sandreas.sandberg@arm.com     *
2511986Sandreas.sandberg@arm.com     * The object will automatically be deallocated once
2611986Sandreas.sandberg@arm.com     * the reference count reaches zero.
2711986Sandreas.sandberg@arm.com     */
2811986Sandreas.sandberg@arm.com    void decRef(bool dealloc = true) const {
2911986Sandreas.sandberg@arm.com        --m_refCount;
3011986Sandreas.sandberg@arm.com        if (m_refCount == 0 && dealloc)
3111986Sandreas.sandberg@arm.com            delete this;
3211986Sandreas.sandberg@arm.com        else if (m_refCount < 0)
3311986Sandreas.sandberg@arm.com            throw std::runtime_error("Internal error: reference count < 0!");
3411986Sandreas.sandberg@arm.com    }
3511986Sandreas.sandberg@arm.com
3611986Sandreas.sandberg@arm.com    virtual std::string toString() const = 0;
3711986Sandreas.sandberg@arm.comprotected:
3811986Sandreas.sandberg@arm.com    /** \brief Virtual protected deconstructor.
3911986Sandreas.sandberg@arm.com     * (Will only be called by \ref ref)
4011986Sandreas.sandberg@arm.com     */
4111986Sandreas.sandberg@arm.com    virtual ~Object() { print_destroyed(this); }
4211986Sandreas.sandberg@arm.comprivate:
4311986Sandreas.sandberg@arm.com    mutable std::atomic<int> m_refCount { 0 };
4411986Sandreas.sandberg@arm.com};
4511986Sandreas.sandberg@arm.com
4611986Sandreas.sandberg@arm.com// Tag class used to track constructions of ref objects.  When we track constructors, below, we
4711986Sandreas.sandberg@arm.com// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
4811986Sandreas.sandberg@arm.com// ref_tag.  This lets us check that the total number of ref<Anything> constructors/destructors is
4911986Sandreas.sandberg@arm.com// correct without having to check each individual ref<Whatever> type individually.
5011986Sandreas.sandberg@arm.comclass ref_tag {};
5111986Sandreas.sandberg@arm.com
5211986Sandreas.sandberg@arm.com/**
5311986Sandreas.sandberg@arm.com * \brief Reference counting helper
5411986Sandreas.sandberg@arm.com *
5511986Sandreas.sandberg@arm.com * The \a ref refeference template is a simple wrapper to store a
5611986Sandreas.sandberg@arm.com * pointer to an object. It takes care of increasing and decreasing
5711986Sandreas.sandberg@arm.com * the reference count of the object. When the last reference goes
5811986Sandreas.sandberg@arm.com * out of scope, the associated object will be deallocated.
5911986Sandreas.sandberg@arm.com *
6011986Sandreas.sandberg@arm.com * \ingroup libcore
6111986Sandreas.sandberg@arm.com */
6211986Sandreas.sandberg@arm.comtemplate <typename T> class ref {
6311986Sandreas.sandberg@arm.compublic:
6411986Sandreas.sandberg@arm.com    /// Create a nullptr reference
6511986Sandreas.sandberg@arm.com    ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
6611986Sandreas.sandberg@arm.com
6711986Sandreas.sandberg@arm.com    /// Construct a reference from a pointer
6811986Sandreas.sandberg@arm.com    ref(T *ptr) : m_ptr(ptr) {
6911986Sandreas.sandberg@arm.com        if (m_ptr) ((Object *) m_ptr)->incRef();
7011986Sandreas.sandberg@arm.com
7111986Sandreas.sandberg@arm.com        print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
7211986Sandreas.sandberg@arm.com
7311986Sandreas.sandberg@arm.com    }
7411986Sandreas.sandberg@arm.com
7511986Sandreas.sandberg@arm.com    /// Copy constructor
7611986Sandreas.sandberg@arm.com    ref(const ref &r) : m_ptr(r.m_ptr) {
7711986Sandreas.sandberg@arm.com        if (m_ptr)
7811986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->incRef();
7911986Sandreas.sandberg@arm.com
8011986Sandreas.sandberg@arm.com        print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
8111986Sandreas.sandberg@arm.com    }
8211986Sandreas.sandberg@arm.com
8311986Sandreas.sandberg@arm.com    /// Move constructor
8411986Sandreas.sandberg@arm.com    ref(ref &&r) : m_ptr(r.m_ptr) {
8511986Sandreas.sandberg@arm.com        r.m_ptr = nullptr;
8611986Sandreas.sandberg@arm.com
8711986Sandreas.sandberg@arm.com        print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
8811986Sandreas.sandberg@arm.com    }
8911986Sandreas.sandberg@arm.com
9011986Sandreas.sandberg@arm.com    /// Destroy this reference
9111986Sandreas.sandberg@arm.com    ~ref() {
9211986Sandreas.sandberg@arm.com        if (m_ptr)
9311986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->decRef();
9411986Sandreas.sandberg@arm.com
9511986Sandreas.sandberg@arm.com        print_destroyed(this); track_destroyed((ref_tag*) this);
9611986Sandreas.sandberg@arm.com    }
9711986Sandreas.sandberg@arm.com
9811986Sandreas.sandberg@arm.com    /// Move another reference into the current one
9911986Sandreas.sandberg@arm.com    ref& operator=(ref&& r) {
10011986Sandreas.sandberg@arm.com        print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
10111986Sandreas.sandberg@arm.com
10211986Sandreas.sandberg@arm.com        if (*this == r)
10311986Sandreas.sandberg@arm.com            return *this;
10411986Sandreas.sandberg@arm.com        if (m_ptr)
10511986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->decRef();
10611986Sandreas.sandberg@arm.com        m_ptr = r.m_ptr;
10711986Sandreas.sandberg@arm.com        r.m_ptr = nullptr;
10811986Sandreas.sandberg@arm.com        return *this;
10911986Sandreas.sandberg@arm.com    }
11011986Sandreas.sandberg@arm.com
11111986Sandreas.sandberg@arm.com    /// Overwrite this reference with another reference
11211986Sandreas.sandberg@arm.com    ref& operator=(const ref& r) {
11311986Sandreas.sandberg@arm.com        print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
11411986Sandreas.sandberg@arm.com
11511986Sandreas.sandberg@arm.com        if (m_ptr == r.m_ptr)
11611986Sandreas.sandberg@arm.com            return *this;
11711986Sandreas.sandberg@arm.com        if (m_ptr)
11811986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->decRef();
11911986Sandreas.sandberg@arm.com        m_ptr = r.m_ptr;
12011986Sandreas.sandberg@arm.com        if (m_ptr)
12111986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->incRef();
12211986Sandreas.sandberg@arm.com        return *this;
12311986Sandreas.sandberg@arm.com    }
12411986Sandreas.sandberg@arm.com
12511986Sandreas.sandberg@arm.com    /// Overwrite this reference with a pointer to another object
12611986Sandreas.sandberg@arm.com    ref& operator=(T *ptr) {
12711986Sandreas.sandberg@arm.com        print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
12811986Sandreas.sandberg@arm.com
12911986Sandreas.sandberg@arm.com        if (m_ptr == ptr)
13011986Sandreas.sandberg@arm.com            return *this;
13111986Sandreas.sandberg@arm.com        if (m_ptr)
13211986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->decRef();
13311986Sandreas.sandberg@arm.com        m_ptr = ptr;
13411986Sandreas.sandberg@arm.com        if (m_ptr)
13511986Sandreas.sandberg@arm.com            ((Object *) m_ptr)->incRef();
13611986Sandreas.sandberg@arm.com        return *this;
13711986Sandreas.sandberg@arm.com    }
13811986Sandreas.sandberg@arm.com
13911986Sandreas.sandberg@arm.com    /// Compare this reference with another reference
14011986Sandreas.sandberg@arm.com    bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
14111986Sandreas.sandberg@arm.com
14211986Sandreas.sandberg@arm.com    /// Compare this reference with another reference
14311986Sandreas.sandberg@arm.com    bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
14411986Sandreas.sandberg@arm.com
14511986Sandreas.sandberg@arm.com    /// Compare this reference with a pointer
14611986Sandreas.sandberg@arm.com    bool operator==(const T* ptr) const { return m_ptr == ptr; }
14711986Sandreas.sandberg@arm.com
14811986Sandreas.sandberg@arm.com    /// Compare this reference with a pointer
14911986Sandreas.sandberg@arm.com    bool operator!=(const T* ptr) const { return m_ptr != ptr; }
15011986Sandreas.sandberg@arm.com
15111986Sandreas.sandberg@arm.com    /// Access the object referenced by this reference
15211986Sandreas.sandberg@arm.com    T* operator->() { return m_ptr; }
15311986Sandreas.sandberg@arm.com
15411986Sandreas.sandberg@arm.com    /// Access the object referenced by this reference
15511986Sandreas.sandberg@arm.com    const T* operator->() const { return m_ptr; }
15611986Sandreas.sandberg@arm.com
15711986Sandreas.sandberg@arm.com    /// Return a C++ reference to the referenced object
15811986Sandreas.sandberg@arm.com    T& operator*() { return *m_ptr; }
15911986Sandreas.sandberg@arm.com
16011986Sandreas.sandberg@arm.com    /// Return a const C++ reference to the referenced object
16111986Sandreas.sandberg@arm.com    const T& operator*() const { return *m_ptr; }
16211986Sandreas.sandberg@arm.com
16311986Sandreas.sandberg@arm.com    /// Return a pointer to the referenced object
16411986Sandreas.sandberg@arm.com    operator T* () { return m_ptr; }
16511986Sandreas.sandberg@arm.com
16611986Sandreas.sandberg@arm.com    /// Return a const pointer to the referenced object
16712037Sandreas.sandberg@arm.com    T* get_ptr() { return m_ptr; }
16811986Sandreas.sandberg@arm.com
16911986Sandreas.sandberg@arm.com    /// Return a pointer to the referenced object
17012037Sandreas.sandberg@arm.com    const T* get_ptr() const { return m_ptr; }
17111986Sandreas.sandberg@arm.comprivate:
17211986Sandreas.sandberg@arm.com    T *m_ptr;
17311986Sandreas.sandberg@arm.com};
17411986Sandreas.sandberg@arm.com
17511986Sandreas.sandberg@arm.com#endif /* __OBJECT_H */
176