305 lines
6.1 KiB
C++
305 lines
6.1 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
|
|
|
|
#if __has_include(<memory>)
|
|
|
|
#include <memory>
|
|
|
|
#else
|
|
|
|
#include "utility.hpp"
|
|
|
|
namespace std {
|
|
|
|
template<class T>
|
|
struct allocator {
|
|
[[nodiscard]]
|
|
constexpr T *allocate(size_t n) {
|
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
|
}
|
|
|
|
constexpr void deallocate(T *p, std::size_t) {
|
|
::operator delete(p);
|
|
}
|
|
};
|
|
|
|
template<typename T, typename... Args>
|
|
constexpr T *construct_at(T *p, Args &&...args ) {
|
|
return new (p) T(ox::forward<Args>(args)...);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#include "error.hpp"
|
|
#include "utility.hpp"
|
|
|
|
|
|
namespace ox {
|
|
|
|
/*
|
|
* safeDelete exists because deleting an incomplete type will simply
|
|
* free the memory without running the destructor.
|
|
*/
|
|
|
|
template<typename T>
|
|
constexpr void safeDelete(T *val) requires(sizeof(T) >= 1) {
|
|
delete val;
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
|
|
delete[] val;
|
|
}
|
|
|
|
struct DefaultDelete {
|
|
constexpr void operator()(auto *p) noexcept {
|
|
safeDelete(p);
|
|
}
|
|
};
|
|
|
|
|
|
template<typename T, typename Deleter = DefaultDelete>
|
|
class SharedPtr {
|
|
|
|
private:
|
|
T *m_t = nullptr;
|
|
int *m_refCnt = nullptr;
|
|
|
|
public:
|
|
using value_type = T;
|
|
explicit constexpr SharedPtr(T *t = nullptr) noexcept: m_t(t), m_refCnt(new int) {
|
|
}
|
|
|
|
constexpr SharedPtr(SharedPtr &other) {
|
|
m_t = other.m_t;
|
|
m_refCnt = other.m_refCnt;
|
|
++*m_refCnt;
|
|
}
|
|
|
|
constexpr SharedPtr(const SharedPtr&) = delete;
|
|
|
|
template<typename U>
|
|
constexpr SharedPtr(SharedPtr<U> &&other) noexcept {
|
|
m_t = other.m_t;
|
|
m_refCnt = other.m_refCnt;
|
|
other.m_refCnt = nullptr;
|
|
}
|
|
|
|
~SharedPtr() {
|
|
if (m_refCnt) {
|
|
--*m_refCnt;
|
|
if (!*m_refCnt) {
|
|
Deleter()(m_t);
|
|
safeDelete(m_refCnt);
|
|
}
|
|
}
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr T *get() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
constexpr T *reset() noexcept {
|
|
if (m_refCnt) {
|
|
--*m_refCnt;
|
|
if (!*m_refCnt) {
|
|
safeDelete(m_refCnt);
|
|
Deleter()(m_t);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename U>
|
|
constexpr void reset(U *other) {
|
|
reset();
|
|
m_t = other;
|
|
m_refCnt = new int(1);
|
|
}
|
|
|
|
template<typename U>
|
|
constexpr SharedPtr &operator=(SharedPtr<U> &&other) {
|
|
reset(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
constexpr T *operator->() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
constexpr T &operator*() const noexcept {
|
|
return *m_t;
|
|
}
|
|
|
|
constexpr operator bool() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(const SharedPtr<T> &p1, const SharedPtr<T> &p2) noexcept {
|
|
return p1.get() == p2.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(const SharedPtr<T> &p1, std::nullptr_t) noexcept {
|
|
return p1.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(std::nullptr_t, const SharedPtr<T> &p2) noexcept {
|
|
return p2.get();
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(const SharedPtr<T> &p1, const SharedPtr<T> &p2) noexcept {
|
|
return p1.get() != p2.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(const SharedPtr<T> &p1, std::nullptr_t) noexcept {
|
|
return !p1.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(std::nullptr_t, const SharedPtr<T> &p2) noexcept {
|
|
return !p2.get();
|
|
}
|
|
|
|
|
|
template<typename T, typename Deleter = DefaultDelete>
|
|
class UniquePtr {
|
|
|
|
private:
|
|
T *m_t = nullptr;
|
|
|
|
public:
|
|
using value_type = T;
|
|
explicit constexpr UniquePtr(T *t = nullptr) noexcept: m_t(t) {
|
|
}
|
|
|
|
constexpr UniquePtr(UniquePtr&) = delete;
|
|
|
|
constexpr UniquePtr(const UniquePtr&) = delete;
|
|
|
|
template<typename U, typename UDeleter>
|
|
constexpr UniquePtr(UniquePtr<U, UDeleter> &&other) noexcept {
|
|
m_t = other.release();
|
|
}
|
|
|
|
constexpr ~UniquePtr() {
|
|
Deleter()(m_t);
|
|
}
|
|
|
|
constexpr T *release() noexcept {
|
|
auto t = m_t;
|
|
m_t = nullptr;
|
|
return t;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr T *get() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
template<typename U, typename UDeleter>
|
|
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
|
|
auto t = m_t;
|
|
m_t = other.release();
|
|
Deleter()(t);
|
|
}
|
|
|
|
constexpr UniquePtr &operator=(UniquePtr const&other) = delete;
|
|
|
|
template<typename U, typename UDeleter>
|
|
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> const&other) = delete;
|
|
|
|
constexpr UniquePtr &operator=(UniquePtr<T> &&other) noexcept {
|
|
reset(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
template<typename U, typename UDeleter>
|
|
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> &&other) noexcept {
|
|
reset(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
constexpr T *operator->() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
constexpr T &operator*() const noexcept {
|
|
return *m_t;
|
|
}
|
|
|
|
constexpr operator bool() const noexcept {
|
|
return m_t;
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T, typename Deleter = DefaultDelete>
|
|
using UPtr = UniquePtr<T, Deleter>;
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
|
|
return p1.get() == p2.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
|
|
return p1.get() == nullptr;
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator==(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
|
|
return p2.get() == nullptr;
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
|
|
return p1.get() != p2.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
|
|
return !p1.get();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr bool operator!=(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
|
|
return !p2.get();
|
|
}
|
|
|
|
|
|
template<typename T, typename U = T, typename ...Args>
|
|
[[nodiscard]]
|
|
constexpr auto make_unique(Args&&... args) {
|
|
return UniquePtr<U>(new T(ox::forward<Args>(args)...));
|
|
}
|
|
|
|
template<typename T, typename U = T, typename ...Args>
|
|
[[nodiscard]]
|
|
constexpr Result<UniquePtr<U>> make_unique_catch(Args&&... args) noexcept {
|
|
try {
|
|
return UniquePtr<U>(new T(ox::forward<Args>(args)...));
|
|
} catch (ox::Exception const&ex) {
|
|
return ex.toError();
|
|
}
|
|
}
|
|
|
|
}
|