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 private: 67 size_t mElementSize; 68 size_t mChunkSize; 69 size_t mNbChunks; 70 size_t mMaxElements; 71 size_t mNbElements; 72 ubyte[] mData; 73 } 74 75 class Pool(T, size_t ChunkSize = 8192) : BasePool 76 { 77 this(in size_t n) 78 { 79 super(T.sizeof, ChunkSize); 80 accomodate(n); 81 } 82 83 ref T opIndex(size_t n) 84 { 85 return *getPtr(n); 86 } 87 88 static if (!hasConst!T) 89 { 90 T opIndexAssign(T t, size_t n) 91 { 92 *getPtr(n) = t; 93 return t; 94 } 95 } 96 97 void initN(size_t n) 98 { 99 import std.conv : emplace; 100 emplace(getPtr(n)); 101 } 102 103 T* getPtr(in size_t n) 104 { 105 if (n >= mNbElements) 106 return null; 107 size_t offset = n * mElementSize; 108 return cast(T*)&mData[offset]; 109 } 110 111 T* ptr() @property 112 { 113 return cast(T*)mData.ptr; 114 } 115 116 } 117 118 119 //****************************************************************************** 120 //***** UNIT-TESTS 121 //****************************************************************************** 122 unittest 123 { 124 static struct TestComponent 125 { 126 int i; 127 string s; 128 } 129 130 auto pool0 = new Pool!TestComponent(5); 131 auto pool1 = new Pool!ulong(2000); 132 133 assert(pool0.nbChunks == 1); 134 assert(pool1.nbChunks == (2000 * ulong.sizeof + 8191) / 8192); 135 assert(pool1.getPtr(1) !is null); 136 assert(pool0.getPtr(5) is null); 137 138 pool0[0].i = 10; pool0[0].s = "hello"; 139 pool0[3] = TestComponent(5, "world"); 140 141 assert(pool0[0].i == 10 && pool0[0].s == "hello"); 142 assert(pool0[1].i == 0 && pool0[1].s is null); 143 assert(pool0[2].i == 0 && pool0[2].s is null); 144 assert(pool0[3].i == 5 && pool0[3].s == "world"); 145 assert(pool0[4].i == 0 && pool0[4].s is null); 146 147 pool1[1999] = 325; 148 assert(pool1[1999] == 325); 149 150 }