172 lines
3.7 KiB
C++
172 lines
3.7 KiB
C++
/*
|
|
* Copyright 2015 - 2025 gary@drinkingtea.net
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "assert.hpp"
|
|
#include "array.hpp"
|
|
#include "def.hpp"
|
|
#include "span.hpp"
|
|
|
|
namespace ox {
|
|
|
|
namespace detail {
|
|
|
|
template<bool unique>
|
|
class AnyPtrT {
|
|
private:
|
|
struct WrapBase {
|
|
virtual constexpr ~WrapBase() = default;
|
|
virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
|
|
virtual constexpr operator bool() const noexcept = 0;
|
|
virtual void free() noexcept = 0;
|
|
};
|
|
|
|
template<typename T>
|
|
struct Wrap final: WrapBase {
|
|
T *data{};
|
|
explicit constexpr Wrap(T *pData) noexcept: data(pData) {
|
|
}
|
|
constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override {
|
|
oxAssert(s.size() >= sizeof(Wrap), "too small buffer");
|
|
if (std::is_constant_evaluated()) {
|
|
return new Wrap(data);
|
|
} else {
|
|
return new(s.data()) Wrap(data);
|
|
}
|
|
}
|
|
constexpr operator bool() const noexcept override {
|
|
return data != nullptr;
|
|
}
|
|
constexpr void free() noexcept override {
|
|
safeDelete(data);
|
|
data = {};
|
|
}
|
|
};
|
|
|
|
WrapBase *m_wrapPtr{};
|
|
ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
|
|
|
|
public:
|
|
constexpr AnyPtrT() noexcept = default;
|
|
|
|
template<typename T>
|
|
constexpr AnyPtrT(T *ptr) noexcept {
|
|
if (std::is_constant_evaluated()) {
|
|
m_wrapPtr = new Wrap<T>(ptr);
|
|
} else {
|
|
m_wrapPtr = new(m_wrapData.data()) Wrap<T>(ptr);
|
|
}
|
|
}
|
|
|
|
constexpr AnyPtrT(AnyPtrT const&other) noexcept requires(!unique) {
|
|
if (other) {
|
|
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
|
|
}
|
|
}
|
|
|
|
constexpr AnyPtrT(AnyPtrT &&other) noexcept {
|
|
if (other) {
|
|
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
|
|
if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
other.m_wrapPtr = {};
|
|
}
|
|
}
|
|
|
|
constexpr ~AnyPtrT() noexcept {
|
|
if constexpr(unique) {
|
|
free();
|
|
}
|
|
if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr AnyPtrT &operator=(T *ptr) noexcept {
|
|
if constexpr(unique) {
|
|
free();
|
|
} else if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
if (std::is_constant_evaluated()) {
|
|
m_wrapPtr = new Wrap(ptr);
|
|
} else {
|
|
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept requires(!unique) {
|
|
if (this != &ptr) {
|
|
if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
if (ptr) {
|
|
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
|
|
} else {
|
|
m_wrapPtr = nullptr;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
constexpr AnyPtrT &operator=(AnyPtrT &&ptr) noexcept {
|
|
if (this != &ptr) {
|
|
if constexpr(unique) {
|
|
free();
|
|
} else if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
if (ptr) {
|
|
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
|
|
if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(ptr.m_wrapPtr);
|
|
ptr.m_wrapPtr = nullptr;
|
|
}
|
|
} else {
|
|
m_wrapPtr = nullptr;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
constexpr operator bool() const noexcept {
|
|
return m_wrapPtr && *m_wrapPtr;
|
|
}
|
|
|
|
constexpr void free() noexcept {
|
|
if (m_wrapPtr) {
|
|
m_wrapPtr->free();
|
|
}
|
|
if (std::is_constant_evaluated()) {
|
|
ox::safeDelete(m_wrapPtr);
|
|
}
|
|
m_wrapPtr = nullptr;
|
|
}
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr T *get() const noexcept {
|
|
#ifdef OX_BARE_METAL
|
|
return static_cast<Wrap<T>*>(m_wrapPtr)->data;
|
|
#else
|
|
return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
|
|
#endif
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
using AnyPtr = detail::AnyPtrT<false>;
|
|
using UAnyPtr = detail::AnyPtrT<true>;
|
|
|
|
} |