/*1* *****************************************************************************2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2018-2025 Gavin D. Howard and contributors.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions are met:9*10* * Redistributions of source code must retain the above copyright notice, this11* list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright notice,14* this list of conditions and the following disclaimer in the documentation15* and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"18* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE21* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGE.28*29* *****************************************************************************30*31* Definitions for bc vectors (resizable arrays).32*33*/3435#ifndef BC_VECTOR_H36#define BC_VECTOR_H3738#include <stdbool.h>39#include <stddef.h>40#include <stdint.h>4142#include <status.h>4344/// An invalid index for a map to mark when an item does not exist.45#define BC_VEC_INVALID_IDX (SIZE_MAX)4647/// The starting capacity for vectors. This is based on the minimum allocation48/// for 64-bit systems.49#define BC_VEC_START_CAP (UINTMAX_C(1) << 5)5051/// An alias.52typedef unsigned char uchar;5354/**55* A destructor. Frees the object that @a ptr points to. This is used by vectors56* to free the memory they own.57* @param ptr Pointer to the data to free.58*/59typedef void (*BcVecFree)(void* ptr);6061#if BC_LONG_BIT >= 646263/// An integer to shrink the size of a vector by using these instead of size_t.64typedef uint32_t BcSize;6566#else // BC_LONG_BIT >= 646768/// An integer to shrink the size of a vector by using these instead of size_t.69typedef uint16_t BcSize;7071#endif // BC_LONG_BIT >= 647273/// An enum of all of the destructors. We use an enum to save space.74typedef enum BcDtorType75{76/// No destructor needed.77BC_DTOR_NONE,7879/// Vector destructor.80BC_DTOR_VEC,8182/// BcNum destructor.83BC_DTOR_NUM,8485#if !BC_ENABLE_LIBRARY8687#if BC_DEBUG8889/// BcFunc destructor.90BC_DTOR_FUNC,9192#endif // BC_DEBUG9394/// BcSlab destructor.95BC_DTOR_SLAB,9697/// BcConst destructor.98BC_DTOR_CONST,99100/// BcResult destructor.101BC_DTOR_RESULT,102103#if BC_ENABLE_HISTORY104105/// String destructor for history, which is *special*.106BC_DTOR_HISTORY_STRING,107108#endif // BC_ENABLE_HISTORY109#else // !BC_ENABLE_LIBRARY110111/// Destructor for bcl numbers.112BC_DTOR_BCL_NUM,113114#endif // !BC_ENABLE_LIBRARY115116} BcDtorType;117118/// The actual vector struct.119typedef struct BcVec120{121/// The vector array itself. This uses a char* because it is compatible with122/// pointers of all other types, and I can do pointer arithmetic on it.123char* restrict v;124125/// The length of the vector, which is how many items actually exist.126size_t len;127128/// The capacity of the vector, which is how many items can fit in the129/// current allocation.130size_t cap;131132/// The size of the items in the vector, as returned by sizeof().133BcSize size;134135/// The destructor as a BcDtorType enum.136BcSize dtor;137138} BcVec;139140/**141* Initializes a vector.142* @param v The vector to initialize.143* @param esize The size of the elements, as returned by sizeof().144* @param dtor The destructor of the elements, as a BcDtorType enum.145*/146void147bc_vec_init(BcVec* restrict v, size_t esize, BcDtorType dtor);148149/**150* Expands the vector to have a capacity of @a req items, if it doesn't have151* enough already.152* @param v The vector to expand.153* @param req The requested capacity.154*/155void156bc_vec_expand(BcVec* restrict v, size_t req);157158/**159* Grow a vector by at least @a n elements.160* @param v The vector to grow.161* @param n The number of elements to grow the vector by.162*/163void164bc_vec_grow(BcVec* restrict v, size_t n);165166/**167* Pops @a n items off the back of the vector. The vector must have at least168* @a n elements.169* @param v The vector to pop off of.170* @param n The number of elements to pop off.171*/172void173bc_vec_npop(BcVec* restrict v, size_t n);174175/**176* Pops @a n items, starting at index @a idx, off the vector. The vector must177* have at least @a n elements after the @a idx index. Any remaining elements at178* the end are moved up to fill the hole.179* @param v The vector to pop off of.180* @param n The number of elements to pop off.181* @param idx The index to start popping at.182*/183void184bc_vec_npopAt(BcVec* restrict v, size_t n, size_t idx);185186/**187* Pushes one item on the back of the vector. It does a memcpy(), but it assumes188* that the vector takes ownership of the data.189* @param v The vector to push onto.190* @param data A pointer to the data to push.191*/192void193bc_vec_push(BcVec* restrict v, const void* data);194195/**196* Pushes @a n items on the back of the vector. It does a memcpy(), but it197* assumes that the vector takes ownership of the data.198* @param v The vector to push onto.199* @param data A pointer to the elements of data to push.200*/201void202bc_vec_npush(BcVec* restrict v, size_t n, const void* data);203204/**205* Push an empty element and return a pointer to it. This is done as an206* optimization where initializing an item needs a pointer anyway. It removes an207* extra memcpy().208* @param v The vector to push onto.209* @return A pointer to the newly-pushed element.210*/211void*212bc_vec_pushEmpty(BcVec* restrict v);213214/**215* Pushes a byte onto a bytecode vector. This is a convenience function for the216* parsers pushing instructions. The vector must be a bytecode vector.217* @param v The vector to push onto.218* @param data The byte to push.219*/220void221bc_vec_pushByte(BcVec* restrict v, uchar data);222223/**224* Pushes and index onto a bytecode vector. The vector must be a bytecode225* vector. For more info about why and how this is done, see the development226* manual (manuals/development#bytecode-indices).227* @param v The vector to push onto.228* @param idx The index to push.229*/230void231bc_vec_pushIndex(BcVec* restrict v, size_t idx);232233/**234* Push an item onto the vector at a certain index. The index must be valid235* (either exists or is equal to the length of the vector). The elements at that236* index and after are moved back one element and kept in the same order. This237* is how the map vectors are kept sorted.238* @param v The vector to push onto.239* @param data A pointer to the data to push.240* @param idx The index to push at.241*/242void243bc_vec_pushAt(BcVec* restrict v, const void* data, size_t idx);244245/**246* Empties the vector and sets it to the string. The vector must be a valid247* vector and must have chars as its elements.248* @param v The vector to set to the string.249* @param len The length of the string. This can be less than the actual length250* of the string, but must never be more.251* @param str The string to push.252*/253void254bc_vec_string(BcVec* restrict v, size_t len, const char* restrict str);255256/**257* Appends the string to the end of the vector, which must be holding a string258* (nul byte-terminated) already.259* @param v The vector to append to.260* @param str The string to append (by copying).261*/262void263bc_vec_concat(BcVec* restrict v, const char* restrict str);264265/**266* Empties a vector and pushes a nul-byte at the first index. The vector must be267* a char vector.268*/269void270bc_vec_empty(BcVec* restrict v);271272#if BC_ENABLE_HISTORY273274/**275* Replaces an item at a particular index. No elements are moved. The index must276* exist.277* @param v The vector to replace an item on.278* @param idx The index of the item to replace.279* @param data The data to replace the item with.280*/281void282bc_vec_replaceAt(BcVec* restrict v, size_t idx, const void* data);283284#endif // BC_ENABLE_HISTORY285286/**287* Returns a pointer to the item in the vector at the index. This is the key288* function for vectors. The index must exist.289* @param v The vector.290* @param idx The index to the item to get a pointer to.291* @return A pointer to the item at @a idx.292*/293void*294bc_vec_item(const BcVec* restrict v, size_t idx);295296/**297* Returns a pointer to the item in the vector at the index, reversed. This is298* another key function for vectors. The index must exist.299* @param v The vector.300* @param idx The index to the item to get a pointer to.301* @return A pointer to the item at len - @a idx - 1.302*/303void*304bc_vec_item_rev(const BcVec* restrict v, size_t idx);305306/**307* Zeros a vector. The vector must not be allocated.308* @param v The vector to clear.309*/310void311bc_vec_clear(BcVec* restrict v);312313/**314* Frees a vector and its elements. This is a destructor.315* @param vec A vector as a void pointer.316*/317void318bc_vec_free(void* vec);319320/**321* Attempts to insert an ID into a map and returns true if it succeeded, false322* if the item already exists.323* @param v The map vector to insert into.324* @param name The name of the item to insert. This name is assumed to be owned325* by another entity.326* @param idx The index of the partner array where the actual item is.327* @param i A pointer to an index that will be set to the index of the item328* in the map.329* @return True if the item was inserted, false if the item already exists.330*/331bool332bc_map_insert(BcVec* restrict v, const char* name, size_t idx,333size_t* restrict i);334335/**336* Returns the index of the item with @a name in the map, or BC_VEC_INVALID_IDX337* if it doesn't exist.338* @param v The map vector.339* @param name The name of the item to find.340* @return The index in the map of the item with @a name, or341* BC_VEC_INVALID_IDX if the item does not exist.342*/343size_t344bc_map_index(const BcVec* restrict v, const char* name);345346#if DC_ENABLED347348/**349* Returns the name of the item at index @a idx in the map.350* @param v The map vector.351* @param idx The index.352* @return The name of the item at @a idx.353*/354const char*355bc_map_name(const BcVec* restrict v, size_t idx);356357#endif // DC_ENABLED358359/**360* Pops one item off of the vector.361* @param v The vector to pop one item off of.362*/363#define bc_vec_pop(v) (bc_vec_npop((v), 1))364365/**366* Pops all items off of the vector.367* @param v The vector to pop all items off of.368*/369#define bc_vec_popAll(v) (bc_vec_npop((v), (v)->len))370371/**372* Return a pointer to the last item in the vector, or first if it's being373* treated as a stack.374* @param v The vector to get the top of stack of.375*/376#define bc_vec_top(v) (bc_vec_item_rev((v), 0))377378/**379* Initializes a vector to serve as a map.380* @param v The vector to initialize.381*/382#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), BC_DTOR_NONE))383384/// A reference to the array of destructors.385extern const BcVecFree bc_vec_dtors[];386387#if !BC_ENABLE_LIBRARY388389/// The allocated size of slabs.390#define BC_SLAB_SIZE (4096)391392/// A slab for allocating strings.393typedef struct BcSlab394{395/// The actual allocation.396char* s;397398/// How many bytes of the slab are taken.399size_t len;400401} BcSlab;402403/**404* Frees a slab. This is a destructor.405* @param slab The slab as a void pointer.406*/407void408bc_slab_free(void* slab);409410/**411* Initializes a slab vector.412* @param v The vector to initialize.413*/414void415bc_slabvec_init(BcVec* restrict v);416417/**418* Duplicates the string using slabs in the slab vector.419* @param v The slab vector.420* @param str The string to duplicate.421* @return A pointer to the duplicated string, owned by the slab vector.422*/423char*424bc_slabvec_strdup(BcVec* restrict v, const char* str);425426/**427* Clears a slab vector. This deallocates all but the first slab and clears the428* first slab.429* @param v The slab vector to clear.430*/431void432bc_slabvec_clear(BcVec* restrict v);433434#if BC_DEBUG_CODE435436/**437* Prints all of the items in a slab vector, in order.438* @param v The vector whose items will be printed.439*/440void441bc_slabvec_print(BcVec* v, const char* func);442443#endif // BC_DEBUG_CODE444445/// A convenience macro for freeing a vector of slabs.446#define bc_slabvec_free bc_vec_free447448#ifndef _WIN32449450/**451* A macro to get rid of a warning on Windows.452* @param d The destination string.453* @param l The length of the destination string. This has to be big enough to454* contain @a s.455* @param s The source string.456*/457#define bc_strcpy(d, l, s) strcpy(d, s)458459#else // _WIN32460461/**462* A macro to get rid of a warning on Windows.463* @param d The destination string.464* @param l The length of the destination string. This has to be big enough to465* contain @a s.466* @param s The source string.467*/468#define bc_strcpy(d, l, s) strcpy_s(d, l, s)469470#endif // _WIN32471472#endif // !BC_ENABLE_LIBRARY473474#endif // BC_VECTOR_H475476477