You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.2 KiB

#pragma once
#include <new>
#include <utility>
#include "common.h"
namespace mem
{
template<typename T>
struct aligned_ptr_handle
{
constexpr inline aligned_ptr_handle(){};
constexpr inline ~aligned_ptr_handle(){};
constexpr static inline void delete_object(T** ptr) { (*ptr)->~T(); }
};
template<typename T, typename H = aligned_ptr_handle<T > >
struct aligned_ptr;
template<>
struct aligned_ptr<void, void>;
using aligned_ptr_util = aligned_ptr<void, void>;
template<>
struct aligned_ptr<void, void> final
{
template<typename T>
static inline T* alloc(T&& value)
{
u8* ptr = reinterpret_cast<u8*>(_alloc(alignof(T), sizeof(T)));
new(ptr) T(std::move(value));
return reinterpret_cast<T*>(ptr);
}
template<typename T>
static inline T* alloc()
{
return alloc(T());
}
template<typename T, typename... Args>
static inline T* make(Args&&... init) { return alloc(T(std::forward<Args>(init)...)); }
template<typename T, typename H>
static inline void dealloc(T* ptr) { H::delete_object(&ptr); if(ptr) _dealloc(reinterpret_cast<void*>(ptr)); }
private:
static void* _alloc(usize align, usize size);
static void _dealloc(void* ptr);
constexpr inline ~aligned_ptr(){}
};
template<typename T, typename H>
struct aligned_ptr final
{
using Handle = H;
inline explicit aligned_ptr(T* raw) : ptr(raw){}
inline aligned_ptr(aligned_ptr<T, H>&& move) : ptr(move.ptr) { *const_cast<T**>(&move.ptr) = nullptr; }
inline aligned_ptr(T&& box) : aligned_ptr(aligned_ptr_util::alloc(std::move(box))){}
inline aligned_ptr() : aligned_ptr(T()){}
inline ~aligned_ptr() { if(ptr) aligned_ptr_util::dealloc<T, Handle>(ptr); }
inline aligned_ptr<T> clone() const { return aligned_ptr(*this); }
inline const T & get() const { if(ptr) return *ptr; else throw "TODO: moved"; }
inline T & get() { if(ptr) return *ptr; else throw "TODO: moved"; }
inline const T * get_ptr() const { if(ptr) return ptr; else throw "TODO: moved"; }
inline T * get_ptr() { if(ptr) return ptr; else throw "TODO: moved"; }
inline const T * operator->() const { return get_ptr(); }
inline T * operator->() { return get_ptr(); }
inline const T * operator&() const { return get_ptr(); }
inline T * operator&() { return get_ptr(); }
inline const T & operator*() const { return get(); }
inline T & operator*() { return get(); }
inline operator const T*() const { return get_ptr(); }
inline operator T*() { return get_ptr(); }
inline operator const T&() const { return get(); }
inline operator T&() { return get(); }
inline aligned_ptr<T>& operator=(aligned_ptr<T, H>&& other)
{
if(ptr) aligned_ptr_util::dealloc<T, H>(ptr);
*const_cast<T**>(&ptr) = other.ptr;
*const_cast<T**>(&other.ptr) = nullptr;
return *this;
}
private:
inline aligned_ptr<T>& operator=(const aligned_ptr<T, H>& other)
{
return (*this = other.clone());
}
inline aligned_ptr(const aligned_ptr<T, H>& copy) : ptr(aligned_ptr_util::make<T>(copy.get())){}
T* __restrict__ const ptr;
};
template<typename T, typename... Args>
inline aligned_ptr<T> make_aligned(Args&&... init) { return aligned_ptr<T >(aligned_ptr_util::template make<T>(std::forward<Args>(init)...)); }
}