1 //===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// 10 /// This file defines MallocAllocator. MallocAllocator conforms to the LLVM 11 /// "Allocator" concept which consists of an Allocate method accepting a size 12 /// and alignment, and a Deallocate accepting a pointer and size. Further, the 13 /// LLVM "Allocator" concept has overloads of Allocate and Deallocate for 14 /// setting size and alignment based on the final type. These overloads are 15 /// typically provided by a base class template \c AllocatorBase. 16 /// 17 //===----------------------------------------------------------------------===// 18 19 #ifndef LLVM_SUPPORT_ALLOCATORBASE_H 20 #define LLVM_SUPPORT_ALLOCATORBASE_H 21 22 #ifdef _MSC_VER 23 #define LLVM_ALLOCATORHOLDER_EMPTYBASE __declspec(empty_bases) 24 #else 25 #define LLVM_ALLOCATORHOLDER_EMPTYBASE 26 #endif // _MSC_VER 27 28 #include "llvm/Support/Compiler.h" 29 #include "llvm/Support/MemAlloc.h" 30 #include <type_traits> 31 32 namespace llvm { 33 34 /// CRTP base class providing obvious overloads for the core \c 35 /// Allocate() methods of LLVM-style allocators. 36 /// 37 /// This base class both documents the full public interface exposed by all 38 /// LLVM-style allocators, and redirects all of the overloads to a single core 39 /// set of methods which the derived class must define. 40 template <typename DerivedT> class AllocatorBase { 41 public: 42 /// Allocate \a Size bytes of \a Alignment aligned memory. This method 43 /// must be implemented by \c DerivedT. Allocate(size_t Size,size_t Alignment)44 void *Allocate(size_t Size, size_t Alignment) { 45 #ifdef __clang__ 46 static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>( 47 &AllocatorBase::Allocate) != 48 static_cast<void *(DerivedT::*)(size_t, size_t)>( 49 &DerivedT::Allocate), 50 "Class derives from AllocatorBase without implementing the " 51 "core Allocate(size_t, size_t) overload!"); 52 #endif 53 return static_cast<DerivedT *>(this)->Allocate(Size, Alignment); 54 } 55 56 /// Deallocate \a Ptr to \a Size bytes of memory allocated by this 57 /// allocator. Deallocate(const void * Ptr,size_t Size,size_t Alignment)58 void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { 59 #ifdef __clang__ 60 static_assert( 61 static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>( 62 &AllocatorBase::Deallocate) != 63 static_cast<void (DerivedT::*)(const void *, size_t, size_t)>( 64 &DerivedT::Deallocate), 65 "Class derives from AllocatorBase without implementing the " 66 "core Deallocate(void *) overload!"); 67 #endif 68 return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment); 69 } 70 71 // The rest of these methods are helpers that redirect to one of the above 72 // core methods. 73 74 /// Allocate space for a sequence of objects without constructing them. 75 template <typename T> T *Allocate(size_t Num = 1) { 76 return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T))); 77 } 78 79 /// Deallocate space for a sequence of objects without constructing them. 80 template <typename T> 81 std::enable_if_t<!std::is_same_v<std::remove_cv_t<T>, void>, void> 82 Deallocate(T *Ptr, size_t Num = 1) { 83 Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T)); 84 } 85 }; 86 87 class MallocAllocator : public AllocatorBase<MallocAllocator> { 88 public: Reset()89 void Reset() {} 90 Allocate(size_t Size,size_t Alignment)91 LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) { 92 return allocate_buffer(Size, Alignment); 93 } 94 95 // Pull in base class overloads. 96 using AllocatorBase<MallocAllocator>::Allocate; 97 Deallocate(const void * Ptr,size_t Size,size_t Alignment)98 void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { 99 deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment); 100 } 101 102 // Pull in base class overloads. 103 using AllocatorBase<MallocAllocator>::Deallocate; 104 PrintStats()105 void PrintStats() const {} 106 }; 107 108 namespace detail { 109 110 template <typename Alloc> class AllocatorHolder : Alloc { 111 public: 112 AllocatorHolder() = default; AllocatorHolder(const Alloc & A)113 AllocatorHolder(const Alloc &A) : Alloc(A) {} AllocatorHolder(Alloc && A)114 AllocatorHolder(Alloc &&A) : Alloc(static_cast<Alloc &&>(A)) {} getAllocator()115 Alloc &getAllocator() { return *this; } getAllocator()116 const Alloc &getAllocator() const { return *this; } 117 }; 118 119 template <typename Alloc> class AllocatorHolder<Alloc &> { 120 Alloc &A; 121 122 public: AllocatorHolder(Alloc & A)123 AllocatorHolder(Alloc &A) : A(A) {} getAllocator()124 Alloc &getAllocator() { return A; } getAllocator()125 const Alloc &getAllocator() const { return A; } 126 }; 127 128 } // namespace detail 129 130 } // namespace llvm 131 132 #endif // LLVM_SUPPORT_ALLOCATORBASE_H 133