mijin2/source/mijin/memory/memutil.hpp

86 lines
2.8 KiB
C++

#pragma once
#if !defined(MIJIN_MEMORY_MEMUTIL_HPP_INCLUDED)
#define MIJIN_MEMORY_MEMUTIL_HPP_INCLUDED 1
#include <memory>
#include "../internal/common.hpp"
namespace mijin
{
template<typename TAllocator>
class AllocatorDeleter
{
public:
using value_type = std::allocator_traits<TAllocator>::value_type;
using pointer = std::allocator_traits<TAllocator>::pointer;
private:
[[no_unique_address]] TAllocator allocator_;
public:
explicit AllocatorDeleter(TAllocator allocator = {}) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<TAllocator>)
: allocator_(std::move(allocator)) {}
template<typename TOtherAllocator> requires (std::is_constructible_v<TAllocator, const TOtherAllocator&>)
AllocatorDeleter(const AllocatorDeleter<TOtherAllocator>& other)
MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<TAllocator, TOtherAllocator>))
: allocator_(other.allocator_) {}
template<typename TOtherAllocator> requires (std::is_constructible_v<TAllocator, TOtherAllocator&&>)
AllocatorDeleter(AllocatorDeleter<TOtherAllocator>&& other)
MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<TAllocator, TOtherAllocator&&>))
: allocator_(std::move(other.allocator_)) {}
template<typename TOtherAllocator> requires (std::is_assignable_v<TAllocator&, const TOtherAllocator&>)
AllocatorDeleter& operator=(const AllocatorDeleter<TOtherAllocator>& other)
MIJIN_NOEXCEPT_IF((std::is_nothrow_assignable_v<TAllocator&, const TOtherAllocator&>))
{
if (this != static_cast<const void*>(&other))
{
allocator_ = other.allocator_;
}
return *this;
}
template<typename TOtherAllocator> requires (std::is_assignable_v<TAllocator&, TOtherAllocator&&>)
AllocatorDeleter& operator=(AllocatorDeleter<TOtherAllocator>&& other)
MIJIN_NOEXCEPT_IF((std::is_nothrow_assignable_v<TAllocator&, TOtherAllocator&&>))
{
if (this != static_cast<const void*>(&other))
{
allocator_ = std::move(other.allocator_);
}
return *this;
}
void operator()(pointer ptr) MIJIN_NOEXCEPT_IF(noexcept(allocator_.deallocate(ptr, sizeof(value_type))))
{
allocator_.deallocate(ptr, sizeof(value_type));
}
template<typename TOtherAllocator>
friend class AllocatorDeleter;
};
template<typename T>
class AllocatorDeleter<std::allocator<T>>
{
public:
AllocatorDeleter() noexcept = default;
template<typename TOther>
AllocatorDeleter(const AllocatorDeleter<std::allocator<TOther>>&) noexcept {}
template<typename TOther>
AllocatorDeleter& operator=(const AllocatorDeleter<std::allocator<TOther>>&) noexcept { return *this; }
void operator()(T* ptr) const MIJIN_NOEXCEPT
{
delete ptr;
}
};
} // namespace mijin
#endif // !defined(MIJIN_MEMORY_MEMUTIL_HPP_INCLUDED)