|
2 | 2 |
|
3 | 3 | namespace Flamui;
|
4 | 4 |
|
| 5 | +//todo, implement IEnumerable |
| 6 | + |
| 7 | +/// <summary> |
| 8 | +/// Basic dynamic array on the arena |
| 9 | +/// </summary> |
| 10 | +/// <typeparam name="T"></typeparam> |
5 | 11 | public struct ArenaList<T> where T : unmanaged
|
6 | 12 | {
|
7 | 13 | private Arena? _arena;
|
8 | 14 | private Slice<T> _backingSlice;
|
| 15 | + private int _backingSliceAllocateNum; |
9 | 16 |
|
10 | 17 | public int Count;
|
11 | 18 | public int Capacity => _backingSlice.Count;
|
12 | 19 |
|
13 | 20 | public ArenaList(Arena arena, int initialCapacity)
|
14 | 21 | {
|
| 22 | + ArgumentNullException.ThrowIfNull(arena); |
| 23 | + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(initialCapacity); |
| 24 | + |
15 | 25 | _arena = arena;
|
16 | 26 | _backingSlice = _arena.AllocateSlice<T>(initialCapacity);
|
| 27 | + _backingSliceAllocateNum = _arena.AllocNum; |
17 | 28 | }
|
18 | 29 |
|
19 |
| - public void Add(T value) |
| 30 | + public unsafe void Add(T value) |
20 | 31 | {
|
21 | 32 | _arena ??= Ui.Arena;
|
22 | 33 | if (Capacity == 0) //in case the ArenaList isn't initialized via the constructor
|
23 | 34 | {
|
24 | 35 | _backingSlice = _arena.AllocateSlice<T>(1);
|
| 36 | + _backingSliceAllocateNum = _arena.AllocNum; |
25 | 37 | }
|
26 | 38 |
|
27 | 39 | Debug.Assert(Count <= Capacity);
|
28 | 40 |
|
29 | 41 | if (Count == Capacity)
|
30 | 42 | {
|
31 |
| - var newSlice = _arena.AllocateSlice<T>(Capacity * 2); |
32 |
| - _backingSlice.Span.CopyTo(newSlice.Span); |
33 |
| - _backingSlice = newSlice; |
| 43 | + //if there hasn't been another allocation on the arena, we don't need to allocate a new slice, we can just "extend" the current one |
| 44 | + |
| 45 | + //todo, this isn't really elegant or easy to understand, would be better to have a method directly on the |
| 46 | + //arena, that can tell you if a slice is at the end of the arena, and therefore allows *zero* cost resize |
| 47 | + if (_backingSliceAllocateNum == _arena.AllocNum) |
| 48 | + { |
| 49 | + _arena.AllocateSlice<T>(_backingSlice.Count); |
| 50 | + _backingSlice = new Slice<T>(_backingSlice.Items, _backingSlice.Count * 2); |
| 51 | + } |
| 52 | + else |
| 53 | + { |
| 54 | + var newSlice = _arena.AllocateSlice<T>(Capacity * 2); |
| 55 | + _backingSlice.Span.CopyTo(newSlice.Span); |
| 56 | + _backingSlice = newSlice; |
| 57 | + } |
34 | 58 | }
|
35 | 59 |
|
36 | 60 | _backingSlice[Count] = value;
|
|
0 commit comments