Generic Unordered Set Library (similar to C++ STL unordered_set).
From: Amit
Date: Sun Feb 19 2023 - 02:54:31 EST
Generic Unordered Set Library (similar to C++ STL unordered_set).
The code is below:
-------------------------------------------
generic_unordered_set_library.c
-------------------------------------------
/*
* License: This file has been released under APACHE LICENSE, VERSION 2.0.
* The license details can be found here:
* https://www.apache.org/licenses/LICENSE-2.0
*/
#include "generic_unordered_set_library.h"
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
static void us_get_matching_and_prev_elements(
struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size,
struct element **pmatch, struct element **pprev)
{
struct element *temp = NULL;
struct element *prev = NULL;
*pmatch = NULL;
if (pprev) {
*pprev = NULL;
}
for (prev = NULL, temp = gusc_ptr->first;
temp != NULL;
prev = temp, temp = temp->next) {
if (temp->data_size != data_size) {
continue;
}
if (memcmp(temp->data, data, (size_t)(data_size)) == 0) { //
element matched
*pmatch = temp;
if (pprev) {
*pprev = prev;
}
break;
}
} // end of for loop
return;
} // end of us_get_matching_and_prev_elements
struct generic_unordered_set_container *us_init_generic_unordered_set_container(
call_function_before_deleting_data cfbdd_callback_function)
{
struct generic_unordered_set_container *gusc_ptr = NULL;
gusc_ptr = malloc(sizeof(*gusc_ptr));
if (!gusc_ptr) {
return NULL;
}
gusc_ptr->first = NULL;
gusc_ptr->fi = NULL;
gusc_ptr->total_number_of_elements = 0;
gusc_ptr->cfbdd_callback_function = cfbdd_callback_function;
return gusc_ptr;
} // end of us_init_generic_unordered_set_container
long us_get_total_number_of_elements(
struct generic_unordered_set_container *gusc_ptr)
{
long num_elems = 0;
num_elems = gusc_ptr->total_number_of_elements;
return num_elems;
} // end of us_get_total_number_of_elements
int us_add_new_element(struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size)
{
struct element *matched_elem = NULL;
struct element *prev_elem = NULL;
struct element *new_elem = NULL;
if (!data) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (data_size <= 0) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
us_get_matching_and_prev_elements(gusc_ptr, data, data_size, &matched_elem,
&prev_elem);
if (matched_elem) {
return GUSL_ELEMENT_EXISTS;
}
new_elem = malloc(sizeof(*new_elem));
if (!new_elem) {
return GUSL_NO_MEMORY;
}
new_elem->data = malloc((size_t)(data_size));
if (!new_elem->data) {
free(new_elem);
return GUSL_NO_MEMORY;
}
new_elem->data_size = data_size;
memmove(new_elem->data, data, (size_t)(new_elem->data_size));
new_elem->next = NULL;
if (!prev_elem) { // no elements in the set
gusc_ptr->first = new_elem;
} else {
prev_elem->next = new_elem;
}
gusc_ptr->total_number_of_elements = gusc_ptr->total_number_of_elements + 1;
return GUSL_SUCCESS;
} // end of us_add_new_element
// The user is responsible for freeing the data pointer that is returned in
// *pdata.
int us_get_data_from_front_element_and_delete_front_element(
struct generic_unordered_set_container *gusc_ptr,
void **pdata, long *pdata_size)
{
struct element *temp = NULL;
if ((!pdata) || (!pdata_size)) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
*pdata = NULL;
*pdata_size = 0;
if (gusc_ptr->total_number_of_elements == 0) {
return GUSL_SET_IS_EMPTY;
}
*pdata = gusc_ptr->first->data;
*pdata_size = gusc_ptr->first->data_size;
temp = gusc_ptr->first;
gusc_ptr->first = gusc_ptr->first->next;
temp->next = NULL;
free(temp);
gusc_ptr->total_number_of_elements = gusc_ptr->total_number_of_elements - 1;
return GUSL_SUCCESS;
} // end of us_get_data_from_front_element_and_delete_front_element
int us_is_element_present(struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size)
{
struct element *matched_elem = NULL;
if (!data) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (data_size <= 0) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (gusc_ptr->total_number_of_elements == 0) {
return GUSL_FALSE;
}
us_get_matching_and_prev_elements(gusc_ptr, data, data_size, &matched_elem,
NULL);
if (matched_elem) {
return GUSL_TRUE;
}
return GUSL_FALSE;
} // end of us_is_element_present
int us_replace_data_and_size_in_matching_element(
struct generic_unordered_set_container *gusc_ptr,
void *old_data, long old_data_size,
void *new_data, long new_data_size)
{
struct element *matched_elem = NULL;
void *data = NULL;
if ((!old_data) || (!new_data)) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if ((old_data_size <= 0) || (new_data_size <= 0)) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (gusc_ptr->total_number_of_elements == 0) {
return GUSL_SET_IS_EMPTY;
}
us_get_matching_and_prev_elements(gusc_ptr, old_data, old_data_size,
&matched_elem, NULL);
if (!matched_elem) {
return GUSL_ELEMENT_NOT_FOUND;
}
// We will allocate memory for contents of new_data and copy contents of
// new_data into this newly allocated memory. Then we will free old_data
// and populate the data member of the matched_elem with the address of the
// newly allocated memory. We will also populate the data_size member of
// the matched_elem with the value in new_data_size.
data = malloc((size_t)(new_data_size));
if (!data) {
return GUSL_NO_MEMORY;
}
memmove(data, new_data, (size_t)(new_data_size));
if (gusc_ptr->cfbdd_callback_function) {
gusc_ptr->cfbdd_callback_function(gusc_ptr, matched_elem->data);
}
free(matched_elem->data);
matched_elem->data = data;
matched_elem->data_size = new_data_size;
return GUSL_SUCCESS;
} // end of us_replace_data_and_size_in_matching_element
int us_delete_matching_element(
struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size)
{
struct element *matched_elem = NULL;
struct element *prev_elem = NULL;
if (!data) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (data_size <= 0) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
if (gusc_ptr->total_number_of_elements == 0) {
return GUSL_SET_IS_EMPTY;
}
us_get_matching_and_prev_elements(gusc_ptr, data, data_size, &matched_elem,
&prev_elem);
if (!matched_elem) {
return GUSL_ELEMENT_NOT_FOUND;
}
if (!prev_elem) { // first element matched
gusc_ptr->first = gusc_ptr->first->next;
} else {
prev_elem->next = matched_elem->next;
}
matched_elem->next = NULL;
if (gusc_ptr->cfbdd_callback_function) {
gusc_ptr->cfbdd_callback_function(gusc_ptr, matched_elem->data);
}
gusc_ptr->total_number_of_elements = gusc_ptr->total_number_of_elements - 1;
free(matched_elem->data);
free(matched_elem);
return GUSL_SUCCESS;
} // end of us_delete_matching_element
void us_init_fi(struct generic_unordered_set_container *gusc_ptr)
{
gusc_ptr->fi = gusc_ptr->first;
return;
} // end of us_init_fi
int us_fi_has_next_element(struct generic_unordered_set_container *gusc_ptr)
{
int has_next = GUSL_FALSE;
if (gusc_ptr->fi) {
has_next = GUSL_TRUE;
}
return has_next;
} // end of us_fi_has_next_element
// The user should not free the data pointer that is returned in *pdata because
// the element that contains the data is still part of the set. However, the
// user can modify the data and then modify data_size if the size of data has
// changed.
int us_fi_get_data_from_next_element(
struct generic_unordered_set_container *gusc_ptr,
void **pdata, long **ppdata_size)
{
if ((!pdata) || (!ppdata_size)) {
return GUSL_AT_LEAST_ONE_ARG_IS_INVALID;
}
*pdata = NULL;
*ppdata_size = 0;
*pdata = gusc_ptr->fi->data;
*ppdata_size = &(gusc_ptr->fi->data_size);
gusc_ptr->fi = gusc_ptr->fi->next;
return GUSL_SUCCESS;
} // end of us_fi_get_data_from_next_element
void us_delete_all_elements(struct generic_unordered_set_container *gusc_ptr)
{
struct element *temp = NULL;
while ((temp = gusc_ptr->first)) {
gusc_ptr->first = gusc_ptr->first->next;
temp->next = NULL;
if (gusc_ptr->cfbdd_callback_function) {
gusc_ptr->cfbdd_callback_function(gusc_ptr, temp->data);
}
free(temp->data);
free(temp);
gusc_ptr->total_number_of_elements =
gusc_ptr->total_number_of_elements - 1;
}
// crash the program if total_number_of_elements is not zero
if (gusc_ptr->total_number_of_elements != 0) {
*((unsigned long *)(-1)) = 123;
}
return;
} // end of us_delete_all_elements
void us_delete_container(struct generic_unordered_set_container *gusc_ptr)
{
us_delete_all_elements(gusc_ptr);
free(gusc_ptr);
return;
} // end of us_delete_container
-------------------------------------------
generic_unordered_set_library.h
-------------------------------------------
/*
* License: This file has been released under APACHE LICENSE, VERSION 2.0.
* The license details can be found here:
* https://www.apache.org/licenses/LICENSE-2.0
*/
#ifndef _GENERIC_UNORDERED_SET_LIBRARY_H_
#define _GENERIC_UNORDERED_SET_LIBRARY_H_
#define GUSL_SUCCESS 2 // everything happened successfully
#define GUSL_TRUE 1 // true
#define GUSL_FALSE 0 // false
#define GUSL_AT_LEAST_ONE_ARG_IS_INVALID -1 // at least one argument is invalid
#define GUSL_NO_MEMORY -2 // no memory available
#define GUSL_ELEMENT_EXISTS -3 // element already exists in the set
#define GUSL_SET_IS_EMPTY -4 // there are no elements in the set
#define GUSL_ELEMENT_NOT_FOUND -5 // element not found in the set
struct generic_unordered_set_container;
struct element
{
void *data;
long data_size;
struct element *next;
};
// gusc_ptr needs to be sent because in case the user has created more than
// one container and the user stores different 'data' in each container, then
// the user will be able to identify that the 'data' belongs to which container.
// Otherwise, the user won't be able to identify that the 'data' belongs to
// which container and then things won't happen correctly.
typedef void (*call_function_before_deleting_data)(
struct generic_unordered_set_container *gusc_ptr,
void *data);
struct generic_unordered_set_container
{
struct element *first;
struct element *fi; // fi stands for forward iterator
long total_number_of_elements;
// callback function
call_function_before_deleting_data cfbdd_callback_function;
};
/*
* Names of functions start with the prefix us_. us_ stands for unordered set.
*
* In this software, delete and free mean the same thing.
*/
struct generic_unordered_set_container *us_init_generic_unordered_set_container(
call_function_before_deleting_data cfbdd_callback_function);
long us_get_total_number_of_elements(
struct generic_unordered_set_container *gusc_ptr);
int us_add_new_element(struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size);
int us_get_data_from_front_element_and_delete_front_element(
struct generic_unordered_set_container *gusc_ptr,
void **pdata, long *pdata_size);
int us_is_element_present(struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size);
int us_replace_data_and_size_in_matching_element(
struct generic_unordered_set_container *gusc_ptr,
void *old_data, long old_data_size,
void *new_data, long new_data_size);
int us_delete_matching_element(
struct generic_unordered_set_container *gusc_ptr,
void *data, long data_size);
void us_init_fi(struct generic_unordered_set_container *gusc_ptr);
int us_fi_has_next_element(struct generic_unordered_set_container *gusc_ptr);
int us_fi_get_data_from_next_element(
struct generic_unordered_set_container *gusc_ptr,
void **pdata, long **ppdata_size);
void us_delete_all_elements(struct generic_unordered_set_container *gusc_ptr);
void us_delete_container(struct generic_unordered_set_container *gusc_ptr);
#endif