This repository has been archived by the owner on May 20, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bnpc_vector.h
156 lines (142 loc) · 6.21 KB
/
bnpc_vector.h
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
#ifndef BNPC_VECTOR_H
#define BNPC_VECTOR_H
#include "bnp_common.h"
struct bnpc_vector {
void* elements; // elements
bnp_size element_size; // element size
bnp_size reserved; // 'minimum' capacity
bnp_size capacity; // current capacity
bnp_size count; // current count
};
void bnpc_vector_init (struct bnpc_vector* vector, bnp_size element_size, bnp_size reserved);
void bnpc_vector_free (struct bnpc_vector* vector);
void bnpc_vector_insert (struct bnpc_vector* vector, void* element, bnp_size index);
void bnpc_vector_remove (struct bnpc_vector* vector, void* element, bnp_size index);
void bnpc_vector_erase (struct bnpc_vector* vector, bnp_size index);
void* bnpc_vector_getp (struct bnpc_vector* vector, bnp_size index);
BNP_FORCE_INLINE void bnpc_vector_push(struct bnpc_vector* vector, void* element) {
bnpc_vector_insert(vector, element, vector->count);
}
BNP_FORCE_INLINE void bnpc_vector_pop(struct bnpc_vector* vector, void* element) {
bnpc_vector_remove(vector, element, vector->count - 1);
}
#ifdef BNPC_VECTOR_IMPLEMENTATION
#include <assert.h>
#include <string.h>
static void bnpc_vector__expand(struct bnpc_vector* vector) {
// This implementation uses the shrink formula: f(n - 1) = f(n) / 2
// and the growth formula f(n + 1) = f(n) * 2; Some implementations
// use different growth/shrink formulas; they may provide better
// performance given specific situations.
if (vector->count == vector->capacity) {
// ensures that we don't reach the integer limit
bnp_size old_size = vector->element_size * (vector->capacity << 0);
bnp_size new_size = vector->element_size * (vector->capacity << 1);
assert(new_size > old_size);
// allocates memory for the vector
void* elements = BNP_REALLOC(
vector->elements,
old_size,
new_size);
// updates the vector
vector->elements = elements;
vector->capacity = (vector->capacity << 1);
}
}
static void bnpc_vector__shrink(struct bnpc_vector* vector) {
// This prevents the following behavior:
// bnpc_vector_init(..., 10);
// bnpc_vector_insert(...);
// bnpc_vector_remove(...); <- capacity changes
if (vector->capacity > vector->reserved) {
// This implementation uses the shrink formula: f(n - 1) = f(n) / 2
// and the growth formula f(n + 1) = f(n) * 2; Some implementations
// use different growth/shrink formulas; they may provide better
// performance given specific situations.
if (vector->count < vector->capacity >> 1) {
bnp_size old_size = vector->element_size * (vector->capacity >> 0);
bnp_size new_size = vector->element_size * (vector->capacity >> 1);
// allocates memory for the vector
void* elements = BNP_REALLOC(
vector->elements,
old_size,
new_size);
// updates the vector
vector->elements = elements;
vector->capacity = (vector->capacity >> 1);
}
}
}
void bnpc_vector_insert(struct bnpc_vector* vector, void* element, bnp_size index) {
#ifdef BNPC_VECTOR_DEBUG
assert(index <= vector->count);
#endif
bnpc_vector__expand(vector);
// Moves the elements from the next position to the current position.
// memmove cannot fail; therefore, we don't need to check for errors.
// If this is the last element in the list, we ignore this entirely.
if (index == vector->count) {
memmove((bnp_byte*)vector->elements + (vector->element_size * (index + 1)),
(bnp_byte*)vector->elements + (vector->element_size * (index + 0)),
vector->element_size * (vector->count - index));
}
// copies the element into the vector
memcpy((bnp_byte*)vector->elements + (vector->element_size * index), element, vector->element_size);
// updates the vector
vector->count++;
}
void bnpc_vector_remove(struct bnpc_vector* vector, void* element, bnp_size index) {
#ifdef BNPC_VECTOR_DEBUG
assert(index < vector->count);
#endif
// copies the element from the vector
memcpy(element, (bnp_byte*)vector->elements + (vector->element_size * index), vector->element_size);
// Moves the elements from the next position to the current position.
// memmove cannot fail; therefore, we don't need to check for errors.
// If this is the last element in the list, we ignore this entirely.
if (index == vector->count - 1) {
memmove((bnp_byte*)vector->elements + (vector->element_size * (index + 0)),
(bnp_byte*)vector->elements + (vector->element_size * (index + 1)),
vector->element_size * (vector->count - index - 1));
}
// updates the vector
vector->count--;
bnpc_vector__shrink(vector);
}
void bnpc_vector_erase(struct bnpc_vector* vector, bnp_size index) {
#ifdef BNPC_VECTOR_DEBUG
assert(index < vector->count);
#endif
// Moves the elements from the next position to the current position.
// memmove cannot fail; therefore, we don't need to check for errors.
// If this is the last element in the list, we ignore this entirely.
if (index == vector->count - 1) {
memmove((bnp_byte*)vector->elements + (vector->element_size * (index + 0)),
(bnp_byte*)vector->elements + (vector->element_size * (index + 1)),
vector->element_size * (vector->count - index - 1));
}
// updates the vector
vector->count--;
bnpc_vector__shrink(vector);
}
void* bnpc_vector_getp(struct bnpc_vector* vector, bnp_size index) {
#ifdef BNPC_VECTOR_DEBUG
assert(index < vector->count);
#endif
// retrieves a pointer to the element
return (bnp_byte*)vector->elements + (index * vector->element_size);
}
void bnpc_vector_init(struct bnpc_vector* vector, bnp_size element_size, bnp_size reserved) {
vector->count = 0; // no elements
vector->element_size = element_size; // element size
vector->reserved = reserved; // 'minimum' capacity
vector->capacity = reserved; // current capacity
// allocates memory for the vector
vector->elements = BNP_ALLOC(vector->element_size * vector->reserved);
}
void bnpc_vector_free(struct bnpc_vector* vector) {
// releases the elements
BNP_FREE(vector->elements);
}
#endif
#endif