summaryrefslogtreecommitdiff
path: root/src/array.cc
blob: f522bfc91bcb672510f3574504791dd65f158277 (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
99
#ifndef ARRAY_CC
#define ARRAY_CC

#include "memory.cc"

#define ARRAY_INIT 4
#define ARRAY_GROWTH 2

template <typename T>
struct Array {
  usize capacity, size;
  T* data;
  const Allocator* allocator;
};

#define array_init(T, allocator) \
  Array<T> { 0, 0, nullptr, allocator }

template<typename T>
static inline usize array_nbytes(usize size) {
  assert_neq(size, 0);
  return size * sizeof(T);
}

template<typename T>
static inline usize array_next_capacity(const Array<T>* array) {
  assert_neq(array, nullptr);
  return array->capacity == 0 ? ARRAY_INIT : array->capacity * ARRAY_GROWTH;
}

template<typename T>
bool array_resize(Array<T>* array, usize new_capacity) {
  assert_neq(array, nullptr);
  assert_st(array->size, new_capacity);

  T* new_data = (T*)allocate(array->allocator, array_nbytes<T>(new_capacity), alignof(T));
  if(new_data == nullptr) return false;

  memcpy(new_data, array->data, array_nbytes<T>(new_capacity));
  deallocate(array->allocator, (u8*)array->data);

  array->data = new_data;
  array->capacity = new_capacity;
  return true;
}

template<typename T>
static inline bool array_grow_if_needed(Array<T>* array) {
  assert_neq(array, nullptr);
  assert_ste(array->size, array->capacity);
  
  if(array->size < array->capacity) return true;

  usize new_capacity = array_next_capacity(array);
  return array_resize(array, new_capacity);
}

template<typename T>
static inline T* array_at(const Array<T>* array, usize index) {
  assert_neq(array, nullptr);
  assert_st(index, array->capacity);

  return array->data + index;
}

template<typename T>
inline T* array_last(const Array<T>* array) {
  assert_neq(array, nullptr);

  if(array->size == 0) return nullptr;
  return array_at(array, array->size - 1);
}

template<typename T>
bool array_push(Array<T>* array, T* item) {
  assert_neq(array, nullptr);
  assert_neq(item, nullptr);

  bool ret = array_grow_if_needed(array);
  if(!ret) return false;

  T* loc = array_at(array, array->size);
  memcpy(loc, item, sizeof(T));
  array->size += 1;

  return true;
}

template <typename T>
void array_deinit(Array<T>* array) {
  assert_neq(array, nullptr);
  
  if (unlikely(array->data == nullptr)) return;

  deallocate(array->allocator, (u8*)array->data);
  memset(array, 0, sizeof(*array));  
}

#endif