91 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			3.0 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:
 | |
|     AllocatorDeleter() = default;
 | |
|     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(std::allocator<TOther>) noexcept {}
 | |
| 
 | |
|     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)
 |