1 // Written in the D programming language. 2 /** 3 This module provides high-level interface for mi-mallocator 4 Copyright: Copyright 2019 Ernesto Castellotti <erny.castell@gmail.com> 5 License: $(HTTP https://www.mozilla.org/en-US/MPL/2.0/, Mozilla Public License - Version 2.0). 6 Authors: $(HTTP github.com/ErnyTech, Ernesto Castellotti) 7 */ 8 module neomimalloc.mimallocator; 9 10 /** 11 * High-level interface for mimalloc. 12 */ 13 struct Mimallocator { 14 import std.experimental.allocator.common : platformAlignment; 15 import std.typecons : Ternary; 16 17 /** 18 * Returns the global instance of this allocator type. 19 * Mimallocator is thread-safe, all methods are shared. 20 */ 21 static shared Mimallocator instance; 22 23 /** 24 * The alignment is a static constant equal to `platformAlignment`, which 25 * ensures proper alignment for any D data type. 26 */ 27 enum uint alignment = platformAlignment; 28 29 /** 30 * Return the memory size that will be allocated asking for the minimum required size. 31 * 32 * Params: 33 * size = The minimal required size in bytes. 34 * 35 * Returns: 36 * the size n that will be allocated, where n >= size. 37 */ 38 @trusted @nogc nothrow size_t goodAllocSize(size_t size) shared { 39 import neomimalloc.c.mimalloc : mi_good_size; 40 41 return mi_good_size(size); 42 } 43 44 /** 45 * Allocates the size expressed in bytes. 46 * 47 * Params: 48 * bytes = Number of bytes to allocate. 49 * 50 * Returns: 51 * An array with allocated memory or null if out of memory. Returns null if called with size 0. 52 */ 53 @trusted @nogc pure nothrow void[] allocate(size_t bytes) shared { 54 import neomimalloc.c.mimalloc : mi_malloc; 55 56 if (bytes == 0) { 57 return null; 58 } 59 60 auto p = mi_malloc(bytes); 61 return p ? p[0 .. bytes] : null; 62 } 63 64 /** 65 * Allocates the size expressed in bytes aligned by alignment. 66 * 67 * Params: 68 * bytes = Number of bytes to allocate. 69 * alignment = the minimal alignment of the allocated memory. 70 * 71 * Returns: 72 * An array with aligned allocated memory or null if out of memory. Returns null if called with size 0. 73 */ 74 @trusted @nogc pure nothrow void[] alignedAllocate(size_t bytes, uint alignment) shared { 75 import neomimalloc.c.mimalloc : mi_malloc_aligned; 76 77 if (bytes == 0) { 78 return null; 79 } 80 81 auto p = mi_malloc_aligned(bytes, alignment); 82 return p ? p[0 .. bytes] : null; 83 } 84 85 /** 86 * Expands the array by increasing its length with the required delta. 87 * 88 * Params: 89 * b = The array to be expanded (old size + delta). 90 * delta = The dimension to be increased. 91 * 92 * Returns: 93 * true if the expansion was successful, false if the array is null or the allocator has failed. 94 */ 95 @system @nogc pure nothrow bool expand(ref void[] b, size_t delta) shared { 96 import neomimalloc.c.mimalloc : mi_expand; 97 98 if (delta == 0) { 99 return true; 100 } 101 102 if (b is null) { 103 return false; 104 } 105 106 auto newSize = b.length + delta; 107 auto p = cast(ubyte*) mi_expand(b.ptr, newSize); 108 109 if (!p) { 110 return false; 111 } 112 113 b = p[0 .. newSize]; 114 return true; 115 } 116 117 /** 118 * Re-allocate memory to newsize bytes. 119 * 120 * Params: 121 * b = The array to be reallocated. 122 * newSize = The new size that the array will take. 123 * 124 * Returns: 125 * true if the reallocatiom was successful, false if the allocator has failed. 126 */ 127 @system @nogc pure nothrow bool reallocate(ref void[] b, size_t newSize) shared { 128 import neomimalloc.c.mimalloc : mi_realloc; 129 130 auto p = cast(ubyte*) mi_realloc(b.ptr, newSize); 131 132 if (!p) { 133 return false; 134 } 135 136 b = p[0 .. newSize]; 137 return true; 138 } 139 140 /** 141 * Re-allocate memory to newsize bytes aligned by alignment. 142 * 143 * Params: 144 * b = The array to be reallocated. 145 * newSize = The new size that the array will take. 146 * alignment = The minimal alignment of the allocated memory. 147 * 148 * Returns: 149 * true if the reallocatiom was successful, false if the allocator has failed 150 */ 151 @system @nogc pure nothrow bool alignedReallocate(ref void[] b, size_t newSize, uint alignment) shared { 152 import neomimalloc.c.mimalloc : mi_realloc_aligned; 153 154 auto p = cast(ubyte*) mi_realloc_aligned(b.ptr, newSize, alignment); 155 156 if (!p) { 157 return false; 158 } 159 160 b = p[0 .. newSize]; 161 return true; 162 } 163 164 /** 165 * Checks if the memory has been allocated by this allocator. 166 * 167 * Params: 168 * b = The array to be verified. 169 * 170 * Returns: 171 * Ternary.yes if the memory has been allocated by this allocator or Ternary.no if the memory is managed to other allocators. 172 */ 173 @trusted @nogc pure nothrow Ternary owns(const void[] b) shared { 174 auto result = implIsOwn(b.ptr); 175 176 if (result) { 177 return Ternary.yes; 178 } else { 179 return Ternary.no; 180 } 181 } 182 183 /** 184 * Resolves a pointer to get the full memory block. 185 * 186 * Params: 187 * p = The pointer to resolve. 188 * result = The array with the full memory block. 189 * 190 * Returns: 191 * Ternary.no if the memory is managed to other allocators otherwise Ternary.yes. 192 */ 193 @trusted @nogc pure nothrow Ternary resolveInternalPointer(const void* p, ref void[] result) shared { 194 import neomimalloc.c.mimalloc : mi_check_owned; 195 import neomimalloc.c.mimalloc : mi_usable_size; 196 197 auto pIsOwn = implIsOwn(p); 198 199 if (!pIsOwn) { 200 result = null; 201 return Ternary.no; 202 } 203 204 auto sizeOfP = mi_usable_size(p); 205 result = (cast(void*) p)[0 .. sizeOfP]; 206 return Ternary.yes; 207 } 208 209 /** 210 * Deallocate the specified memory block 211 * 212 * Params: 213 * b = The memory block to be deallocated. 214 * 215 * Returns: 216 * false if the array is null, otherwise true. 217 */ 218 @system @nogc pure nothrow bool deallocate(void[] b) shared { 219 import neomimalloc.c.mimalloc : mi_free; 220 221 if (b is null) { 222 return true; 223 } 224 225 mi_free(b.ptr); 226 return true; 227 } 228 229 private @trusted @nogc pure nothrow bool implIsOwn(const void* p) shared { 230 import neomimalloc.c.mimalloc : mi_check_owned; 231 232 if (!p) { 233 return false; 234 } 235 236 return mi_check_owned(p); 237 } 238 }