// -*- Mode: c++ -*-

#ifndef MYTHREFCOUNT_H_
#define MYTHREFCOUNT_H_

// Uncomment this line for more useful reference counting debugging
//#define EXTRA_DEBUG
// Uncomment the DEBUG define lines in referencecounter.cpp for
// even more debugging.

#include <QAtomicInt>

#ifdef EXTRA_DEBUG
#include <QString>
#else
class QString;
#endif

#include "mythbaseexp.h"

/** \brief General purpose reference counter.
 *
 *  This class uses QAtomicInt for lockless reference counting.
 *
 */
class MBASE_PUBLIC ReferenceCounter
{
  public:
    /// Creates reference counter with an initial value of 1.
    explicit ReferenceCounter(const QString &debugName, bool logDebug = true);

    /// Increments reference count.
    /// \return last reference count
    virtual int IncrRef(void);

    /// Decrements reference count and deletes on 0.
    /// \return last reference count, 0 if deleted
    virtual int DecrRef(void);

    /// Print out any leaks if that level of debugging is enabled.
    static void PrintDebug(void);
  protected:
    /// Called on destruction, will warn if object deleted with
    /// references in place. Set breakpoint here for debugging.
    virtual ~ReferenceCounter(void);

  protected:
#ifdef EXTRA_DEBUG
    const QString m_debugName;
#endif
    /// This is used to suppress creating LoggingItem classes for
    /// LoggingItem reference count changes. This is necessary to
    /// prevent infinte recursion. If you need to debug LoggingItem
    /// reference counting you need to print the messages to the
    /// console by modifying IncrRef() and DecrRef().
    bool m_logDebug;
    QAtomicInt m_referenceCount {1};
};

/** \brief This decrements the reference on destruction.
 *
 *  This can be used to ensure a reference to an object is decrimented
 *  at the end of the scope containing ReferenceLocker.
 *
 */
class MBASE_PUBLIC ReferenceLocker
{
  public:
    explicit ReferenceLocker(ReferenceCounter *counter) : m_counter(counter) { }
    ~ReferenceLocker()
    {
        if (m_counter)
            m_counter->DecrRef();
    }
  private:
    ReferenceCounter *m_counter {nullptr};
};

#endif
