geode/loader/include/Geode/utils/Ref.hpp

133 lines
3.4 KiB
C++
Raw Normal View History

#pragma once
#include <cocos2d.h>
namespace geode {
/**
2022-10-30 14:59:20 -04:00
* A smart pointer to a managed CCObject-deriving class. Retains shared
* ownership over the managed instance. Releases the object when the Ref
* is destroyed, or assigned another object or nullptr.
2022-10-30 14:59:20 -04:00
*
* Use-cases include, for example, non-CCNode class members, or nodes that
* are not always in the scene tree.
2022-10-30 14:59:20 -04:00
*
* @example class MyNode : public CCNode {
* protected:
2022-10-30 14:59:20 -04:00
* // no need to manually call retain or
* // release on this array; Ref manages it
* // for you :3
* Ref<CCArray> m_list = CCArray::create();
* };
*/
2022-10-30 14:59:20 -04:00
template <class T>
class Ref final {
static_assert(
std::is_base_of_v<cocos2d::CCObject, T>,
"Ref can only be used with a CCObject-inheriting class!"
);
T* m_obj = nullptr;
public:
/**
2022-10-30 14:59:20 -04:00
* Construct a Ref of an object. The object will be retained and
* managed until Ref goes out of scope
*/
Ref(T* obj) : m_obj(obj) {
CC_SAFE_RETAIN(obj);
}
2022-10-30 14:59:20 -04:00
Ref(Ref<T> const& other) : Ref(other.data()) {}
2022-10-30 14:59:20 -04:00
Ref(Ref<T>&& other) : m_obj(other.m_obj) {
other.m_obj = nullptr;
}
2022-10-30 14:59:20 -04:00
/**
* Construct an empty Ref (the managed object will be null)
*/
Ref() = default;
2022-10-30 14:59:20 -04:00
~Ref() {
CC_SAFE_RELEASE(m_obj);
}
/**
2022-10-30 14:59:20 -04:00
* Swap the managed object with another object. The managed object
* will be released, and the new object retained
* @param other The new object to swap to
*/
void swap(T* other) {
CC_SAFE_RELEASE(m_obj);
m_obj = other;
CC_SAFE_RETAIN(other);
}
2022-10-30 14:59:20 -04:00
/**
* Return the managed object
* @returns The managed object
*/
T* data() const {
return m_obj;
}
operator T*() const {
return m_obj;
}
2022-10-30 14:59:20 -04:00
T* operator*() const {
return m_obj;
}
2022-10-30 14:59:20 -04:00
T* operator->() const {
return m_obj;
}
2022-10-30 14:59:20 -04:00
T* operator=(T* obj) {
this->swap(obj);
return obj;
}
2022-10-30 14:59:20 -04:00
Ref<T>& operator=(Ref<T> const& other) {
this->swap(other.data());
return *this;
}
2022-10-30 14:59:20 -04:00
Ref<T>& operator=(Ref<T>&& other) {
this->swap(other.data());
return *this;
}
2022-10-30 14:59:20 -04:00
bool operator==(T* other) const {
return m_obj == other;
}
bool operator==(Ref<T> const& other) const {
return m_obj == other.m_obj;
}
bool operator!=(T* other) const {
return m_obj != other;
}
bool operator!=(Ref<T> const& other) const {
return m_obj != other.m_obj;
}
// for containers
bool operator<(Ref<T> const& other) const {
return m_obj < other.m_obj;
}
bool operator>(Ref<T> const& other) const {
return m_obj > other.m_obj;
}
};
}
namespace std {
template<class T>
struct hash<geode::Ref<T>> {
size_t operator()(geode::Ref<T> const& ref) const {
return std::hash<T*>()(ref.data());
}
};
}