summaryrefslogtreecommitdiffstats
path: root/src/lisiblestd/vec.h
blob: 6592bc40d98b0989b9711f82d253627a47a7c2f9 (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
#ifndef LSTD_VEC_H
#define LSTD_VEC_H

#include "assert.h"
#include "memory.h"
#include "types.h"
#include <stdlib.h>
#include <string.h>

#define DECL_VEC(T, name)                                                      \
  struct name {                                                                \
    Allocator *allocator;                                                      \
    T *data;                                                                   \
    size_t length;                                                             \
    size_t capacity;                                                           \
  };                                                                           \
  typedef struct name name;                                                    \
  void name##_init(Allocator *allocator, name *vec);                           \
  void name##_deinit(name *vec);                                               \
  void name##_reserve(name *vec, size_t length_to_reserve);                    \
  void name##_push_back(name *vec, T value);                                   \
  T name##_pop_back(name *vec);                                                \
  void name##_append(name *vec, const T *values, size_t count);                \
  void name##_clear(name *vec);                                                \
  size_t name##_length(name *vec);                                             \
  size_t name##_capacity(name *vec);

#define DEF_VEC(T, name, initial_capacity)                                     \
  void name##_init(Allocator *allocator, name *vec) {                          \
    LSTD_ASSERT(vec != NULL);                                                  \
    vec->allocator = allocator;                                                \
    vec->capacity = initial_capacity;                                          \
    vec->data = Allocator_allocate(allocator, vec->capacity * sizeof(T));      \
    vec->length = 0;                                                           \
  }                                                                            \
  void name##_deinit(name *vec) {                                              \
    LSTD_ASSERT(vec != NULL);                                                  \
    Allocator_free(vec->allocator, vec->data);                                 \
    vec->data = NULL;                                                          \
    vec->capacity = 0;                                                         \
    vec->length = 0;                                                           \
  }                                                                            \
  void name##_reserve(name *vec, size_t length_to_reserve) {                   \
    LSTD_ASSERT(vec != NULL);                                                  \
    if (vec->length + length_to_reserve < vec->capacity) {                     \
      /* No need to reallocate as there is still enough capacity */            \
      return;                                                                  \
    }                                                                          \
                                                                               \
    size_t new_capacity = vec->capacity * 2;                                   \
    if (vec->length + length_to_reserve > new_capacity) {                      \
      new_capacity = vec->length + length_to_reserve;                          \
    }                                                                          \
                                                                               \
    vec->data = Allocator_reallocate(vec->allocator, vec->data,                \
                                     vec->capacity * sizeof(T),                \
                                     new_capacity * sizeof(T));                \
    if (!vec->data) {                                                          \
      /* TODO maybe improve that error handling? */                            \
      LOG0_ERROR("Vec reallocation failed, no memory left");                   \
      abort();                                                                 \
    }                                                                          \
    vec->capacity = new_capacity;                                              \
  }                                                                            \
  void name##_push_back(name *vec, T value) {                                  \
    LSTD_ASSERT(vec != NULL);                                                  \
    name##_reserve(vec, vec->length + 1);                                      \
    vec->data[vec->length] = value;                                            \
    vec->length++;                                                             \
  }                                                                            \
  T name##_pop_back(name *vec) {                                               \
    LSTD_ASSERT(vec != NULL);                                                  \
    vec->length--;                                                             \
    return vec->data[vec->length];                                             \
  }                                                                            \
  void name##_append(name *vec, const T *values, size_t count) {               \
    LSTD_ASSERT(vec != NULL);                                                  \
    LSTD_ASSERT(values != NULL);                                               \
    name##_reserve(vec, vec->length + count);                                  \
    memmove(&vec->data[vec->length], values, count * sizeof(T));               \
    vec->length += count;                                                      \
  }                                                                            \
  void name##_clear(name *vec) {                                               \
    LSTD_ASSERT(vec != NULL);                                                  \
    vec->length = 0;                                                           \
  }                                                                            \
  size_t name##_length(name *vec) {                                            \
    LSTD_ASSERT(vec != NULL);                                                  \
    return vec->length;                                                        \
  }                                                                            \
  size_t name##_capacity(name *vec) {                                          \
    LSTD_ASSERT(vec != NULL);                                                  \
    return vec->capacity;                                                      \
  }

#define VEC_IMPL(T, name, initial_capacity)                                    \
  DECL_VEC(T, name)                                                            \
  DEF_VEC(T, name, initial_capacity)

#define VEC_FOR_EACH(vec, elt_identifier, T, ...)                              \
  do {                                                                         \
    for (size_t i = 0; i < (vec)->length; i++) {                               \
      T *elt_identifier = &(vec)->data[i];                                     \
      __VA_ARGS__                                                              \
    }                                                                          \
  } while (0);

DECL_VEC(char *, StringVec)
DECL_VEC(u8, u8vec)

#endif // LSTD_VEC_H
Go back to lisible.xyz