xref: /freebsd/contrib/bc/include/vector.h (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * *****************************************************************************
31  *
32  * Definitions for bc vectors (resizable arrays).
33  *
34  */
35 
36 #ifndef BC_VECTOR_H
37 #define BC_VECTOR_H
38 
39 #include <stdbool.h>
40 #include <stddef.h>
41 #include <stdint.h>
42 
43 #include <status.h>
44 
45 /// An invalid index for a map to mark when an item does not exist.
46 #define BC_VEC_INVALID_IDX (SIZE_MAX)
47 
48 /// The starting capacity for vectors. This is based on the minimum allocation
49 /// for 64-bit systems.
50 #define BC_VEC_START_CAP (UINTMAX_C(1) << 5)
51 
52 /// An alias.
53 typedef unsigned char uchar;
54 
55 /**
56  * A destructor. Frees the object that @a ptr points to. This is used by vectors
57  * to free the memory they own.
58  * @param ptr  Pointer to the data to free.
59  */
60 typedef void (*BcVecFree)(void* ptr);
61 
62 #if BC_LONG_BIT >= 64
63 
64 /// An integer to shrink the size of a vector by using these instead of size_t.
65 typedef uint32_t BcSize;
66 
67 #else // BC_LONG_BIT >= 64
68 
69 /// An integer to shrink the size of a vector by using these instead of size_t.
70 typedef uint16_t BcSize;
71 
72 #endif // BC_LONG_BIT >= 64
73 
74 /// An enum of all of the destructors. We use an enum to save space.
75 typedef enum BcDtorType
76 {
77 	/// No destructor needed.
78 	BC_DTOR_NONE,
79 
80 	/// Vector destructor.
81 	BC_DTOR_VEC,
82 
83 	/// BcNum destructor.
84 	BC_DTOR_NUM,
85 
86 #if !BC_ENABLE_LIBRARY
87 
88 #if BC_DEBUG
89 
90 	/// BcFunc destructor.
91 	BC_DTOR_FUNC,
92 
93 #endif // BC_DEBUG
94 
95 	/// BcSlab destructor.
96 	BC_DTOR_SLAB,
97 
98 	/// BcConst destructor.
99 	BC_DTOR_CONST,
100 
101 	/// BcResult destructor.
102 	BC_DTOR_RESULT,
103 
104 #if BC_ENABLE_HISTORY
105 
106 	/// String destructor for history, which is *special*.
107 	BC_DTOR_HISTORY_STRING,
108 
109 #endif // BC_ENABLE_HISTORY
110 #else // !BC_ENABLE_LIBRARY
111 
112 	/// Destructor for bcl numbers.
113 	BC_DTOR_BCL_NUM,
114 
115 #endif // !BC_ENABLE_LIBRARY
116 
117 } BcDtorType;
118 
119 /// The actual vector struct.
120 typedef struct BcVec
121 {
122 	/// The vector array itself. This uses a char* because it is compatible with
123 	/// pointers of all other types, and I can do pointer arithmetic on it.
124 	char* restrict v;
125 
126 	/// The length of the vector, which is how many items actually exist.
127 	size_t len;
128 
129 	/// The capacity of the vector, which is how many items can fit in the
130 	/// current allocation.
131 	size_t cap;
132 
133 	/// The size of the items in the vector, as returned by sizeof().
134 	BcSize size;
135 
136 	/// The destructor as a BcDtorType enum.
137 	BcSize dtor;
138 
139 } BcVec;
140 
141 /**
142  * Initializes a vector.
143  * @param v      The vector to initialize.
144  * @param esize  The size of the elements, as returned by sizeof().
145  * @param dtor   The destructor of the elements, as a BcDtorType enum.
146  */
147 void
148 bc_vec_init(BcVec* restrict v, size_t esize, BcDtorType dtor);
149 
150 /**
151  * Expands the vector to have a capacity of @a req items, if it doesn't have
152  * enough already.
153  * @param v    The vector to expand.
154  * @param req  The requested capacity.
155  */
156 void
157 bc_vec_expand(BcVec* restrict v, size_t req);
158 
159 /**
160  * Grow a vector by at least @a n elements.
161  * @param v  The vector to grow.
162  * @param n  The number of elements to grow the vector by.
163  */
164 void
165 bc_vec_grow(BcVec* restrict v, size_t n);
166 
167 /**
168  * Pops @a n items off the back of the vector. The vector must have at least
169  * @a n elements.
170  * @param v  The vector to pop off of.
171  * @param n  The number of elements to pop off.
172  */
173 void
174 bc_vec_npop(BcVec* restrict v, size_t n);
175 
176 /**
177  * Pops @a n items, starting at index @a idx, off the vector. The vector must
178  * have at least @a n elements after the @a idx index. Any remaining elements at
179  * the end are moved up to fill the hole.
180  * @param v  The vector to pop off of.
181  * @param n  The number of elements to pop off.
182  * @param idx  The index to start popping at.
183  */
184 void
185 bc_vec_npopAt(BcVec* restrict v, size_t n, size_t idx);
186 
187 /**
188  * Pushes one item on the back of the vector. It does a memcpy(), but it assumes
189  * that the vector takes ownership of the data.
190  * @param v     The vector to push onto.
191  * @param data  A pointer to the data to push.
192  */
193 void
194 bc_vec_push(BcVec* restrict v, const void* data);
195 
196 /**
197  * Pushes @a n items on the back of the vector. It does a memcpy(), but it
198  * assumes that the vector takes ownership of the data.
199  * @param v     The vector to push onto.
200  * @param data  A pointer to the elements of data to push.
201  */
202 void
203 bc_vec_npush(BcVec* restrict v, size_t n, const void* data);
204 
205 /**
206  * Push an empty element and return a pointer to it. This is done as an
207  * optimization where initializing an item needs a pointer anyway. It removes an
208  * extra memcpy().
209  * @param v  The vector to push onto.
210  * @return   A pointer to the newly-pushed element.
211  */
212 void*
213 bc_vec_pushEmpty(BcVec* restrict v);
214 
215 /**
216  * Pushes a byte onto a bytecode vector. This is a convenience function for the
217  * parsers pushing instructions. The vector must be a bytecode vector.
218  * @param v     The vector to push onto.
219  * @param data  The byte to push.
220  */
221 void
222 bc_vec_pushByte(BcVec* restrict v, uchar data);
223 
224 /**
225  * Pushes and index onto a bytecode vector. The vector must be a bytecode
226  * vector. For more info about why and how this is done, see the development
227  * manual (manuals/development#bytecode-indices).
228  * @param v    The vector to push onto.
229  * @param idx  The index to push.
230  */
231 void
232 bc_vec_pushIndex(BcVec* restrict v, size_t idx);
233 
234 /**
235  * Push an item onto the vector at a certain index. The index must be valid
236  * (either exists or is equal to the length of the vector). The elements at that
237  * index and after are moved back one element and kept in the same order. This
238  * is how the map vectors are kept sorted.
239  * @param v     The vector to push onto.
240  * @param data  A pointer to the data to push.
241  * @param idx   The index to push at.
242  */
243 void
244 bc_vec_pushAt(BcVec* restrict v, const void* data, size_t idx);
245 
246 /**
247  * Empties the vector and sets it to the string. The vector must be a valid
248  * vector and must have chars as its elements.
249  * @param v    The vector to set to the string.
250  * @param len  The length of the string. This can be less than the actual length
251  *             of the string, but must never be more.
252  * @param str  The string to push.
253  */
254 void
255 bc_vec_string(BcVec* restrict v, size_t len, const char* restrict str);
256 
257 /**
258  * Appends the string to the end of the vector, which must be holding a string
259  * (nul byte-terminated) already.
260  * @param v    The vector to append to.
261  * @param str  The string to append (by copying).
262  */
263 void
264 bc_vec_concat(BcVec* restrict v, const char* restrict str);
265 
266 /**
267  * Empties a vector and pushes a nul-byte at the first index. The vector must be
268  * a char vector.
269  */
270 void
271 bc_vec_empty(BcVec* restrict v);
272 
273 #if BC_ENABLE_HISTORY
274 
275 /**
276  * Replaces an item at a particular index. No elements are moved. The index must
277  * exist.
278  * @param v     The vector to replace an item on.
279  * @param idx   The index of the item to replace.
280  * @param data  The data to replace the item with.
281  */
282 void
283 bc_vec_replaceAt(BcVec* restrict v, size_t idx, const void* data);
284 
285 #endif // BC_ENABLE_HISTORY
286 
287 /**
288  * Returns a pointer to the item in the vector at the index. This is the key
289  * function for vectors. The index must exist.
290  * @param v    The vector.
291  * @param idx  The index to the item to get a pointer to.
292  * @return     A pointer to the item at @a idx.
293  */
294 void*
295 bc_vec_item(const BcVec* restrict v, size_t idx);
296 
297 /**
298  * Returns a pointer to the item in the vector at the index, reversed. This is
299  * another key function for vectors. The index must exist.
300  * @param v    The vector.
301  * @param idx  The index to the item to get a pointer to.
302  * @return     A pointer to the item at len - @a idx - 1.
303  */
304 void*
305 bc_vec_item_rev(const BcVec* restrict v, size_t idx);
306 
307 /**
308  * Zeros a vector. The vector must not be allocated.
309  * @param v  The vector to clear.
310  */
311 void
312 bc_vec_clear(BcVec* restrict v);
313 
314 /**
315  * Frees a vector and its elements. This is a destructor.
316  * @param vec  A vector as a void pointer.
317  */
318 void
319 bc_vec_free(void* vec);
320 
321 /**
322  * Attempts to insert an ID into a map and returns true if it succeeded, false
323  * if the item already exists.
324  * @param v     The map vector to insert into.
325  * @param name  The name of the item to insert. This name is assumed to be owned
326  *              by another entity.
327  * @param idx   The index of the partner array where the actual item is.
328  * @param i     A pointer to an index that will be set to the index of the item
329  *              in the map.
330  * @return      True if the item was inserted, false if the item already exists.
331  */
332 bool
333 bc_map_insert(BcVec* restrict v, const char* name, size_t idx,
334               size_t* restrict i);
335 
336 /**
337  * Returns the index of the item with @a name in the map, or BC_VEC_INVALID_IDX
338  * if it doesn't exist.
339  * @param v     The map vector.
340  * @param name  The name of the item to find.
341  * @return      The index in the map of the item with @a name, or
342  *              BC_VEC_INVALID_IDX if the item does not exist.
343  */
344 size_t
345 bc_map_index(const BcVec* restrict v, const char* name);
346 
347 #if DC_ENABLED
348 
349 /**
350  * Returns the name of the item at index @a idx in the map.
351  * @param v    The map vector.
352  * @param idx  The index.
353  * @return     The name of the item at @a idx.
354  */
355 const char*
356 bc_map_name(const BcVec* restrict v, size_t idx);
357 
358 #endif // DC_ENABLED
359 
360 /**
361  * Pops one item off of the vector.
362  * @param v  The vector to pop one item off of.
363  */
364 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
365 
366 /**
367  * Pops all items off of the vector.
368  * @param v  The vector to pop all items off of.
369  */
370 #define bc_vec_popAll(v) (bc_vec_npop((v), (v)->len))
371 
372 /**
373  * Return a pointer to the last item in the vector, or first if it's being
374  * treated as a stack.
375  * @param v  The vector to get the top of stack of.
376  */
377 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
378 
379 /**
380  * Initializes a vector to serve as a map.
381  * @param v  The vector to initialize.
382  */
383 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), BC_DTOR_NONE))
384 
385 /// A reference to the array of destructors.
386 extern const BcVecFree bc_vec_dtors[];
387 
388 #if !BC_ENABLE_LIBRARY
389 
390 /// The allocated size of slabs.
391 #define BC_SLAB_SIZE (4096)
392 
393 /// A slab for allocating strings.
394 typedef struct BcSlab
395 {
396 	/// The actual allocation.
397 	char* s;
398 
399 	/// How many bytes of the slab are taken.
400 	size_t len;
401 
402 } BcSlab;
403 
404 /**
405  * Frees a slab. This is a destructor.
406  * @param slab  The slab as a void pointer.
407  */
408 void
409 bc_slab_free(void* slab);
410 
411 /**
412  * Initializes a slab vector.
413  * @param v  The vector to initialize.
414  */
415 void
416 bc_slabvec_init(BcVec* restrict v);
417 
418 /**
419  * Duplicates the string using slabs in the slab vector.
420  * @param v    The slab vector.
421  * @param str  The string to duplicate.
422  * @return     A pointer to the duplicated string, owned by the slab vector.
423  */
424 char*
425 bc_slabvec_strdup(BcVec* restrict v, const char* str);
426 
427 /**
428  * Clears a slab vector. This deallocates all but the first slab and clears the
429  * first slab.
430  * @param v  The slab vector to clear.
431  */
432 void
433 bc_slabvec_clear(BcVec* restrict v);
434 
435 #if BC_DEBUG_CODE
436 
437 /**
438  * Prints all of the items in a slab vector, in order.
439  * @param v  The vector whose items will be printed.
440  */
441 void
442 bc_slabvec_print(BcVec* v, const char* func);
443 
444 #endif // BC_DEBUG_CODE
445 
446 /// A convenience macro for freeing a vector of slabs.
447 #define bc_slabvec_free bc_vec_free
448 
449 #ifndef _WIN32
450 
451 /**
452  * A macro to get rid of a warning on Windows.
453  * @param d  The destination string.
454  * @param l  The length of the destination string. This has to be big enough to
455  *           contain @a s.
456  * @param s  The source string.
457  */
458 #define bc_strcpy(d, l, s) strcpy(d, s)
459 
460 #else // _WIN32
461 
462 /**
463  * A macro to get rid of a warning on Windows.
464  * @param d  The destination string.
465  * @param l  The length of the destination string. This has to be big enough to
466  *           contain @a s.
467  * @param s  The source string.
468  */
469 #define bc_strcpy(d, l, s) strcpy_s(d, l, s)
470 
471 #endif // _WIN32
472 
473 #endif // !BC_ENABLE_LIBRARY
474 
475 #endif // BC_VECTOR_H
476