1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * Allocator based on $(D_PSYMBOL malloc), $(D_PSYMBOL realloc) and 7 * $(D_PSYMBOL free). 8 * 9 * Copyright: Eugene Wissner 2017-2020. 10 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 11 * Mozilla Public License, v. 2.0). 12 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 13 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/middle/tanya/memory/mallocator.d, 14 * tanya/memory/mallocator.d) 15 */ 16 module tanya.memory.mallocator; 17 18 import core.stdc.stdlib; 19 import tanya.memory.allocator; 20 21 /** 22 * Wrapper for $(D_PSYMBOL malloc)/$(D_PSYMBOL realloc)/$(D_PSYMBOL free) from 23 * the C standard library. 24 */ 25 final class Mallocator : Allocator 26 { 27 private alias MallocType = extern (C) void* function(size_t) 28 @nogc nothrow pure @system; 29 private alias FreeType = extern (C) void function(void*) 30 @nogc nothrow pure @system; 31 private alias ReallocType = extern (C) void* function(void*, size_t) 32 @nogc nothrow pure @system; 33 34 /** 35 * Allocates $(D_PARAM size) bytes of memory. 36 * 37 * Params: 38 * size = Amount of memory to allocate. 39 * 40 * Returns: The pointer to the new allocated memory. 41 */ 42 void[] allocate(size_t size) @nogc nothrow pure shared @system 43 { 44 if (size == 0) 45 { 46 return null; 47 } 48 auto p = (cast(MallocType) &malloc)(size + psize); 49 50 return p is null ? null : p[psize .. psize + size]; 51 } 52 53 /// 54 @nogc nothrow pure @system unittest 55 { 56 auto p = Mallocator.instance.allocate(20); 57 assert(p.length == 20); 58 Mallocator.instance.deallocate(p); 59 60 p = Mallocator.instance.allocate(0); 61 assert(p.length == 0); 62 } 63 64 /** 65 * Deallocates a memory block. 66 * 67 * Params: 68 * p = A pointer to the memory block to be freed. 69 * 70 * Returns: Whether the deallocation was successful. 71 */ 72 bool deallocate(void[] p) @nogc nothrow pure shared @system 73 { 74 if (p !is null) 75 { 76 (cast(FreeType) &free)(p.ptr - psize); 77 } 78 return true; 79 } 80 81 /// 82 @nogc nothrow pure @system unittest 83 { 84 void[] p; 85 assert(Mallocator.instance.deallocate(p)); 86 87 p = Mallocator.instance.allocate(10); 88 assert(Mallocator.instance.deallocate(p)); 89 } 90 91 /** 92 * Reallocating in place isn't supported. 93 * 94 * Params: 95 * p = A pointer to the memory block. 96 * size = Size of the reallocated block. 97 * 98 * Returns: $(D_KEYWORD false). 99 */ 100 bool reallocateInPlace(ref void[] p, size_t size) 101 @nogc nothrow pure shared @system 102 { 103 cast(void) size; 104 return false; 105 } 106 107 /// 108 @nogc nothrow pure @system unittest 109 { 110 void[] p; 111 assert(!Mallocator.instance.reallocateInPlace(p, 8)); 112 } 113 114 /** 115 * Increases or decreases the size of a memory block. 116 * 117 * Params: 118 * p = A pointer to the memory block. 119 * size = Size of the reallocated block. 120 * 121 * Returns: Whether the reallocation was successful. 122 */ 123 bool reallocate(ref void[] p, size_t size) 124 @nogc nothrow pure shared @system 125 { 126 if (size == 0) 127 { 128 if (deallocate(p)) 129 { 130 p = null; 131 return true; 132 } 133 } 134 else if (p is null) 135 { 136 p = allocate(size); 137 return p is null ? false : true; 138 } 139 else 140 { 141 auto r = (cast(ReallocType) &realloc)(p.ptr - psize, size + psize); 142 143 if (r !is null) 144 { 145 p = r[psize .. psize + size]; 146 return true; 147 } 148 } 149 return false; 150 } 151 152 /// 153 @nogc nothrow pure @system unittest 154 { 155 void[] p; 156 157 assert(Mallocator.instance.reallocate(p, 20)); 158 assert(p.length == 20); 159 160 assert(Mallocator.instance.reallocate(p, 30)); 161 assert(p.length == 30); 162 163 assert(Mallocator.instance.reallocate(p, 10)); 164 assert(p.length == 10); 165 166 assert(Mallocator.instance.reallocate(p, 0)); 167 assert(p is null); 168 } 169 170 /** 171 * Returns: The alignment offered. 172 */ 173 @property uint alignment() const @nogc nothrow pure @safe shared 174 { 175 return (void*).alignof; 176 } 177 178 static private shared(Mallocator) instantiate() @nogc nothrow @system 179 { 180 if (instance_ is null) 181 { 182 const size = __traits(classInstanceSize, Mallocator) + psize; 183 void* p = malloc(size); 184 185 if (p !is null) 186 { 187 p[psize .. size] = typeid(Mallocator).initializer[]; 188 instance_ = cast(shared Mallocator) p[psize .. size].ptr; 189 } 190 } 191 return instance_; 192 } 193 194 /** 195 * Static allocator instance and initializer. 196 * 197 * Returns: The global $(D_PSYMBOL Allocator) instance. 198 */ 199 static @property shared(Mallocator) instance() @nogc nothrow pure @system 200 { 201 return (cast(GetPureInstance!Mallocator) &instantiate)(); 202 } 203 204 /// 205 @nogc nothrow pure @system unittest 206 { 207 assert(instance is instance); 208 } 209 210 private enum ushort psize = 8; 211 212 private shared static Mallocator instance_; 213 }