summaryrefslogtreecommitdiff
path: root/array.c
blob: aa8d4e084d44337930d58fc63a68851f70af6ed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <string.h>
#include "array.h"

/* Invariant: There are always >= next_pot(n_elements) elements
 * allocated for data.
 */
struct array_t
{
    size_t      element_size;
    size_t      n_elements;
    /* uint8_t     data[]; */
};

static size_t
next_pot (size_t n)
{
    n -= 1;
        
    n |= (n >>  1);
    n |= (n >>  2);
    n |= (n >>  4);
    n |= (n >>  8);
    n |= (n >> 16);
    if (sizeof (n) > 4)
        n |= (n >> 32);

    return n + 1;
}

static bool_t
array_reallocate (array_t **array, size_t n_elements)
{
    size_t alloc = next_pot (n_elements);

    if (alloc != next_pot ((*array)->n_elements))
    {
        array_t *new_array;

        if (!(new_array = realloc (
                  (*array), sizeof (array_t) + alloc * (*array)->element_size)))
            return FALSE;

        *array = new_array;
    }

    (*array)->n_elements = n_elements;
    return TRUE;
}

bool_t
array_create (array_t **array, size_t element_size)
{
    if (!(*array = malloc (sizeof (array_t))))
        return FALSE;

    (*array)->element_size = element_size;
    (*array)->n_elements = 0;

    return TRUE;
}

/* Delete the last n_elements */
void
array_delete_tail (array_t **array, size_t n_delete)
{
    array_reallocate (array, (*array)->n_elements - n_delete);
}

void
array_free (array_t **array)
{
    free (*array);
    *array = NULL;
}

void *
array_get_data (array_t **array, size_t *n_elements)
{
    if (n_elements)
        *n_elements = (*array)->n_elements;

    return (*array) + 1;
}

bool_t
array_append (array_t **array, size_t n_elements, void *tail)
{
    size_t old_n_elements = (*array)->n_elements;
    size_t tail_offset = old_n_elements * (*array)->element_size;
    
    if (!array_reallocate (array, old_n_elements + n_elements))
        return FALSE;

    if (tail)
        *(void **)tail = ((uint8_t *)((*array) + 1)) + tail_offset;

    return TRUE;
}