countedptr.hpp

Back to Reference-counted pointers

pastel/sys/pointer/countedptr/

#ifndef PASTELSYS_COUNTEDPTR_HPP
#define PASTELSYS_COUNTEDPTR_HPP

#include "pastel/sys/pointer/countedptr.h"

#include "pastel/sys/ensure.h"

#include <type_traits>

namespace Pastel
{

    template <typename Type>
    CountedPtr<Type>::CountedPtr()
        : data_(0)
    {
    }

    template <typename Type>
    CountedPtr<Type>::CountedPtr(const CountedPtr<Type>& that)
        : data_(that.data_)
    {
        if (data_)
        {
            increaseCount();
        }
    }

    template <typename Type>
    template <typename ThatType>
    CountedPtr<Type>::CountedPtr(const WeakPtr<ThatType>& that)
        : data_(that.get())
    {
        if (data_)
        {
            increaseCount();
        }
    }

    template <typename Type>
    template <typename ThatType>
    CountedPtr<Type>::CountedPtr(
        const CountedPtr<ThatType>& that)
        : data_(that.data_)
    {
        if (data_)
        {
            increaseCount();
        }
    }

    template <typename Type>
    CountedPtr<Type>::CountedPtr(Type* that)
        : data_(that)
    {
        if (data_)
        {
            increaseCount();
        }
    }

    template <typename Type>
    CountedPtr<Type>& CountedPtr<Type>::operator=(
        const CountedPtr<Type>& that)
    {
        CountedPtr<Type> copy(that);
        swap(copy);
        return *this;
    }

    template <typename Type>
    template <typename ThatType>
    CountedPtr<Type>& CountedPtr<Type>::operator=(
        const CountedPtr<ThatType>& that)
    {
        CountedPtr<Type> copy(that);
        swap(copy);
        return *this;
    }

    template <typename Type>
    CountedPtr<Type>& CountedPtr<Type>::operator=(Type* that)
    {
        CountedPtr<Type> copy(that);
        swap(copy);
        return *this;
    }

    template <typename Type>
    template <typename ThatType>
    bool CountedPtr<Type>::operator==(
        const CountedPtr<ThatType>& that) const
    {
        return data_ == that.data_;
    }

    template <typename Type>
    template <typename ThatType>
    bool CountedPtr<Type>::operator<(
        const CountedPtr<ThatType>& that) const
    {
        return data_ < that.data_;
    }

    template <typename Type>
    CountedPtr<Type>::~CountedPtr()
    {
        clear();
    }

    template <typename Type>
    Type* CountedPtr<Type>::get() const
    {
        return data_;
    }

    template <typename Type>
    Type* CountedPtr<Type>::operator->() const
    {
        PENSURE(!empty());

        return data_;
    }

    template <typename Type>
    Type& CountedPtr<Type>::operator*() const
    {
        PENSURE(!empty());

        return *data_;
    }

    template <typename Type>
    void CountedPtr<Type>::swap(CountedPtr<Type>& that)
    {
        std::swap(data_, that.data_);
    }

    template <typename Type>
    void CountedPtr<Type>::clear()
    {
        if (data_)
        {
            //#pragma omp critical (CountedPtr_ReadWrite)
            {
            // Decrease the reference count.

            decreaseCount();

            // If the reference count reaches zero,
            // free the object.

            if (count() == 0)
            {
                delete data_;
            }

            data_ = 0;
            }
        }
    }

    template <typename Type>
    integer CountedPtr<Type>::count() const
    {
        static constexpr bool IsBase =
            std::is_base_of<ReferenceCounted, Type>::value;

        PASTEL_STATIC_ASSERT(IsBase);

        if (!data_)
        {
            return 0;
        }

        const ReferenceCounted* counter =
            (const ReferenceCounted*)data_;
        integer result = 0;
#pragma omp critical (CountedPtr_ReadWrite)
        {
            result = counter->count_;
        }
        return result;
    }

    template <typename Type>
    bool CountedPtr<Type>::empty() const
    {
        return (data_ == 0);
    }

    // Private

    template <typename Type>
    void CountedPtr<Type>::increaseCount() const
    {
        static constexpr bool IsBase =
            std::is_base_of<ReferenceCounted, Type>::value;

        PASTEL_STATIC_ASSERT(IsBase);

        PENSURE(data_);

        const ReferenceCounted* counter =
            (const ReferenceCounted*)data_;

#pragma omp critical (CountedPtr_ReadWrite)
        {
            ++(counter->count_);
        }
    }

    template <typename Type>
    void CountedPtr<Type>::decreaseCount() const
    {
        static constexpr bool IsBase =
            std::is_base_of<ReferenceCounted, Type>::value;

        PASTEL_STATIC_ASSERT(IsBase);

        PENSURE(data_);
        ENSURE_OP(count(), >, 0);

        const ReferenceCounted* counter =
            (const ReferenceCounted*)data_;

#pragma omp critical (CountedPtr_ReadWrite)
        {
            --(counter->count_);
        }
    }

    template <typename Type>
    void swap(CountedPtr<Type>& left,
        CountedPtr<Type>& right)
    {
        left.swap(right);
    }

}

#endif