/* * Copyright © 2026 Kana Steimle * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file table.h * @brief A library for creating tables of key-value pairs, where keys are strings and values are pointers to arbitrary data. */ #ifndef _TABLE_H #define _TABLE_H #include /** * @struct table */ typedef struct table table_t; /** * A function used to compare 2 strings. * It's recommended to use strcmp (the default) or strcasecmp (if you want to ignore case), but you could write your own version as long as comparisons rank strings in a consistent way. */ typedef int cmpkeys_f (char const *, char const *); /** * A function used to make a copy of a value in a table. * It is only called on non-NULL values. */ typedef void *copyval_f (void *); /** * A function used to deallocate a value in a table. * It is only called on values not set to NULL. * The function should not be able to fail. */ typedef void freeval_f (void *); /** * Create a new table. * * @param copyval If this function pointer is non-NULL, it is used to duplicate non-NULL values when needed. * @param freeval If this function pointer is non-NULL, it is used to deallocate non-NULL values when needed. * @param cmpkeys If this function pointer is non-NULL, it is used to compare keys for the sake of sorting them. If NULL is passed, strcmp is used. * * @return A pointer to the table, or a NULL value. */ table_t *table_create (copyval_f *copyval, freeval_f *freeval, cmpkeys_f *cmpkeys); /** * Copy an existing table. * The function pointers of the original table are used for the new table. * If the original table's copyval function is non-NULL, new copies of the original values are made. * * @param original The original table. * * @return The new table. If an allocation error occurs, NULL is returned. */ table_t *table_copy (table_t const *original); /** * Create a new table containing the contents of an array of tables. * All the original tables must have the same function pointers, which are inherited by the new table. * If the copyval function of the tables is non-NULL, new copies of the original values are made. * If at any point multiple tables contain the same key, only the one from the first table in the list is stored in the new table. * * @param originals The original tables. * @param numoriginals The length of the array of tables. * * @return The new table. If an error occurs at any point during the merge, NULL is returned. */ table_t *table_merge (table_t const **originals, size_t numoriginals); /** * Delete a table, deallocating it and its contents. * If the freeval function is non-NULL, all non-NULL values are freed. */ void table_delete (table_t *); /** * Get the number of assigned keys in a table. * @return The number of assigned keys in a table. */ size_t table_length (table_t const *); /** * Gets the key / value pair at the specified index into the table. * Keep in mind that if you set or unset values in the table while iterating it, you'll have to start iteration over. * * @param[in] index The index to inspect. * @param[out] key The key at the specified index. If the pointer is NULL, it is not returned. * @param[out] value The value at the specified index. If the pointer is NULL, it is not returned. * * @return 0 on success, or 1 if the index is out of range. */ int table_getindex (table_t const *, size_t index, char const **key, void const **value); // In all the below functions, indexcache is an optional variable. If it's non-NULL, it's used both as an input and as an output. // If it's within the length of the table, it will be used as the first guess as for where the key is. // In all cases, if it's non-NULL and the key was found, the indexcache is set to the index at which the key was found. // The point of this is to let callers have the option to cache where a particular key was found, to speed up access time. /** * Gets the value associated with a specific key from the table. * Keep in mind that the data pointed to by value will be the same data stored in the table. * If you want to make a modified copy of the data stored, instead of modifying the data itself, you should use table_getvalcopy() instead. * * @param[in] key A string used to refer to the desired key. * @param[out] value If non-NULL, the value is returned in the variable pointed to by this parameter. * @param[in,out] indexcache If non-NULL, the variable pointed to is first used as an initial guess as to where the key might be found, * and then is set to the index at which the key actually is. * This is compatible with other functions with an indexcache parameter. * @return On success, 0 is returned. If the key isn't found, 1 is returned. */ int table_getval (table_t const *, size_t *indexcache, char const *key, void **value); /** * Gets a copy of the value associated with a specific key from the table. * If you want to access the original data pointed to by the value in the table, you should use table_getval() instead. * If the table doesn't have a copyval() function, it behaves the same as table_getval(). * * @param[in] key A string used to refer to the desired key. * @param[out] value If non-NULL, the copy of the value is returned in the variable pointed to by this parameter. * @param[in,out] indexcache If non-NULL, the variable pointed to is first used as an initial guess as to where the key might be found, and then is used to record the index at which the key actually is. This is compatible with other functions with an indexcache parameter. * * @return On success, 0 is returned. If the key isn't found, 1 is returned. If an allocation error occurs, -1 is returned. */ int table_getvalcopy (table_t const *, size_t *indexcache, char const *key, void **value); /** * Sets the value associated with a specific key in the table, adding the key if it doesn't exist. * If the key is already assigned a non-NULL value and the table has a freeval() function, it is used to free the original value. * If the new value is non-NULL and the table has a copyval() function, it is used to make a copy of the value to assign to the key instead. * * @param[in] key A string used to refer to the desired key. * @param[out] value The value to assign to the key. * @param[in,out] indexcache If non-NULL, the variable pointed to is first used as an initial guess as to where the key might be found, and then is used to record the index at which the key actually is. This is compatible with other functions with an indexcache parameter. * * @return On success, 0 is returned. If an allocation error occurs, -1 is returned. */ int table_setval (table_t *, size_t *indexcache, char const *key, void *value); /** * Sets the value associated with a specific key in the table if it doesn't already exist, or returns an error if it does. * If the new value is non-NULL and the table has a copyval() function, it is used to make a copy of the value to assign to the key instead. * * @param[in] key A string used to refer to the desired key. * @param[out] value The value to assign to the key. * @param[in,out] indexcache If non-NULL, the variable pointed to is first used as an initial guess as to where the key might be found, and then is used to record the index at which the key actually is. This is compatible with other functions with an indexcache parameter. * * @return On success, 0 is returned. If the key already exists, 1 is returned (but indexcache is still updated). If an allocation error occurs, -1 is returned. */ int table_addval (table_t *, size_t *indexcache, char const *key, void *value); /** * Unsets a key in the table, removing it from the table. * If the new value is non-NULL and the table has a copyval() function, it is used to make a copy of the value to assign to the key instead. * Keep in mind that unsetting a key is not the same as setting the key's value to NULL. * * @param[in] key A string used to refer to the desired key. * @param[in,out] indexcache If non-NULL, the variable pointed to is first used as an initial guess as to where the key might be found, and then is used to record the index at which the key actually is. This is compatible with other functions with an indexcache parameter. * * @return On success, 0 is returned. If the key does not exist, 1 is returned. */ int table_unsetval (table_t *, size_t *indexcache, char const *key); #endif