
#ifndef TB_MEMORY_H
#define TB_MEMORY_H

#include "tb_core.h"

namespace tb {

/** TBUniquePointer is a smart pointer with unique object ownership. */
template<class T>
class TBUniquePointer
{
public:
	TBUniquePointer() : m_p(nullptr) {}
	TBUniquePointer(decltype(nullptr)) : m_p(nullptr) {}
	explicit TBUniquePointer(T *p) : m_p(p) {}

	TBUniquePointer(const TBUniquePointer &) = delete;
	TBUniquePointer &operator=(const TBUniquePointer &) = delete;

	TBUniquePointer(TBUniquePointer &&rhs) : m_p(rhs.m_p) { rhs.m_p = nullptr; }

	TBUniquePointer &operator=(TBUniquePointer &&rhs)
	{
		if (this != &rhs)
		{
			Set(rhs.m_p);
			rhs.m_p = nullptr;
		}

		return *this;
	}

	TBUniquePointer &operator=(decltype(nullptr))
	{
		Reset();
		return *this;
	}

	~TBUniquePointer()
	{
		Reset();
	}

	void Reset()
	{
		if (m_p)
		{
			delete m_p;
			m_p = nullptr;
		}
	}

	T *Release()
	{
		T *p = m_p;
		m_p = nullptr;
		return p;
	}

	void Set(T *p)
	{
		Reset();
		m_p = p;
	}

	void Set(decltype(nullptr))    { Reset(); }

	explicit operator bool() const { return !!m_p; }
	T *Get()                       { return m_p; }
	const T *Get() const           { return m_p; }
	T &operator*()                 { return *m_p; }
	const T &operator*() const     { return *m_p; }
	T *operator->()                { return m_p; }
	const T *operator->() const    { return m_p; }

private:
	T *m_p;
};

template<class T>
struct RemoveReference { using Type = T; };

template<class T>
struct RemoveReference<T&> { using Type = T; };

template<class T>
struct RemoveReference<T&&> { using Type = T; };

template<class T>
typename RemoveReference<T>::Type&& TBMove(T&& x) { return static_cast<typename RemoveReference<T>::Type&&>(x); }

} // namespace tb

#endif // !TB_MEMORY_H
