Skip to content
Snippets Groups Projects
Commit 721ed2f0 authored by Bruce Cowan's avatar Bruce Cowan :airplane:
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
array.c 0 → 100644
#include <math.h>
#include <stdbool.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "array.h"
#include "mem.h"
#define MIN_SIZE 2
struct _Array
{
void **data;
size_t length;
size_t capacity;
FreeFunc free_func;
atomic_int ref_count;
};
static void
resize_array (Array *array,
size_t required)
{
size_t size = MIN_SIZE;
while (size < required)
{
size = (size_t) ceil (size * 1.5);
}
array->data = check_realloc (array->data, sizeof (void *) * size);
array->capacity = size;
}
static bool
index_in_array (const Array *array,
size_t index)
{
if (index < array->length)
return true;
else
{
fprintf (stderr, "ERROR: Index %zu of array %p is not valid\n", index, array);
return false;
}
}
static void
maybe_shrink (Array *array)
{
if (array->length <= (size_t) ceil (array->capacity * 0.3))
resize_array (array, array->length);
}
/**
* array_new:
* @func: (nullable): A #FreeFunc which is used to free deleted items
*
* Creates a new #Array.
*
* Returns: The new #Array, free with array_free()
*/
Array *
array_new (FreeFunc func)
{
Array *array = check_malloc (sizeof (Array));
array->data = check_malloc (sizeof (void *) * MIN_SIZE);
array->length = 0;
array->capacity = MIN_SIZE;
array->free_func = func;
return array;
}
/**
* array_ref:
* @array: The array to increase the reference count of
*
* Increase the reference account of the array.
*
* Returns: The array
*/
Array *
array_ref (Array *array)
{
atomic_fetch_add (&array->ref_count, 1);
return array;
}
/**
* array_unref:
* @array: The array to decrease the reference count of
*
* Decrease the reference account of the array. If it becomes 0, it will be
* freed.
*/
void
array_unref (Array *array)
{
if (atomic_fetch_sub (&array->ref_count, 1) == 1)
{
if (array->free_func)
{
for (size_t i = 0; i < array->length; i++)
array->free_func (array->data[i]);
}
free (array->data);
free (array);
}
}
/**
* array_add:
* @array: An array
* @val: The value to add to the array
*
* Adds a value to an array.
*/
void
array_add (Array *array,
const void *val)
{
if (array->length == array->capacity)
resize_array (array, array->length + 1);
array->data[array->length] = (void *) val;
array->length += 1;
}
/**
* array_remove_fast:
* @array: An array
* @index: The index of the item to remove from @array
*
* Removes an item from an array. This function copies the last member of the
* array to the location of the item to be removed, which means that ordering
* is not preserved.
*/
void
array_remove_fast (Array *array,
size_t index)
{
if (!index_in_array (array, index))
return;
if (array->free_func)
array->free_func (array->data[index]);
void *last = array->data[array->length - 1];
array->data[index] = last;
array->length -= 1;
maybe_shrink (array);
}
/**
* array_remove:
* @array: An array
* @index: The index of the item to remove from @array
*
* Removes an item from an array. This function moves the items following the
* removed item down one space. This preserves the ordering of the items, but is
* slower than array_remove_fast().
*/
void
array_remove (Array *array,
size_t index)
{
if (!index_in_array (array, index))
return;
if (array->free_func)
array->free_func (array->data[index]);
memmove (array->data + index,
array->data + index + 1,
sizeof (void *) * (array->length - index - 1));
array->length -= 1;
maybe_shrink (array);
}
/**
* array_set:
* @array: An array
* @index: The index of the item to set a value for
* @val: The value to set the item to
*
* Sets an element of @array to @val, using the @index.
*/
void
array_set (Array *array,
size_t index,
const void *val)
{
if (!index_in_array (array, index))
return;
array->data[index] = (void *) val;
}
/**
* array_get:
* @array: An array
* @index: The index of @array to get a value from
*
* Get a value of @array, using @index.
*
* Returns: (transfer none): The value at @index of @array
*/
const void *
array_get (const Array *array,
size_t index)
{
if (index_in_array (array, index))
return array->data[index];
else
return NULL;
}
/**
* array_get_length:
* @array: An array
*
* Gets the number of elements in an array.
*
* Returns: The length of the array
*/
size_t
array_get_length (const Array *array)
{
return array->length;
}
/**
* array_get_capacity:
* @array: An array
*
* Get the capacity (proportional to memory usage) of @array.
*
* Returns: The capacity, in items.
*/
size_t
array_get_capacity (const Array *array)
{
return array->capacity;
}
/**
* array_total_val:
* @array: An array
* @func: A function which converts the contained data into doubles
*
* Gets the total value of the array.
*
* Returns: The total value of the array.
*/
double
array_total_val (const Array *array,
ValueFunc func)
{
double total = 0;
for (int i = 0; i < array->length; i++)
total += func (array->data[i]);
return total;
}
/**
* array_average_val:
* @array: An array
* @func: A function which converts the contained data into ints
*
* Gets the average value of the array.
*
* Returns: The average value of the array.
*/
double
array_average_val (const Array *array,
ValueFunc func)
{
return array_total_val (array, func) / array->length;
}
/**
* array_sort:
* @array: An array
* @func: A function which returns -1 for less than, 0 for equal, and 1 for more than
*
* Sorts the array
*/
void
array_sort (Array *array,
CompareFunc func)
{
qsort (*array->data, array->length, sizeof (void *), func);
}
array.h 0 → 100644
#pragma once
#include <stddef.h>
typedef struct _Array Array;
typedef void (*FreeFunc) (void *element);
typedef double (*ValueFunc) (const void *element);
typedef int (*CompareFunc) (const void *a, const void *b);
// Fundamental functions
Array * array_new (FreeFunc func);
Array * array_ref (Array *array);
void array_unref (Array *array);
void array_add (Array *array,
const void *val);
void array_remove_fast (Array *array,
size_t index);
void array_remove (Array *array,
size_t index);
void array_set (Array *array,
size_t index,
const void *val);
// Getters
const void * array_get (const Array *array,
size_t index);
size_t array_get_length (const Array *array);
size_t array_get_capacity (const Array *array);
// Aggregate functions
double array_total_val (const Array *array,
ValueFunc func);
double array_average_val (const Array *array,
ValueFunc func);
// Misc
void array_sort (Array *array,
CompareFunc func);
mem.c 0 → 100644
#include "mem.h"
#include <stdlib.h>
void *
check_malloc (size_t size)
{
void *ptr = malloc (size);
if (!ptr)
exit (EXIT_FAILURE);
return ptr;
}
void *
check_realloc (void *ptr,
size_t size)
{
void *new = realloc (ptr, size);
if (!new)
exit (EXIT_FAILURE);
return new;
}
mem.h 0 → 100644
#pragma once
#include <stddef.h>
void * check_malloc (size_t size);
void * check_realloc (void *ptr,
size_t size);
project('array', 'c')
cc = meson.get_compiler('c')
m = cc.find_library('m')
l_src = ['array.c', 'mem.c']
lib = shared_library('array', l_src, dependencies: m)
executable('testarray', 'testarray.c', link_with: lib)
executable('pavg', 'pavg.c', link_with: lib)
pavg.c 0 → 100644
#include <stdio.h>
#include <stdlib.h>
#include "array.h"
#define INT_TO_PTR(x) ((void *) (size_t) (x))
#define PTR_TO_INT(x) ((int) (size_t) (x))
static double
array_to_int (const void *data)
{
return (double) PTR_TO_INT (data);
}
static void
print_array (Array *array)
{
size_t length = array_get_length (array);
printf ("Array at %p is of length %zu\n", array, length);
printf ("Array has capacity %zu\n", array_get_capacity (array));
double total = array_total_val (array, array_to_int);
double average = array_average_val (array, array_to_int);
printf ("Array total is %lf\n", total);
printf ("Array average is %lf\n", average);
}
static Array *
create_test_array (size_t start,
size_t end)
{
Array *array = array_new (NULL);
for (size_t i = start; i < end; i++)
array_add (array, INT_TO_PTR (i));
return array;
}
int
main (void)
{
Array *array = create_test_array (0, 100);
print_array (array);
return EXIT_SUCCESS;
}
#define _GNU_SOURCE // For asprintf
#include <stdio.h>
#include <stdlib.h>
#include "array.h"
static void
print_array (Array *array)
{
size_t length = array_get_length (array);
printf ("Array at %p is of length %zu\n", array, length);
printf ("Array has capacity %zu\n", array_get_capacity (array));
for (size_t i = 0; i < length; i++)
{
const char *str = (const char *) array_get (array, i);
printf ("Array member %zu has value %s\n", i, str);
}
}
static Array *
create_test_array (size_t start,
size_t end)
{
Array *array = array_new (free);
for (size_t i = start; i < end; i++)
{
char *str;
if (asprintf (&str, "String #%zu", i) < 0)
exit (EXIT_FAILURE);
array_add (array, str);
}
return array;
}
static void
remove_array_items_fast (Array *array,
size_t start,
size_t num)
{
for (int i = 0; i < num; i++)
array_remove_fast (array, start);
}
static void
remove_array_items (Array *array,
size_t start,
size_t num)
{
for (size_t i = 0; i < num; i++)
array_remove (array, start);
}
int
main (void)
{
printf ("Slow\n----\n");
Array *array = create_test_array (0, 100);
print_array (array);
remove_array_items (array, 20, 70);
print_array (array);
array_unref (array);
printf ("Fast\n----\n");
array = create_test_array (0, 100);
print_array (array);
remove_array_items_fast (array, 20, 70);
print_array (array);
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment