-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathConstantIndexIntList
More file actions
174 lines (146 loc) · 5.18 KB
/
ConstantIndexIntList
File metadata and controls
174 lines (146 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using Unity.Assertions;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace NSS.Data
{
/// <summary>
/// - represents an object as a list of integers that are stored from first_index until first_index + num_fields
///
/// - a constant index list -> indices dont change on removal of items, the free items
/// are reused on later inserts, they are linked together as a linked list starting at
/// free_element
///
/// - can optionally use stack from caller and expand into heap if needed
///
/// </summary>
[BurstCompatible]
public unsafe struct ConstantIndexIntList
{
const int initial_capacity = 128;
// data pointer, may point to heap
private int* data;
// Stores how many integer fields each element has.
private int num_fields;
// Stores the number of elements in the list.
private int num;
// Stores the capacity of the array.
private int cap;
// Stores an index to the free element or -1 if the free list
// is empty.
private int free_element;
private Allocator data_allocator;
public int Size => num;
/// <summary>
/// capacity in number of object == internal array capacity / num_fields
/// </summary>
public int Capacity => cap / num_fields;
public bool IsAllocated => data != null && !on_stack;
private bool on_stack;
static public ConstantIndexIntList Create(int numfields, Allocator allocator = Allocator.Temp)
{
return Create(numfields, allocator, null, 0);
}
static public ConstantIndexIntList Create(int numfields, Allocator allocator = Allocator.Temp, int* stack_ptr = null, int stack_size = 0)
{
ConstantIndexIntList l = default(ConstantIndexIntList);
l.data_allocator = allocator;
l.num = 0;
l.cap = stack_ptr == null ? initial_capacity : stack_size;
l.num_fields = numfields;
l.free_element = -1;
l.on_stack = stack_ptr != null;
l.data =
stack_ptr == null
?
(int*)UnsafeUtility.Malloc(initial_capacity * sizeof(int), 4, allocator)
:
stack_ptr;
return l;
}
public void Destroy()
{
if (IsAllocated)
{
UnsafeUtility.Free(data, data_allocator);
}
}
public void Clear()
{
num = 0;
free_element = -1;
}
public int Get(int n, int field)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
Assert.IsTrue(n >= 0 && n < num);
#endif
return data[n * num_fields + field];
}
public void Set(int n, int field, int val)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
Assert.IsTrue(n >= 0 && n < num);
#endif
data[n * num_fields + field] = val;
}
public int PushBack()
{
int new_pos = (num + 1) * num_fields;
if (new_pos > cap)
{
int new_cap = cap * 2;
if (on_stack)
{
// allocate from heap and copy segment from stack to it
int* new_data = (int*)UnsafeUtility.Malloc(new_cap * sizeof(int), 4, data_allocator);
UnsafeUtility.MemCpy(new_data, data, cap * sizeof(int));
data = new_data;
// not on stack anymore
on_stack = false;
}
else
{
// reallocate the heap buffer to the new size.
int* new_data = (int*)UnsafeUtility.Malloc(new_cap * sizeof(int), 4, data_allocator);
UnsafeUtility.MemCpy(new_data, data, cap * sizeof(int));
UnsafeUtility.Free(data, data_allocator);
data = new_data;
}
// Set the old capacity to the new capacity.
cap = new_cap;
}
int old = num;
num++;
return old;
}
public void PopBack()
{
// Just decrement the list size.
Assert.IsTrue(num > 0);
num = num - 1;
}
public int Insert()
{
// If there's a free index in the free list, pop that and use it.
if (free_element != -1)
{
int index = free_element;
int pos = index * num_fields;
// Set the free index to the next free index.
free_element = data[pos];
// Return the free index.
return index;
}
// Otherwise insert to the back of the array.
return PushBack();
}
public void Erase(int n)
{
// Push the element to the free list.
int pos = n * num_fields;
data[pos] = free_element;
free_element = n;
// note: we never decrease the size of data but instead leave a linked list of open elements
}
}
}