1 /* 2 * Copyright (C) 2020, 2021 Vladimir Panteleev <btdu@cy.md> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 /// Memory allocation 20 module btdu.alloc; 21 22 import core.exception : onOutOfMemoryError; 23 24 import std.algorithm.comparison : max; 25 import std.experimental.allocator.building_blocks.allocator_list; 26 import std.experimental.allocator.building_blocks.null_allocator; 27 import std.experimental.allocator.building_blocks.region; 28 import std.experimental.allocator.mallocator; 29 import std.experimental.allocator.mmap_allocator; 30 import std.experimental.allocator; 31 32 /// Allocator to use for objects with infinite lifetime, which will never be freed. 33 alias GrowAllocator = AllocatorList!((n) => Region!MmapAllocator(max(n, 1024 * 4096)), NullAllocator); 34 CheckedAllocator!GrowAllocator growAllocator; 35 36 /// Casual allocator which supports deallocation. 37 alias CasualAllocator = CheckedAllocator!Mallocator; 38 39 /// Wrapper allocator which calls a function when memory allocation fails. 40 /// Because downstream code doesn't check for nulls, this allows better error messages 41 /// should btdu run out of memory. (Mainly this is useful for testing and profiling.) 42 struct CheckedAllocator(ParentAllocator, alias onFail = onOutOfMemoryError) 43 { 44 import std.traits : hasMember; 45 import std.typecons : Ternary; 46 47 static if (stateSize!ParentAllocator) 48 ParentAllocator parent; 49 else 50 { 51 alias parent = ParentAllocator.instance; 52 static CheckedAllocator instance; 53 } 54 55 private T check(T)(T value) { if (!value) onFail(); return value; } 56 57 void[] allocate(size_t n) { return check(parent.allocate(n)); } 58 bool reallocate(ref void[] b, size_t s) { return check(parent.reallocate(b, s)); } 59 60 // Note: we can't use `alias this` because we need to intercept allocateZeroed, 61 // but we can't do that because it's package(std). 62 63 enum alignment = ParentAllocator.alignment; 64 65 size_t goodAllocSize(size_t n) { return parent.goodAllocSize(n); } 66 67 static if (hasMember!(ParentAllocator, "expand")) 68 bool expand(ref void[] b, size_t delta) { return parent.expand(b, delta); } 69 70 static if (hasMember!(ParentAllocator, "owns")) 71 Ternary owns(void[] b) { return parent.owns(b); } 72 73 static if (hasMember!(ParentAllocator, "deallocate")) 74 bool deallocate(void[] b) { return parent.deallocate(b); } 75 76 static if (hasMember!(ParentAllocator, "deallocateAll")) 77 bool deallocateAll() { return parent.deallocateAll(); } 78 79 static if (hasMember!(ParentAllocator, "empty")) 80 pure nothrow @safe @nogc Ternary empty() const { return parent.empty; } 81 }