hello
parent
82d36caecf
commit
d19bc6b94b
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
|||
sanitizers(${target_name})
|
||||
endmacro()
|
||||
|
||||
project(blt-gp VERSION 0.2.8)
|
||||
project(blt-gp VERSION 0.2.9)
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
|
|
@ -42,296 +42,316 @@ namespace blt::gp
|
|||
{
|
||||
BLT_META_MAKE_FUNCTION_CHECK(drop);
|
||||
}
|
||||
|
||||
|
||||
class stack_allocator
|
||||
{
|
||||
constexpr static blt::size_t PAGE_SIZE = 0x100;
|
||||
constexpr static blt::size_t MAX_ALIGNMENT = 8;
|
||||
template<typename T>
|
||||
using NO_REF_T = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
using Allocator = aligned_allocator;
|
||||
public:
|
||||
static Allocator& get_allocator();
|
||||
|
||||
struct size_data_t
|
||||
constexpr static blt::size_t PAGE_SIZE = 0x100;
|
||||
constexpr static blt::size_t MAX_ALIGNMENT = 8;
|
||||
template <typename T>
|
||||
using NO_REF_T = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
using Allocator = aligned_allocator;
|
||||
|
||||
public:
|
||||
static Allocator& get_allocator();
|
||||
|
||||
struct size_data_t
|
||||
{
|
||||
blt::size_t total_size_bytes = 0;
|
||||
blt::size_t total_used_bytes = 0;
|
||||
blt::size_t total_remaining_bytes = 0;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const size_data_t& data)
|
||||
{
|
||||
blt::size_t total_size_bytes = 0;
|
||||
blt::size_t total_used_bytes = 0;
|
||||
blt::size_t total_remaining_bytes = 0;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const size_data_t& data)
|
||||
{
|
||||
stream << "[";
|
||||
stream << data.total_used_bytes << " / " << data.total_size_bytes;
|
||||
stream << " ("
|
||||
<< (data.total_size_bytes != 0 ? (static_cast<double>(data.total_used_bytes) / static_cast<double>(data.total_size_bytes) *
|
||||
100) : 0) << "%); space left: " << data.total_remaining_bytes << "]";
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static inline constexpr blt::size_t aligned_size() noexcept
|
||||
{
|
||||
return aligned_size(sizeof(NO_REF_T<T>));
|
||||
stream << "[";
|
||||
stream << data.total_used_bytes << " / " << data.total_size_bytes;
|
||||
stream << " ("
|
||||
<< (data.total_size_bytes != 0
|
||||
? (static_cast<double>(data.total_used_bytes) / static_cast<double>(data.total_size_bytes) *
|
||||
100)
|
||||
: 0) << "%); space left: " << data.total_remaining_bytes << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
static inline constexpr blt::size_t aligned_size(blt::size_t size) noexcept
|
||||
{
|
||||
return (size + (MAX_ALIGNMENT - 1)) & ~(MAX_ALIGNMENT - 1);
|
||||
}
|
||||
|
||||
stack_allocator() = default;
|
||||
|
||||
stack_allocator(const stack_allocator& copy)
|
||||
{
|
||||
if (copy.data_ == nullptr || copy.bytes_stored == 0)
|
||||
return;
|
||||
expand(copy.size_);
|
||||
std::memcpy(data_, copy.data_, copy.bytes_stored);
|
||||
bytes_stored = copy.bytes_stored;
|
||||
}
|
||||
|
||||
stack_allocator(stack_allocator&& move) noexcept:
|
||||
data_(std::exchange(move.data_, nullptr)), bytes_stored(std::exchange(move.bytes_stored, 0)), size_(std::exchange(move.size_, 0))
|
||||
{}
|
||||
|
||||
stack_allocator& operator=(const stack_allocator& copy) = delete;
|
||||
|
||||
stack_allocator& operator=(stack_allocator&& move) noexcept
|
||||
{
|
||||
data_ = std::exchange(move.data_, data_);
|
||||
size_ = std::exchange(move.size_, size_);
|
||||
bytes_stored = std::exchange(move.bytes_stored, bytes_stored);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~stack_allocator()
|
||||
{
|
||||
get_allocator().deallocate(data_, size_);
|
||||
}
|
||||
|
||||
void insert(const stack_allocator& stack)
|
||||
{
|
||||
if (stack.empty())
|
||||
return;
|
||||
if (stack.bytes_stored + bytes_stored > size_)
|
||||
expand(stack.bytes_stored + size_);
|
||||
std::memcpy(data_ + bytes_stored, stack.data_, stack.bytes_stored);
|
||||
bytes_stored += stack.bytes_stored;
|
||||
}
|
||||
|
||||
void copy_from(const stack_allocator& stack, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return;
|
||||
if (bytes + bytes_stored > size_)
|
||||
expand(bytes + size_);
|
||||
std::memcpy(data_ + bytes_stored, stack.data_ + (stack.bytes_stored - bytes), bytes);
|
||||
bytes_stored += bytes;
|
||||
}
|
||||
|
||||
void copy_from(blt::u8* data, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0 || data == nullptr)
|
||||
return;
|
||||
if (bytes + bytes_stored > size_)
|
||||
expand(bytes + size_);
|
||||
std::memcpy(data_ + bytes_stored, data, bytes);
|
||||
bytes_stored += bytes;
|
||||
}
|
||||
|
||||
void copy_to(blt::u8* data, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0 || data == nullptr)
|
||||
return;
|
||||
std::memcpy(data, data_ + (bytes_stored - bytes), bytes);
|
||||
}
|
||||
|
||||
template<typename T, typename NO_REF = NO_REF_T<T>>
|
||||
void push(const T& t)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
auto ptr = allocate_bytes_for_size(sizeof(NO_REF));
|
||||
std::memcpy(ptr, &t, sizeof(NO_REF));
|
||||
}
|
||||
|
||||
template<typename T, typename NO_REF = NO_REF_T<T>>
|
||||
T pop()
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
constexpr auto size = aligned_size(sizeof(NO_REF));
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static inline constexpr blt::size_t aligned_size() noexcept
|
||||
{
|
||||
return aligned_size(sizeof(NO_REF_T<T>));
|
||||
}
|
||||
|
||||
static inline constexpr blt::size_t aligned_size(blt::size_t size) noexcept
|
||||
{
|
||||
return (size + (MAX_ALIGNMENT - 1)) & ~(MAX_ALIGNMENT - 1);
|
||||
}
|
||||
|
||||
stack_allocator() = default;
|
||||
|
||||
stack_allocator(const stack_allocator& copy)
|
||||
{
|
||||
if (copy.data_ == nullptr || copy.bytes_stored == 0)
|
||||
return;
|
||||
expand(copy.size_);
|
||||
std::memcpy(data_, copy.data_, copy.bytes_stored);
|
||||
bytes_stored = copy.bytes_stored;
|
||||
}
|
||||
|
||||
stack_allocator(stack_allocator&& move) noexcept:
|
||||
data_(std::exchange(move.data_, nullptr)), bytes_stored(std::exchange(move.bytes_stored, 0)), size_(std::exchange(move.size_, 0))
|
||||
{
|
||||
}
|
||||
|
||||
stack_allocator& operator=(const stack_allocator& copy) = delete;
|
||||
|
||||
stack_allocator& operator=(stack_allocator&& move) noexcept
|
||||
{
|
||||
data_ = std::exchange(move.data_, data_);
|
||||
size_ = std::exchange(move.size_, size_);
|
||||
bytes_stored = std::exchange(move.bytes_stored, bytes_stored);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~stack_allocator()
|
||||
{
|
||||
get_allocator().deallocate(data_, size_);
|
||||
}
|
||||
|
||||
void insert(const stack_allocator& stack)
|
||||
{
|
||||
if (stack.empty())
|
||||
return;
|
||||
if (stack.bytes_stored + bytes_stored > size_)
|
||||
expand(stack.bytes_stored + size_);
|
||||
std::memcpy(data_ + bytes_stored, stack.data_, stack.bytes_stored);
|
||||
bytes_stored += stack.bytes_stored;
|
||||
}
|
||||
|
||||
void copy_from(const stack_allocator& stack, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return;
|
||||
if (bytes + bytes_stored > size_)
|
||||
expand(bytes + size_);
|
||||
std::memcpy(data_ + bytes_stored, stack.data_ + (stack.bytes_stored - bytes), bytes);
|
||||
bytes_stored += bytes;
|
||||
}
|
||||
|
||||
void copy_from(blt::u8* data, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0 || data == nullptr)
|
||||
return;
|
||||
if (bytes + bytes_stored > size_)
|
||||
expand(bytes + size_);
|
||||
std::memcpy(data_ + bytes_stored, data, bytes);
|
||||
bytes_stored += bytes;
|
||||
}
|
||||
|
||||
void copy_to(blt::u8* data, blt::size_t bytes)
|
||||
{
|
||||
if (bytes == 0 || data == nullptr)
|
||||
return;
|
||||
std::memcpy(data, data_ + (bytes_stored - bytes), bytes);
|
||||
}
|
||||
|
||||
template <typename T, typename NO_REF = NO_REF_T<T>>
|
||||
void push(const T& t)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
auto ptr = allocate_bytes_for_size(sizeof(NO_REF));
|
||||
std::memcpy(ptr, &t, sizeof(NO_REF));
|
||||
}
|
||||
|
||||
template <typename T, typename NO_REF = NO_REF_T<T>>
|
||||
T pop()
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
constexpr auto size = aligned_size(sizeof(NO_REF));
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
if (bytes_stored < size)
|
||||
BLT_ABORT("Not enough bytes left to pop!");
|
||||
#endif
|
||||
bytes_stored -= size;
|
||||
return *reinterpret_cast<T*>(data_ + bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::u8* from(blt::size_t bytes) const
|
||||
{
|
||||
bytes_stored -= size;
|
||||
return *reinterpret_cast<T*>(data_ + bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::u8* from(blt::size_t bytes) const
|
||||
{
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
if (bytes_stored < bytes)
|
||||
BLT_ABORT(("Not enough bytes in stack to reference " + std::to_string(bytes) + " bytes requested but " + std::to_string(bytes) +
|
||||
" bytes stored!").c_str());
|
||||
#endif
|
||||
return data_ + (bytes_stored - bytes);
|
||||
}
|
||||
|
||||
template<typename T, typename NO_REF = NO_REF_T<T>>
|
||||
T& from(blt::size_t bytes)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
return *reinterpret_cast<NO_REF*>(from(aligned_size(sizeof(NO_REF)) + bytes));
|
||||
}
|
||||
|
||||
void pop_bytes(blt::size_t bytes)
|
||||
{
|
||||
return data_ + (bytes_stored - bytes);
|
||||
}
|
||||
|
||||
template <typename T, typename NO_REF = NO_REF_T<T>>
|
||||
T& from(blt::size_t bytes)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<NO_REF> && "Type must be bitwise copyable!");
|
||||
static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!");
|
||||
return *reinterpret_cast<NO_REF*>(from(aligned_size(sizeof(NO_REF)) + bytes));
|
||||
}
|
||||
|
||||
void pop_bytes(blt::size_t bytes)
|
||||
{
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
if (bytes_stored < bytes)
|
||||
BLT_ABORT(("Not enough bytes in stack to pop " + std::to_string(bytes) + " bytes requested but " + std::to_string(bytes) +
|
||||
" bytes stored!").c_str());
|
||||
#endif
|
||||
bytes_stored -= bytes;
|
||||
}
|
||||
|
||||
void transfer_bytes(stack_allocator& to, blt::size_t bytes)
|
||||
{
|
||||
bytes_stored -= bytes;
|
||||
}
|
||||
|
||||
void transfer_bytes(stack_allocator& to, blt::size_t bytes)
|
||||
{
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
if (bytes_stored < bytes)
|
||||
BLT_ABORT(("Not enough bytes in stack to transfer " + std::to_string(bytes) + " bytes requested but " + std::to_string(bytes) +
|
||||
" bytes stored!").c_str());
|
||||
#endif
|
||||
auto alg = aligned_size(bytes);
|
||||
to.copy_from(*this, alg);
|
||||
pop_bytes(alg);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call_destructors()
|
||||
auto alg = aligned_size(bytes);
|
||||
to.copy_from(*this, alg);
|
||||
pop_bytes(alg);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void call_destructors()
|
||||
{
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
{
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
{
|
||||
blt::size_t offset = (stack_allocator::aligned_size(sizeof(NO_REF_T<Args>)) + ...) -
|
||||
stack_allocator::aligned_size(sizeof(NO_REF_T<typename blt::meta::arg_helper<Args...>::First>));
|
||||
((call_drop<Args>(offset), offset -= stack_allocator::aligned_size(sizeof(NO_REF_T<Args>))), ...);
|
||||
}
|
||||
blt::size_t offset = (stack_allocator::aligned_size(sizeof(NO_REF_T<Args>)) + ...) -
|
||||
stack_allocator::aligned_size(sizeof(NO_REF_T<typename blt::meta::arg_helper<Args...>::First>));
|
||||
((call_drop<Args>(offset), offset -= stack_allocator::aligned_size(sizeof(NO_REF_T<Args>))), ...);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
return bytes_stored == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::ptrdiff_t remaining_bytes_in_block() const noexcept
|
||||
{
|
||||
return static_cast<blt::ptrdiff_t>(size_ - bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::ptrdiff_t bytes_in_head() const noexcept
|
||||
{
|
||||
return static_cast<blt::ptrdiff_t>(bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_data_t size() const noexcept
|
||||
{
|
||||
size_data_t data;
|
||||
|
||||
data.total_used_bytes = bytes_stored;
|
||||
data.total_size_bytes = size_;
|
||||
data.total_remaining_bytes = remaining_bytes_in_block();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void reserve(blt::size_t bytes)
|
||||
{
|
||||
if (bytes > size_)
|
||||
expand_raw(bytes);
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::size_t stored() const
|
||||
{
|
||||
return bytes_stored;
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::size_t internal_storage_size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
bytes_stored = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void expand(blt::size_t bytes)
|
||||
{
|
||||
//bytes = to_nearest_page_size(bytes);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
return bytes_stored == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::ptrdiff_t remaining_bytes_in_block() const noexcept
|
||||
{
|
||||
return static_cast<blt::ptrdiff_t>(size_ - bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::ptrdiff_t bytes_in_head() const noexcept
|
||||
{
|
||||
return static_cast<blt::ptrdiff_t>(bytes_stored);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_data_t size() const noexcept
|
||||
{
|
||||
size_data_t data;
|
||||
|
||||
data.total_used_bytes = bytes_stored;
|
||||
data.total_size_bytes = size_;
|
||||
data.total_remaining_bytes = remaining_bytes_in_block();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void reserve(blt::size_t bytes)
|
||||
{
|
||||
if (bytes > size_)
|
||||
expand_raw(bytes);
|
||||
}
|
||||
|
||||
void expand_raw(blt::size_t bytes)
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::size_t stored() const
|
||||
{
|
||||
return bytes_stored;
|
||||
}
|
||||
|
||||
[[nodiscard]] blt::size_t internal_storage_size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
bytes_stored = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void expand(blt::size_t bytes)
|
||||
{
|
||||
//bytes = to_nearest_page_size(bytes);
|
||||
expand_raw(bytes);
|
||||
}
|
||||
|
||||
void expand_raw(blt::size_t bytes)
|
||||
{
|
||||
auto new_data = static_cast<blt::u8*>(get_allocator().allocate(bytes));
|
||||
if (bytes_stored > 0)
|
||||
std::memcpy(new_data, data_, bytes_stored);
|
||||
get_allocator().deallocate(data_, size_);
|
||||
data_ = new_data;
|
||||
size_ = bytes;
|
||||
}
|
||||
|
||||
static size_t to_nearest_page_size(blt::size_t bytes) noexcept
|
||||
{
|
||||
constexpr static blt::size_t MASK = ~(PAGE_SIZE - 1);
|
||||
return (bytes & MASK) + PAGE_SIZE;
|
||||
}
|
||||
|
||||
void* get_aligned_pointer(blt::size_t bytes) noexcept
|
||||
{
|
||||
if (data_ == nullptr)
|
||||
return nullptr;
|
||||
blt::size_t remaining_bytes = remaining_bytes_in_block();
|
||||
auto* pointer = static_cast<void*>(data_ + bytes_stored);
|
||||
return std::align(MAX_ALIGNMENT, bytes, pointer, remaining_bytes);
|
||||
}
|
||||
|
||||
void* allocate_bytes_for_size(blt::size_t bytes)
|
||||
{
|
||||
auto used_bytes = aligned_size(bytes);
|
||||
auto aligned_ptr = get_aligned_pointer(used_bytes);
|
||||
if (aligned_ptr == nullptr)
|
||||
{
|
||||
auto new_data = static_cast<blt::u8*>(get_allocator().allocate(bytes));
|
||||
if (bytes_stored > 0)
|
||||
std::memcpy(new_data, data_, bytes_stored);
|
||||
get_allocator().deallocate(data_, size_);
|
||||
data_ = new_data;
|
||||
size_ = bytes;
|
||||
expand(size_ + used_bytes);
|
||||
aligned_ptr = get_aligned_pointer(used_bytes);
|
||||
}
|
||||
|
||||
static size_t to_nearest_page_size(blt::size_t bytes) noexcept
|
||||
if (aligned_ptr == nullptr)
|
||||
throw std::bad_alloc();
|
||||
bytes_stored += used_bytes;
|
||||
return aligned_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void call_drop(blt::size_t offset)
|
||||
{
|
||||
if constexpr (detail::has_func_drop_v<T>)
|
||||
{
|
||||
constexpr static blt::size_t MASK = ~(PAGE_SIZE - 1);
|
||||
return (bytes & MASK) + PAGE_SIZE;
|
||||
from<NO_REF_T<T>>(offset).drop();
|
||||
}
|
||||
|
||||
void* get_aligned_pointer(blt::size_t bytes) noexcept
|
||||
{
|
||||
if (data_ == nullptr)
|
||||
return nullptr;
|
||||
blt::size_t remaining_bytes = remaining_bytes_in_block();
|
||||
auto* pointer = static_cast<void*>(data_ + bytes_stored);
|
||||
return std::align(MAX_ALIGNMENT, bytes, pointer, remaining_bytes);
|
||||
}
|
||||
|
||||
void* allocate_bytes_for_size(blt::size_t bytes)
|
||||
{
|
||||
auto used_bytes = aligned_size(bytes);
|
||||
auto aligned_ptr = get_aligned_pointer(used_bytes);
|
||||
if (aligned_ptr == nullptr)
|
||||
{
|
||||
expand(size_ + used_bytes);
|
||||
aligned_ptr = get_aligned_pointer(used_bytes);
|
||||
}
|
||||
if (aligned_ptr == nullptr)
|
||||
throw std::bad_alloc();
|
||||
bytes_stored += used_bytes;
|
||||
return aligned_ptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void call_drop(blt::size_t offset)
|
||||
{
|
||||
if constexpr (detail::has_func_drop_v<T>)
|
||||
{
|
||||
from<NO_REF_T<T >>(offset).drop();
|
||||
}
|
||||
}
|
||||
|
||||
blt::u8* data_ = nullptr;
|
||||
// place in the data_ array which has a free spot.
|
||||
blt::size_t bytes_stored = 0;
|
||||
blt::size_t size_ = 0;
|
||||
}
|
||||
|
||||
u8* data_ = nullptr;
|
||||
// place in the data_ array which has a free spot.
|
||||
size_t bytes_stored = 0;
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
template <size_t Size>
|
||||
struct ref_counted_type
|
||||
{
|
||||
explicit ref_counted_type(size_t* ref_count): ref_count(ref_count)
|
||||
{
|
||||
}
|
||||
|
||||
size_t* ref_count = nullptr;
|
||||
u8 storage[Size]{};
|
||||
|
||||
static size_t* access(const void* ptr)
|
||||
{
|
||||
ref_counted_type<1> type{nullptr};
|
||||
std::memcpy(&type, ptr, sizeof(size_t*));
|
||||
return type.ref_count;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_GP_STACK_H
|
||||
|
|
Loading…
Reference in New Issue