Added more stuff like Logging, DynamicPointer, utilities for using STL allocators and NotNullable.
This commit is contained in:
176
source/mijin/memory/dynamic_pointer.hpp
Normal file
176
source/mijin/memory/dynamic_pointer.hpp
Normal file
@@ -0,0 +1,176 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(MIJIN_MEMORY_DYNAMIC_POINTER_HPP_INCLUDED)
|
||||
#define MIJIN_MEMORY_DYNAMIC_POINTER_HPP_INCLUDED 1
|
||||
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include "../internal/common.hpp"
|
||||
#include "../memory/memutil.hpp"
|
||||
#include "../util/concepts.hpp"
|
||||
#include "../util/flag.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
MIJIN_DEFINE_FLAG(Owning);
|
||||
|
||||
template<typename T, deleter_type<T> TDeleter = std::default_delete<T>>
|
||||
class DynamicPointer
|
||||
{
|
||||
public:
|
||||
using pointer = T*;
|
||||
using element_type = T;
|
||||
using deleter_t = TDeleter;
|
||||
private:
|
||||
std::uintptr_t mData = 0;
|
||||
[[no_unique_address]] TDeleter mDeleter;
|
||||
public:
|
||||
constexpr DynamicPointer(std::nullptr_t = nullptr) MIJIN_NOEXCEPT {}
|
||||
DynamicPointer(const DynamicPointer&) = delete;
|
||||
constexpr DynamicPointer(pointer ptr, Owning owning, TDeleter deleter = {}) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<TDeleter>)
|
||||
: mData(std::bit_cast<std::uintptr_t>(ptr) | (owning ? 1 : 0)), mDeleter(std::move(deleter))
|
||||
{
|
||||
MIJIN_ASSERT((std::bit_cast<std::uintptr_t>(ptr) & 1) == 0, "Invalid address, DynamicPointer requires addresses to be divisible by two.");
|
||||
}
|
||||
template<typename TOther, typename TOtherDeleter> requires (std::is_constructible_v<TDeleter, TOtherDeleter&&>)
|
||||
constexpr DynamicPointer(DynamicPointer<TOther, TOtherDeleter>&& other) MIJIN_NOEXCEPT_IF((std::is_nothrow_convertible_v<TOtherDeleter, TDeleter>))
|
||||
: mData(std::exchange(other.mData, 0)), mDeleter(std::move(other.mDeleter)) {
|
||||
MIJIN_ASSERT(other.mData == 0, "");
|
||||
}
|
||||
constexpr ~DynamicPointer() noexcept
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
DynamicPointer& operator=(const DynamicPointer&) = delete;
|
||||
DynamicPointer& operator=(std::nullptr_t) MIJIN_NOEXCEPT
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TOther, typename TOtherDeleter> requires(std::is_assignable_v<TDeleter, TOtherDeleter>)
|
||||
DynamicPointer& operator=(DynamicPointer<TOther, TOtherDeleter>&& other) MIJIN_NOEXCEPT_IF((std::is_nothrow_assignable_v<TDeleter, TOtherDeleter>))
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
reset();
|
||||
mData = std::exchange(other.mData, 0);
|
||||
mDeleter = std::move(other.mDeleter);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TOther, typename TOtherDeleter> requires(std::equality_comparable_with<T, TOther>)
|
||||
auto operator<=>(const DynamicPointer<TOther, TOtherDeleter>& other) MIJIN_NOEXCEPT
|
||||
{
|
||||
return mData <=> other.mData;
|
||||
}
|
||||
|
||||
constexpr bool operator==(std::nullptr_t) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return empty();
|
||||
}
|
||||
|
||||
constexpr bool operator!=(std::nullptr_t) const MIJIN_NOEXCEPT
|
||||
{
|
||||
return !empty();
|
||||
}
|
||||
|
||||
constexpr operator bool() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return !empty();
|
||||
}
|
||||
|
||||
constexpr bool operator!() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return empty();
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
constexpr element_type& operator*() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool isOwning() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return (mData & 1) == 1;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool empty() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return mData == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr pointer get() const MIJIN_NOEXCEPT
|
||||
{
|
||||
return std::bit_cast<pointer>(mData & ~1);
|
||||
}
|
||||
|
||||
constexpr void reset(pointer ptr, Owning owning) MIJIN_NOEXCEPT
|
||||
{
|
||||
if (isOwning())
|
||||
{
|
||||
mDeleter(get());
|
||||
}
|
||||
mData = std::bit_cast<std::uintptr_t>(ptr) | (owning ? 1 : 0);
|
||||
}
|
||||
|
||||
constexpr void reset() MIJIN_NOEXCEPT
|
||||
{
|
||||
reset(nullptr, Owning::NO);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
pointer release() MIJIN_NOEXCEPT
|
||||
{
|
||||
return std::bit_cast<pointer>(std::exchange(mData, 0) & ~1);
|
||||
}
|
||||
|
||||
template<typename TOther, deleter_type<TOther> TOtherDeleter>
|
||||
friend class DynamicPointer;
|
||||
};
|
||||
|
||||
template<typename T, typename TDeleter>
|
||||
bool operator==(std::nullptr_t, const DynamicPointer<T, TDeleter>& pointer) MIJIN_NOEXCEPT
|
||||
{
|
||||
return pointer == nullptr;
|
||||
}
|
||||
|
||||
template<typename T, typename TDeleter>
|
||||
bool operator!=(std::nullptr_t, const DynamicPointer<T, TDeleter>& pointer) MIJIN_NOEXCEPT
|
||||
{
|
||||
return pointer != nullptr;
|
||||
}
|
||||
|
||||
template<typename T, typename... TArgs>
|
||||
DynamicPointer<T, std::default_delete<T>> makeDynamic(TArgs&&... args) MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<T, TArgs...>))
|
||||
{
|
||||
return DynamicPointer<T, std::default_delete<T>>(new T(std::forward<TArgs>(args)...), Owning::YES);
|
||||
}
|
||||
|
||||
template<typename T, allocator_type_for<T> TAllocator, typename... TArgs>
|
||||
DynamicPointer<T, AllocatorDeleter<TAllocator>> makeDynamicWithAllocator(TAllocator allocator, TArgs&&... args)
|
||||
MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<T, TArgs...> && std::is_nothrow_move_constructible_v<TAllocator>))
|
||||
{
|
||||
T* obj = allocator.allocate(1);
|
||||
if (obj != nullptr)
|
||||
{
|
||||
::new(obj) T(std::forward<TArgs>(args)...);
|
||||
}
|
||||
return DynamicPointer<T, AllocatorDeleter<TAllocator>>(obj, Owning::YES, AllocatorDeleter<TAllocator>(std::move(allocator)));
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
#endif // !defined(MIJIN_MEMORY_DYNAMIC_POINTER_HPP_INCLUDED)
|
||||
Reference in New Issue
Block a user