1 /* 2 Copyright (c) 2015 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 // dimage is actually stripped out part of dlib - just to support reading PNG and JPEG 30 module dimage.memory;//dlib.core.memory 31 32 import std.stdio; 33 import std.conv; 34 import std.traits; 35 import core.stdc.stdlib; 36 import core.exception: onOutOfMemoryError; 37 38 /* 39 * Tools for manual memory management 40 */ 41 42 //version = MemoryDebug; 43 44 private static size_t _allocatedMemory = 0; 45 46 version(MemoryDebug) 47 { 48 import std.datetime; 49 import std.algorithm; 50 51 struct AllocationRecord 52 { 53 string type; 54 size_t size; 55 ulong id; 56 bool deleted; 57 } 58 59 AllocationRecord[ulong] records; 60 ulong counter = 0; 61 62 void addRecord(void* p, string type, size_t size) 63 { 64 records[cast(ulong)p] = AllocationRecord(type, size, counter, false); 65 counter++; 66 //writefln("Allocated %s (%s bytes)", type, size); 67 } 68 69 void markDeleted(void* p) 70 { 71 ulong k = cast(ulong)p - psize; 72 //string type = records[k].type; 73 //size_t size = records[k].size; 74 records[k].deleted = true; 75 //writefln("Dellocated %s (%s bytes)", type, size); 76 } 77 78 void printMemoryLog() 79 { 80 writeln("----------------------------------------------------"); 81 writeln(" Memory allocation log "); 82 writeln("----------------------------------------------------"); 83 auto keys = records.keys; 84 sort!((a, b) => records[a].id < records[b].id)(keys); 85 foreach(k; keys) 86 { 87 AllocationRecord r = records[k]; 88 if (r.deleted) 89 writefln(" %s - %s byte(s) at %X", r.type, r.size, k); 90 else 91 writefln("REMAINS: %s - %s byte(s) at %X", r.type, r.size, k); 92 } 93 writeln("----------------------------------------------------"); 94 writefln("Total amount of allocated memory: %s", _allocatedMemory); 95 writeln("----------------------------------------------------"); 96 } 97 } 98 else 99 { 100 void printMemoryLog() {} 101 } 102 103 size_t allocatedMemory() 104 { 105 return _allocatedMemory; 106 } 107 108 interface Freeable 109 { 110 void free(); 111 } 112 113 enum psize = 8; 114 115 T allocate(T, A...) (A args) if (is(T == class)) 116 { 117 enum size = __traits(classInstanceSize, T); 118 void* p = malloc(size+psize); 119 if (!p) 120 onOutOfMemoryError(); 121 auto memory = p[psize..psize+size]; 122 *cast(size_t*)p = size; 123 _allocatedMemory += size; 124 version(MemoryDebug) 125 { 126 addRecord(p, T.stringof, size); 127 } 128 auto res = emplace!(T, A)(memory, args); 129 return res; 130 } 131 132 T* allocate(T, A...) (A args) if (is(T == struct)) 133 { 134 enum size = T.sizeof; 135 void* p = malloc(size+psize); 136 if (!p) 137 onOutOfMemoryError(); 138 auto memory = p[psize..psize+size]; 139 *cast(size_t*)p = size; 140 _allocatedMemory += size; 141 version(MemoryDebug) 142 { 143 addRecord(p, T.stringof, size); 144 } 145 return emplace!(T, A)(memory, args); 146 } 147 148 T allocate(T) (size_t length) if (isArray!T) 149 { 150 alias AT = ForeachType!T; 151 size_t size = length * AT.sizeof; 152 auto mem = malloc(size+psize); 153 if (!mem) 154 onOutOfMemoryError(); 155 T arr = cast(T)mem[psize..psize+size]; 156 foreach(ref v; arr) 157 v = v.init; 158 *cast(size_t*)mem = size; 159 _allocatedMemory += size; 160 version(MemoryDebug) 161 { 162 addRecord(mem, T.stringof, size); 163 } 164 return arr; 165 } 166 167 void deallocate(T)(ref T obj) if (isArray!T) 168 { 169 void* p = cast(void*)obj.ptr; 170 size_t size = *cast(size_t*)(p - psize); 171 free(p - psize); 172 _allocatedMemory -= size; 173 version(MemoryDebug) 174 { 175 markDeleted(p); 176 } 177 obj.length = 0; 178 } 179 180 void deallocate(T)(T obj) if (is(T == class) || is(T == interface)) 181 { 182 Object o = cast(Object)obj; 183 void* p = cast(void*)o; 184 size_t size = *cast(size_t*)(p - psize); 185 destroy(obj); 186 free(p - psize); 187 _allocatedMemory -= size; 188 version(MemoryDebug) 189 { 190 markDeleted(p); 191 } 192 } 193 194 void deallocate(T)(T* obj) 195 { 196 void* p = cast(void*)obj; 197 size_t size = *cast(size_t*)(p - psize); 198 destroy(obj); 199 free(p - psize); 200 _allocatedMemory -= size; 201 version(MemoryDebug) 202 { 203 markDeleted(p); 204 } 205 } 206 207 alias allocate New; 208 alias deallocate Delete;