summaryrefslogtreecommitdiffstats
path: root/lib/vector.c
blob: eb7233cf31a5447cc8aec63a55a63ac40f7777c7 (plain) (blame)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "vector.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

struct vl__vector_tag {
  size_t cap, sz, len;
  void *data; /* cap * len */
};

vl_vector *vl_vector_new(size_t sz)
{
  return vl_vector_new_ex(sz, 16);
}

vl_vector *vl_vector_new_ex(size_t sz, size_t init_cap)
{
  vl_vector *vec = calloc(1, sizeof(vl_vector));
  if (!vec) return NULL;

  if (init_cap < 16) init_cap = 16;

  vec->cap = init_cap;
  vec->len = 0;
  vec->sz = sz;

  void *data = calloc(init_cap, sz);
  if (!data) {
    free(vec);
    return NULL;
  }

  vec->data = data;

  return vec;
}

void vl_vector_free(vl_vector *vec)
{
  if (!vec) return;

  free(vec->data);
  free(vec);
}

static int vec_grow(vl_vector *vec, size_t newlen)
{
  void *temp = reallocarray(vec->data, newlen, vec->sz);
  if (!temp) return -1;
  vec->data = temp;

  return 0;
}

static size_t next_po2(size_t sz)
{
  assert(sz > 0);
  return (size_t)(1 << (64 - __builtin_clzll((unsigned long long)sz)));
}

static int ensure_fits(vl_vector *vec, size_t toadd)
{
  if (vec->len + toadd <= vec->cap) {
    return 0;
  }

  size_t newcap = next_po2(vec->len + toadd);
  return vec_grow(vec, newcap);
}

/* will abort if realloc fails to shrink the allocation (should never happen) */
void vl_vector_shrink_to_size(vl_vector *vec)
{
  if (vec_grow(vec, vec->len) < 0) abort();
}

#define vl_newvec(_t) vl_vector_new(sizeof(_t))
#define vl_newvec_ex(_t, _ic) vl_vector_new_ex(sizeof(_t), _ic)

int vl_vector_push(vl_vector *vec, void *data)
{
  return vl_vector_push_vec(vec, data, 1);
}

int vl_vector_push_vec(vl_vector *vec, void *data, size_t n)
{
  if (ensure_fits(vec, n) < 0) {
    return -1;
  }

  unsigned char *d = vec->data;
  memcpy(d + (vec->len * vec->sz), data, n * vec->sz);
  vec->len += n;
  return 0;
}

int vl_vector_push_2d(vl_vector *vec, void **data, size_t n)
{
  if (ensure_fits(vec, n) < 0) {
    return -1;
  }

  unsigned char *d = vec->data;
  for (size_t i = 0; i < n; ++i) {
    memcpy(d + ((vec->len + i) * vec->sz), data[i], vec->sz);
  }

  vec->len += n;

  return 0;
}

size_t vl_vector_size(const vl_vector *vec)
{
  return vec->len;
}

void *vl_vector_values(const vl_vector *vec, size_t *psz)
{
  if (psz) *psz = vec->len;
  return vec->data;
}