1 /** 2 Memory pool for component storage. 3 4 Copyright: © 2015-2016 Claude Merle 5 Authors: Claude Merle 6 License: This file is part of EntitySysD. 7 8 EntitySysD is free software: you can redistribute it and/or modify it 9 under the terms of the Lesser GNU General Public License as published 10 by the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 EntitySysD is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 Lesser GNU General Public License for more details. 17 18 You should have received a copy of the Lesser GNU General Public License 19 along with EntitySysD. If not, see $(LINK http://www.gnu.org/licenses/). 20 */ 21 22 module entitysysd.pool; 23 24 25 template hasConst(C) 26 { 27 import std.meta : anySatisfy; 28 import std.traits : RepresentationTypeTuple; 29 30 enum bool isConst(F) = is(F == const); 31 enum bool hasConst = anySatisfy!(isConst, RepresentationTypeTuple!C); 32 } 33 34 class BasePool 35 { 36 public: 37 this(size_t elementSize, size_t chunkSize) 38 { 39 mElementSize = elementSize; 40 mChunkSize = chunkSize; 41 } 42 43 void accomodate(in size_t nbElements) 44 { 45 while (nbElements > mMaxElements) 46 { 47 mNbChunks++; 48 mMaxElements = (mNbChunks * mChunkSize) / mElementSize; 49 } 50 51 if (mData.length < mNbChunks * mChunkSize) 52 mData.length = mNbChunks * mChunkSize; 53 mNbElements = nbElements; 54 } 55 56 size_t nbElements() @property 57 { 58 return mNbElements; 59 } 60 61 size_t nbChunks() @property 62 { 63 return mNbChunks; 64 } 65 66 void* getPtr(size_t n) 67 { 68 if (n >= mNbElements) 69 return null; 70 size_t offset = n * mElementSize; 71 return &mData[offset]; 72 } 73 74 private: 75 size_t mElementSize; 76 size_t mChunkSize; 77 size_t mNbChunks; 78 size_t mMaxElements; 79 size_t mNbElements; 80 void[] mData; 81 } 82 83 class Pool(T, size_t ChunkSize = 8192) : BasePool 84 { 85 this(in size_t n) 86 { 87 super(T.sizeof, ChunkSize); 88 accomodate(n); 89 } 90 91 ref T opIndex(size_t n) 92 { 93 return *cast(T*)getPtr(n); 94 } 95 96 static if (!hasConst!T) 97 { 98 T opIndexAssign(T t, size_t n) 99 { 100 *cast(T*)getPtr(n) = t; 101 return t; 102 } 103 } 104 105 void initN(size_t n) 106 { 107 import std.conv : emplace; 108 emplace(&this[n]); 109 } 110 } 111 112 113 //****************************************************************************** 114 //***** UNIT-TESTS 115 //****************************************************************************** 116 unittest 117 { 118 static struct TestComponent 119 { 120 int i; 121 string s; 122 } 123 124 auto pool0 = new Pool!TestComponent(5); 125 auto pool1 = new Pool!ulong(2000); 126 127 assert(pool0.nbChunks == 1); 128 assert(pool1.nbChunks == (2000 * ulong.sizeof + 8191) / 8192); 129 assert(pool1.getPtr(1) !is null); 130 assert(pool0.getPtr(5) is null); 131 132 pool0[0].i = 10; pool0[0].s = "hello"; 133 pool0[3] = TestComponent(5, "world"); 134 135 assert(pool0[0].i == 10 && pool0[0].s == "hello"); 136 assert(pool0[1].i == 0 && pool0[1].s is null); 137 assert(pool0[2].i == 0 && pool0[2].s is null); 138 assert(pool0[3].i == 5 && pool0[3].s == "world"); 139 assert(pool0[4].i == 0 && pool0[4].s is null); 140 141 pool1[1999] = 325; 142 assert(pool1[1999] == 325); 143 }