Move data structures into their own directory

This commit is contained in:
Rickey Fehr
2026-05-23 11:53:35 -07:00
parent 92cb9f9883
commit 625185aa94
12 changed files with 17 additions and 13 deletions

View File

@@ -0,0 +1,207 @@
/**
* @file bitset.h
*
* @brief A bitset for operating on flags
*/
#ifndef BITSET_H
#define BITSET_H
#include <stdbool.h>
#include <stdint.h>
/**
* @def BITSET_BITS_PER_WORD
* @brief Number of bits in a word for a bitset.
*
* Number of bits in a word for a bitset. Will always be 32 here.
*/
#define BITSET_BITS_PER_WORD 32
/**
* @def BITSET_ARRAY_SIZE
* @brief Number of words in a bitset
*
* Number of words in every bitset. This represents the maximum number and each
* bitset will always use this number of words, though it's capacity can be any length
* from `1` to `BITSET_BITS_PER_WORD * BITSET_ARRAY_SIZE`
*/
#define BITSET_ARRAY_SIZE 8
/**
* @def BITSET_MAX_BITS
* @brief Maximum number of bits in a bitset
*/
#define BITSET_MAX_BITS (BITSET_BITS_PER_WORD * BITSET_ARRAY_SIZE)
/**
* @brief A bitset spread across multiple `uint32_t` words
*/
typedef struct Bitset
{
/**
* @brief Word array of `uint32_t` to hold the bitset data
*/
uint32_t* w;
/**
* @brief Number of bits in a word, will be 32
*/
uint32_t nbits;
/**
* @brief Number of words int the `w` array
*/
uint32_t nwords;
/**
* @brief Number of actual flags (nbits * nwords)
*/
uint32_t cap;
} Bitset;
/**
* @brief An iterator into a @ref Bitset
*
* This iterator will parse and find the next index to a '1' bit as efficiently as possible.
*
* There is no implementation of the following (yet):
* - Reverse iteration
* - Bit-by-bit iteration
* - Iterating on offsets to '0' bits
*/
typedef struct
{
/**
* @brief @ref Bitset this is iterating through
*/
const Bitset* bitset;
/**
* @brief Current word the iterator is on
*/
int word;
/**
* @brief Current bit the iterator is on
*/
int bit;
/**
* @brief Number of bits that have been iterated through in total
*/
int itr;
} BitsetItr;
/**
* @brief Set a flag in a bitset to a value
*
* @param bitset A @ref Bitset to operate on
* @param idx the index of the flag to set
* @param on the value to set the flag to
*/
void bitset_set_idx(Bitset* bitset, int idx, bool on);
/**
* @brief Get the value of a flag
*
* @param bitset A @ref Bitset to operate on
* @param idx the index of the flag to get
*
* @return the value of the flag as `true` or `false`
*/
bool bitset_get_idx(Bitset* bitset, int idx);
/**
* @brief Set the next free index in the bitset and return the index value
*
* @param bitset A @ref Bitset to operate on
*
* @return The index of the bit that was set
*/
int bitset_set_next_free_idx(Bitset* bitset);
/**
* @brief Clear the bitset, all to 0
*
* @param bitset A @ref Bitset to operate on
*/
void bitset_clear(Bitset* bitset);
/**
* @brief Check if a bitset is empty (all 0's)
*
* @param bitset A @ref Bitset to operate on
*
* @return `true` if empty, `false` otherwise
*/
bool bitset_is_empty(Bitset* bitset);
/**
* @brief Count how many bits are set to `1` in a bitset
*
* @param bitset A @ref Bitset to operate on
*
* @return The number of flags set to `1` in a bitset
*/
int bitset_num_set_bits(Bitset* bitset);
/**
* @brief Find the index of the nth set bit
*
* Find the index of the nth flag set to `1`. This function is useful to get one value quickly,
* but does not operate iteratively well. Use a @BitsetItr for iterative access to a bitset.
*
* @param bitset A @ref Bitset to operate on
*
* @return The index of the nth flag set to `1` in the bitset
*/
int bitset_find_idx_of_nth_set(const Bitset* bitset, int n);
/**
* @brief Declare a @ref BitsetItr
*
* @param bitset A @ref Bitset to operate on
*
* @return A newly constructed BitsetItr
*/
BitsetItr bitset_itr_create(const Bitset* bitset);
/**
* @brief Get the index of the next set bit in the bitset from a @ref BitsetItr
*
* @param itr A @ref BitsetItr to operate on
*
* @return a positive number if successful, UNDEFINED otherwise (out-of-bounds)
*/
int bitset_itr_next(BitsetItr* itr);
/**
* @def BITSET_DEFINE
* @brief Make a standard bitset
*
* Make a bitset with a valid static array to store it's array of words.
*
* Use this to define bitsets in the code, specifically as a `static` scoped
* variable. The passed `name` will be the same name as the bitset.
*
* Usage example:
*
* ```c
* BITSET_DEFINE(_my_bitset, 128);
* // normal operation...
* bitset_clear(&_my_bitset);
* ```
*
* @param name the name of the bitset
* @param capacity the capacity of the bitset
*/
#define BITSET_DEFINE(name, capacity) \
static uint32_t name##_w[BITSET_ARRAY_SIZE] = {0}; \
static Bitset name = { \
.w = name##_w, \
.nbits = BITSET_BITS_PER_WORD, \
.nwords = BITSET_ARRAY_SIZE, \
.cap = capacity, \
};
#endif // BITSET_H

View File

@@ -0,0 +1,296 @@
/**
* @file list.h
*
* @brief A doubly-linked list
*
* List Implementation
* ===================
*
* - This @ref List operates as a linked list @ref ListNodes. It operates as a regular
* doubly-linked list but doesn't allocate memory and rather gets @ref ListNodes from a pool.
*/
#ifndef LIST_H
#define LIST_H
#include <stdbool.h>
/**
* @def MAX_LIST_NODES
* @brief Number of reserved list nodes.
*
* Number of list nodes available from the pool of @ref ListNode . This should
* be set to to the maximum number of list nodes needed at once.
*/
#define MAX_LIST_NODES 128
/**
* @brief Default list declaration for empty lists
*/
// clang-format off
#define LIST_DEFAULT { .head = NULL, .tail = NULL, .len = 0 }
// clang-format on
typedef struct ListNode ListNode;
/**
* @brief A single entry in a @ref List
*/
struct ListNode
{
/**
* @brief The previous @ref ListNode in the associated @ref List, NULL if at the `head` of the
* list
*/
ListNode* prev;
/**
* @brief The next @ref ListNode in the associated @ref List, NULL if at the `tail` of the list
*/
ListNode* next;
/**
* @brief Pointer to generic data stored in this node
*/
void* data;
};
/**
* @brief A doubly-linked list
*/
typedef struct List
{
/**
* @brief The first entry in the list
*/
ListNode* head;
/**
* @brief The last entry in the list
*/
ListNode* tail;
/**
* @brief Number of elements in list
*/
int len;
} List;
/**
* @brief @ref ListItr direction
*/
enum ListItrDirection
{
LIST_ITR_FORWARD,
LIST_ITR_REVERSE,
};
/**
* @brief An iterator into a list
*/
typedef struct
{
/**
* @brief A pointer to the @ref List this is iterating through
*/
List* list;
/**
* @brief The next node in the list
*/
ListNode* next_node;
/**
* @brief The current node in the list iterator
*
* The node of the most recently returned data from @ref list_itr_next() .
*/
ListNode* current_node;
/**
* @brief The direction of the iterator
*/
enum ListItrDirection direction;
} ListItr;
/**
* Initialize a list.
*
* Set the values of a list to default.
*
* If using this function to reset a list, the list must be freed with @ref list_clear to ensure the
* list's nodes are deleted properly.
*
* @return A @ref List with head and tail reset.
*/
List list_init(void);
/**
* Clear a list.
*
* Go through the list and free each node and set the `head` and `tail` to `NULL`.
* Note, it doesn't "free" the data at the node.
*
* @note To reset an existing list to default values, first call `list_clear` then @ref list_init
*
* @param list pointer to a @ref List to clear
*/
void list_clear(List* list);
/**
* Check if a list is empty
*
* @param list pointer to a @ref List
*
* @return `true` if the `list` is empty, `false` otherwise.
*/
bool list_is_empty(const List* list);
/**
* Prepend an entry to the `head` of a @ref list
*
* @param list pointer to a @ref List
* @param data pointer to data to put into the @ref List
*/
void list_push_front(List* list, void* data);
/**
* Append an entry to the `tail` of a @ref list
*
* @param list pointer to a @ref List
* @param data pointer to data to put into the @ref List
*/
void list_push_back(List* list, void* data);
/**
* Insert data into a @ref List a specific index
*
* If the index specified is larger than the length of the list
* it will @ref list_push_back() the data instead;
*
* Performs the following operation:
*
* ┌─────┐
* │ node│
* └─────┘
* ┌─────┐ ┌─────┐ ┌─────┐
* │idx-1│◄─►│ idx │◄─►│idx+1│
* └─────┘ └─────┘ └─────┘
*
* 1. Set new `node` `prev` to the node at idx - 1
* 2. Set new `node` `next` to the node at idx
* 3. Set node at idx - 1 `next` to new `node`
* 4. Set node at idx `prev` to the new `node`
*
* Result:
*
* ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
* │idx-1│◄─►│ node│◄─►│ idx │◄─►│idx+1│
* └─────┘ └─────┘ └─────┘ └─────┘
*
* Finally, the list is now updated with new `node` now at the labeled idx:
*
* ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
* │idx-1│◄─►│ idx │◄─►│idx+1│◄─►│idx+2│
* └─────┘ └─────┘ └─────┘ └─────┘
*
* @param list pointer to a @ref List
* @param data pointer to data to put into the @ref List
* @param idx desired index to insert
*/
void list_insert(List* list, void* data, unsigned int idx);
/**
* Swap the data pointers at the specified indices of a @ref List
*
* If either indices are larger than the length of the list, return false.
*
* @param list pointer to a @ref List
* @param idx_a desired index to swap with idx_b
* @param idx_b desired index to swap with idx_a
*
* @return true if successful, false otherwise
*/
bool list_swap(List* list, unsigned int idx_a, unsigned int idx_b);
/**
* Get a List's node at the specified index
*
* @param list pointer to a @ref List
* @param idx index of the desired @ref ListNode in the list
*
* @return a pointer to the data at the index of the list, or NULL if out-of-bounds
*/
void* list_get_at_idx(List* list, unsigned int idx);
/**
* Remove a List's node at the specified index
*
* @param list pointer to a @ref List
* @param idx index of the desired @ref ListNode in the list
*
* @return `true` if successfully removed, `false` if out-of-bounds
*/
bool list_remove_at_idx(List* list, unsigned int idx);
/**
* Remove a List's node with the matching pointer
*
* @param list pointer to a @ref List
* @param data pointer to data in node in list
*
* @return `true` if successfully removed, `false` otherwise
*
* @note When working with @ref ListItr, use @ref list_itr_remove_current_node()
*/
bool list_remove_data(List* list, void* data);
/**
* Get the number of elements in a @ref List
*
* @param list pointer to a @ref List
*
* @return The number of elements in the list
*/
int list_get_len(const List* list);
/**
* Declare a @ref ListItr
*
* @param list pointer to a @ref List
*
* @return A new @ref ListItr
*/
ListItr list_itr_create(List* list);
/**
* Declare a reverse @ref ListItr
*
* @param list pointer to a @ref List
*
* @return A new reverse @ref ListItr
*/
ListItr rev_list_itr_create(List* list);
/**
* Get the next data entry in a @ref ListItr
*
* @param itr pointer to the @ref ListItr
*
* @return A pointer to the data pointer at the next @ref ListNode if valid, otherwise return NULL.
*/
void* list_itr_next(ListItr* itr);
/**
* Remove the current @ref ListNode from the iterator.
*
* The "current node" corresponds to the list node associated with the
* most recently returned valu from @ref list_itr_next()
*
* @param itr pointer to the @ref ListItr
*
* @note When working with @ref ListItr, use this and not @ref list_remove_at() as it will
* "break" the iterator.
*/
void list_itr_remove_current_node(ListItr* itr);
#endif

View File

@@ -0,0 +1,67 @@
#ifndef POOL_H
#define POOL_H
#include "bitset.h"
#include <stdbool.h>
#include <stdint.h>
#ifdef POOLS_TEST_ENV
#define POOLS_DEF_FILE "def_test_mempool.h"
#else
#define POOLS_DEF_FILE "def_balatro_mempool.h"
#endif
#define POOL_DECLARE_TYPE(type) \
typedef struct \
{ \
Bitset* bitset; \
type* objects; \
} type##Pool; \
type* pool_get_##type(); \
void pool_free_##type(type* obj); \
int pool_idx_##type(type* obj); \
type* pool_at_##type(int idx);
#define POOL_DEFINE_TYPE(type, capacity) \
BITSET_DEFINE(type##_bitset, capacity) \
static type type##_storage[capacity]; \
static type##Pool type##_pool = { \
.bitset = &type##_bitset, \
.objects = type##_storage, \
}; \
type* pool_get_##type() \
{ \
int free_offset = bitset_set_next_free_idx(type##_pool.bitset); \
if (free_offset == -1) \
return NULL; \
return &type##_pool.objects[free_offset]; \
} \
void pool_free_##type(type* entry) \
{ \
if (entry == NULL) \
return; \
int offset = entry - &type##_pool.objects[0]; \
bitset_set_idx(type##_pool.bitset, offset, false); \
} \
int pool_idx_##type(type* entry) \
{ \
return entry - &type##_pool.objects[0]; \
} \
type* pool_at_##type(int idx) \
{ \
if (idx < 0 || idx >= (type##_pool.bitset)->cap) \
return NULL; \
return &type##_pool.objects[idx]; \
}
#define POOL_GET(type) pool_get_##type()
#define POOL_FREE(type, obj) pool_free_##type(obj)
#define POOL_IDX(type, obj) pool_idx_##type(obj) // the index of the object
#define POOL_AT(type, idx) pool_at_##type(idx) // the object at
#define POOL_ENTRY(name, capacity) POOL_DECLARE_TYPE(name);
#include POOLS_DEF_FILE
#undef POOL_ENTRY
#endif // POOL_H