1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity low)
4 module dil.ChunkAllocator;
5 
6 import dil.Array;
7 
8 /// Custom non-GC allocator for managing a list of chunks.
9 struct ChunkAllocator
10 {
11   Array chunks; /// List of memory chunks, getting larger progressively.
12 
13   /// Constructs a ChunkAllocator.
14   this(size_t size)
15   {
16     initialize(size);
17   }
18 
19   /// Initializes with one chunk.
20   void initialize(size_t size)
21   {
22     chunks.cap = 10; // Reserve space for 10 chunks.
23     chunks ~= Array(size);
24   }
25 
26   /// Returns chunk number n.
27   Array* lastChunk()
28   {
29     auto chunks = chunks.elems!(Array[]);
30     return chunks.ptr + chunks.length - 1;
31     //return &((chunks.elems!(Array[]))[$-1]);
32   }
33 
34   /// Adds a new chunk to the list and returns it.
35   Array* newChunk()
36   {
37     auto cap = lastChunk().cap;
38     cap = (cap << 1) - (cap >> 1); // cap *= 1.5;
39     cap += PAGESIZE - cap % PAGESIZE; // Round up to PAGESIZE.
40     chunks ~= Array(cap);
41     return lastChunk();
42   }
43 
44   /// Returns a chunk that can hold another n bytes.
45   Array* getChunk(size_t n)
46   {
47     auto a = lastChunk();
48     if (n > a.rem) // Do n bytes fit in?
49       a = newChunk();
50     return a;
51   }
52 
53   /// Returns a pointer to an array of size n bytes.
54   void* allocate(size_t n)
55   {
56     auto a = getChunk(n);
57     auto p = a.cur;
58     a.cur += n;
59     return p;
60   }
61 
62   /// Frees all the allocated memory.
63   void destroy()
64   {
65     foreach (ref a; chunks.elems!(Array[]))
66       a.destroy();
67     chunks.destroy();
68   }
69 }