You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+91-15Lines changed: 91 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,7 @@
1
1
# C Vector Library
2
-
A simple vector library for C. This library's vectors work in a similar manner to C++ vectors: they can store any type, their elements can be accessed via the `[]` operator, and elements may be added or removed with simple library calls.
2
+
3
+
A simple vector library for C. This library's vectors work in a similar manner to C++ vectors: they can store any type,
4
+
their elements can be accessed via the `[]` operator, and elements may be added or removed with simple library calls.
3
5
4
6
You can easily create a vector like so:
5
7
@@ -32,7 +34,9 @@ vector_add(&char_vec, 'a');
32
34
printf("first item: %c\n", char_vec[0]);
33
35
```
34
36
35
-
Vectors require that their pointer type corresponds to the contents of the vector (e.g. `int*` for a vector containing `int`s); otherwise, you have to explicitly cast the vector pointer to the correct type when accessing elements or making library calls:
37
+
Vectors require that their pointer type corresponds to the contents of the vector (e.g. `int*` for a vector containing
38
+
`int`s); otherwise, you have to explicitly cast the vector pointer to the correct type when accessing elements or making
39
+
library calls:
36
40
37
41
```c
38
42
// recommended vector use
@@ -51,13 +55,16 @@ vector_add(&(int*)bar, 3);
51
55
52
56
((int*)bar)[0] = 5; // we have to cast to an int* so we can properly access vector elements
53
57
```
58
+
54
59
Note: the `vector` type is just an alias for `void*` defined in `vec.h`.
55
60
56
61
# How It Works
57
62
58
-
These vectors can be manipulated in a similar manner to C++ vectors; their elements can be accessed via the `[]` operator and elements may be added or removed through the use of simple library calls.
63
+
These vectors can be manipulated in a similar manner to C++ vectors; their elements can be accessed via the `[]`
64
+
operator and elements may be added or removed through the use of simple library calls.
59
65
60
-
This works because these vectors are stored directly alongside special header in memory, which keeps track of the vector's size and capacity:
66
+
This works because these vectors are stored directly alongside special header in memory, which keeps track of the
67
+
vector's size and capacity:
61
68
62
69
+--------+-------------+
63
70
| Header | Vector data |
@@ -67,17 +74,28 @@ This works because these vectors are stored directly alongside special header in
67
74
68
75
This design was inspired by anitrez's [Simple Dynamic Strings](https://github.com/antirez/sds/).
69
76
70
-
This library uses the preprocessor to perform compile-time type checks. The type checks are done using C23's `typeof` operator, which was actually implemented in some compilers before C23 (such as GCC and Clang). [Older versions of MSVC](https://learn.microsoft.com/en-us/cpp/c-language/typeof-c?view=msvc-170#requirements) do not support the `typeof` operator. See [Missing typeof Reference Sheet](#missing-typeof-reference-sheet) for info about vector usage when `typeof` is not present.
77
+
This library uses the preprocessor to perform compile-time type checks. The type checks are done using C23's `typeof`
78
+
operator, which was actually implemented in some compilers before C23 (such as GCC and
79
+
Clang). [Older versions of MSVC](https://learn.microsoft.com/en-us/cpp/c-language/typeof-c?view=msvc-170#requirements)
80
+
do not support the `typeof` operator. See [Missing typeof Reference Sheet](#missing-typeof-reference-sheet) for info
81
+
about vector usage when `typeof` is not present.
71
82
72
-
If you're using this library in a C++ project, and `decltype` is supported, a macro substitute for `typeof` will automatically be applied.
83
+
If you're using this library in a C++ project, and `decltype` is supported, a macro substitute for `typeof` will
84
+
automatically be applied.
73
85
74
86
# Usage
75
87
76
-
Just because these vectors can be accessed and modified like regular arrays doesn't mean they should be treated the same in all cases.
88
+
Just because these vectors can be accessed and modified like regular arrays doesn't mean they should be treated the same
89
+
in all cases.
77
90
78
91
Because of the hidden header data, these vectors can only be properly freed by calling `vector_free(vec)`.
79
92
80
-
Since the header data is stored in the same location as the the vector's elements, the entire vector might be moved to a new location when its size is changed. This means the library calls that modify the vector's capacity need to take the address of the vector pointer, e.g `&vec`, so it can be reassigned. This obviously means that you can't have copies of the same vector pointer in multiple locations (unless the vector's capacity is constant), but this issue can be easily remedied by indirectly referencing the vector, either by referencing some kind of structure that contains the vector pointer, or by referencing the vector pointer itself.
93
+
Since the header data is stored in the same location as the the vector's elements, the entire vector might be moved to a
94
+
new location when its size is changed. This means the library calls that modify the vector's capacity need to take the
95
+
address of the vector pointer, e.g `&vec`, so it can be reassigned. This obviously means that you can't have copies of
96
+
the same vector pointer in multiple locations (unless the vector's capacity is constant), but this issue can be easily
97
+
remedied by indirectly referencing the vector, either by referencing some kind of structure that contains the vector
98
+
pointer, or by referencing the vector pointer itself.
81
99
82
100
Here is an example using a function that reassigns the vector pointer:
83
101
@@ -88,7 +106,11 @@ int* baz = vector_create();
88
106
vector_add(&baz, 5); // takes the address of the `int*` in case the pointer needs to be changed
89
107
```
90
108
91
-
This is another similarity to *Simple Dynamic Strings*, which has library calls that are a little more clear in their reassignment, e.g. `s = sdscat(s,"foo")`, but this functionality would break the `vector_add` and `vector_insert` macros, which already expand to an assignment expression. If you're using a compiler that supports the `typeof` operator, the vector macros will perform compile-time checks that will produce an error when the vector pointer is used incorrectly.
109
+
This is another similarity to *Simple Dynamic Strings*, which has library calls that are a little more clear in their
110
+
reassignment, e.g. `s = sdscat(s,"foo")`, but this functionality would break the `vector_add` and `vector_insert`
111
+
macros, which already expand to an assignment expression. If you're using a compiler that supports the `typeof`
112
+
operator, the vector macros will perform compile-time checks that will produce an error when the vector pointer is used
113
+
incorrectly.
92
114
93
115
Some functions never move a vector to a new location, so they just take a regular vector pointer as an argument:
int num_ages = vector_size(age_vec); // just pass the `int*` without taking its address
100
122
```
101
123
102
-
If the vector parameter for a function or macro is named `vec`, you don't need to take the address, but if the parameter is named `vec_addr`, then you do need to take it.
124
+
If the vector parameter for a function or macro is named `vec`, you don't need to take the address, but if the parameter
125
+
is named `vec_addr`, then you do need to take it.
103
126
104
127
# Best Practices
105
128
106
-
Because of the differences between regular arrays and vectors, it's probably a good idea to try to distinguish them from one another.
129
+
Because of the differences between regular arrays and vectors, it's probably a good idea to try to distinguish them from
130
+
one another.
107
131
108
132
One way to do this is to create an alias for various vector types using `typedef`:
109
133
@@ -113,11 +137,14 @@ typedef float* vec_float; // vector alias for float
113
137
vec_float qux = vector_create();
114
138
```
115
139
116
-
The *recommended* way to differentiate between vectors and arrays is to simply name them differently, for example, an array of eggs could be named `eggs` while a vector of eggs could be named `egg_vec`.
140
+
The *recommended* way to differentiate between vectors and arrays is to simply name them differently, for example, an
141
+
array of eggs could be named `eggs` while a vector of eggs could be named `egg_vec`.
117
142
118
143
# What About Structures?
119
144
120
-
If you have a vector storing some kind of structure, you can't initialize new elements of the vector like you would a variable, e.g. `{ a, b, c }`. To get around this, there's a set of special macros that allow for more control over element initialization.
145
+
If you have a vector storing some kind of structure, you can't initialize new elements of the vector like you would a
146
+
variable, e.g. `{ a, b, c }`. To get around this, there's a set of special macros that allow for more control over
147
+
element initialization.
121
148
122
149
Here is an example:
123
150
@@ -138,7 +165,10 @@ temp = NULL; // stop using temp now that the element is initialized
138
165
139
166
Below is a cheat sheet for this library's functions and macros.
140
167
141
-
Some functions and macros take a normal vector argument, e.g. `vec`, while others can change the vector's memory location and therefore require the address of the vector pointer, e.g. `&vec`. You should get a compile-time error if you use a vector pointer incorrectly. Parameter names will also indicate whether or not to take the address of the vector pointer.
168
+
Some functions and macros take a normal vector argument, e.g. `vec`, while others can change the vector's memory
169
+
location and therefore require the address of the vector pointer, e.g. `&vec`. You should get a compile-time error if
170
+
you use a vector pointer incorrectly. Parameter names will also indicate whether or not to take the address of the
@@ -155,9 +185,55 @@ Some functions and macros take a normal vector argument, e.g. `vec`, while other
155
185
| reserve space for 255 items in `vec` | `vector_reserve(&vec, 255);` | yes |
156
186
| make a copy of `vec` | `type* vec_copy = vector_copy(vec);` | no |
157
187
188
+
# Convenience Iterator and Access Macros
189
+
190
+
Several macros are implemented to make iteration and element access more convenient
191
+
192
+
### `vector_front(vec)`
193
+
194
+
Access the first element in the vector by value (`vec[0]`).
195
+
196
+
Will cause an out-of-bounds access on an empty vector.
197
+
198
+
### `vector_back(vec)`
199
+
200
+
Access the last element in the vector by value (`vec[vector_size(vec) - 1]`).
201
+
202
+
Will cause an out-of-bounds access on an empty vector.
203
+
204
+
### `vector_begin(vec)`
205
+
206
+
Address of first element in vector (`vec`).
207
+
208
+
### `vector_end(vec)`
209
+
210
+
Address of element "past the end" of the vector. (`vec + vector_size(vec)`).
211
+
212
+
### `vector_foreach(*T, vec)`
213
+
214
+
Iterate over the vector using the provided item pointer.
215
+
216
+
```c
217
+
int *int_vec = vector_create();
218
+
219
+
for (size_t i = 0; i < 100; i += 1) {
220
+
vector_add(&int_vec, i);
221
+
}
222
+
223
+
int sum = 0;
224
+
vector_foreach(int *ip, int_vec) {
225
+
sum += *ip;
226
+
}
227
+
228
+
printf ("The sum of items is %d", sum);
229
+
```
230
+
158
231
# Missing typeof Reference Sheet
159
232
160
-
Because some compilers don't support the `typeof` operator, which is used for static type checks in some of this library's macros, you have to use a slightly different set of macros. Unfortunately, this also means some errors will be missed at compile time, so if you're getting runtime errors, make sure you are properly using `vec` and `&vec` for their corresponding calls.
233
+
Because some compilers don't support the `typeof` operator, which is used for static type checks in some of this
234
+
library's macros, you have to use a slightly different set of macros. Unfortunately, this also means some errors will be
235
+
missed at compile time, so if you're getting runtime errors, make sure you are properly using `vec` and `&vec` for their
0 commit comments