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 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/MemAlloc.h" 24 #include <type_traits> 25 26 namespace llvm { 27 28 /// CRTP base class providing obvious overloads for the core \c 29 /// Allocate() methods of LLVM-style allocators. 30 /// 31 /// This base class both documents the full public interface exposed by all 32 /// LLVM-style allocators, and redirects all of the overloads to a single core 33 /// set of methods which the derived class must define. 34 template <typename DerivedT> class AllocatorBase { 35 public: 36 /// Allocate \a Size bytes of \a Alignment aligned memory. This method 37 /// must be implemented by \c DerivedT. 38 void *Allocate(size_t Size, size_t Alignment) { 39 #ifdef __clang__ 40 static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>( 41 &AllocatorBase::Allocate) != 42 static_cast<void *(DerivedT::*)(size_t, size_t)>( 43 &DerivedT::Allocate), 44 "Class derives from AllocatorBase without implementing the " 45 "core Allocate(size_t, size_t) overload!"); 46 #endif 47 return static_cast<DerivedT *>(this)->Allocate(Size, Alignment); 48 } 49 50 /// Deallocate \a Ptr to \a Size bytes of memory allocated by this 51 /// allocator. 52 void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { 53 #ifdef __clang__ 54 static_assert( 55 static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>( 56 &AllocatorBase::Deallocate) != 57 static_cast<void (DerivedT::*)(const void *, size_t, size_t)>( 58 &DerivedT::Deallocate), 59 "Class derives from AllocatorBase without implementing the " 60 "core Deallocate(void *) overload!"); 61 #endif 62 return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment); 63 } 64 65 // The rest of these methods are helpers that redirect to one of the above 66 // core methods. 67 68 /// Allocate space for a sequence of objects without constructing them. 69 template <typename T> T *Allocate(size_t Num = 1) { 70 return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T))); 71 } 72 73 /// Deallocate space for a sequence of objects without constructing them. 74 template <typename T> 75 std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void> 76 Deallocate(T *Ptr, size_t Num = 1) { 77 Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T)); 78 } 79 }; 80 81 class MallocAllocator : public AllocatorBase<MallocAllocator> { 82 public: 83 void Reset() {} 84 85 LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) { 86 return allocate_buffer(Size, Alignment); 87 } 88 89 // Pull in base class overloads. 90 using AllocatorBase<MallocAllocator>::Allocate; 91 92 void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { 93 deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment); 94 } 95 96 // Pull in base class overloads. 97 using AllocatorBase<MallocAllocator>::Deallocate; 98 99 void PrintStats() const {} 100 }; 101 102 namespace detail { 103 104 template <typename Alloc> class AllocatorHolder : Alloc { 105 public: 106 AllocatorHolder() = default; 107 AllocatorHolder(const Alloc &A) : Alloc(A) {} 108 AllocatorHolder(Alloc &&A) : Alloc(static_cast<Alloc &&>(A)) {} 109 Alloc &getAllocator() { return *this; } 110 const Alloc &getAllocator() const { return *this; } 111 }; 112 113 template <typename Alloc> class AllocatorHolder<Alloc &> { 114 Alloc &A; 115 116 public: 117 AllocatorHolder(Alloc &A) : A(A) {} 118 Alloc &getAllocator() { return A; } 119 const Alloc &getAllocator() const { return A; } 120 }; 121 122 } // namespace detail 123 124 } // namespace llvm 125 126 #endif // LLVM_SUPPORT_ALLOCATORBASE_H 127