plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


plum-tooling/tree-sitter-plum/src/tree_sitter/array.h
5d12d71 1
#ifndef TREE_SITTER_ARRAY_H_
5d12d71 2
#define TREE_SITTER_ARRAY_H_
5d12d71 3
5d12d71 4
#ifdef __cplusplus
5d12d71 5
extern "C" {
5d12d71 6
#endif
5d12d71 7
5d12d71 8
#include "./alloc.h"
5d12d71 9
5d12d71 10
#include <assert.h>
5d12d71 11
#include <stdbool.h>
5d12d71 12
#include <stdint.h>
5d12d71 13
#include <stdlib.h>
5d12d71 14
#include <string.h>
5d12d71 15
5d12d71 16
#ifdef _MSC_VER
0d43379 17
#pragma warning(push)
5d12d71 18
#pragma warning(disable : 4101)
5d12d71 19
#elif defined(__GNUC__) || defined(__clang__)
5d12d71 20
#pragma GCC diagnostic push
5d12d71 21
#pragma GCC diagnostic ignored "-Wunused-variable"
5d12d71 22
#endif
5d12d71 23
5d12d71 24
#define Array(T)       \
5d12d71 25
  struct {             \
5d12d71 26
    T *contents;       \
5d12d71 27
    uint32_t size;     \
5d12d71 28
    uint32_t capacity; \
5d12d71 29
  }
5d12d71 30
5d12d71 31
/// Initialize an array.
5d12d71 32
#define array_init(self) \
5d12d71 33
  ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
5d12d71 34
5d12d71 35
/// Create an empty array.
5d12d71 36
#define array_new() \
5d12d71 37
  { NULL, 0, 0 }
5d12d71 38
5d12d71 39
/// Get a pointer to the element at a given `index` in the array.
5d12d71 40
#define array_get(self, _index) \
5d12d71 41
  (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
5d12d71 42
5d12d71 43
/// Get a pointer to the first element in the array.
5d12d71 44
#define array_front(self) array_get(self, 0)
5d12d71 45
5d12d71 46
/// Get a pointer to the last element in the array.
5d12d71 47
#define array_back(self) array_get(self, (self)->size - 1)
5d12d71 48
5d12d71 49
/// Clear the array, setting its size to zero. Note that this does not free any
5d12d71 50
/// memory allocated for the array's contents.
5d12d71 51
#define array_clear(self) ((self)->size = 0)
5d12d71 52
f502d22 53
#ifdef __cplusplus
f502d22 54
#define _array__cast(self, expr) (decltype((self)->contents))(expr)
f502d22 55
#else
f502d22 56
#define _array__cast(self, expr) (expr)
f502d22 57
#endif
f502d22 58
5d12d71 59
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
5d12d71 60
/// less than the array's current capacity, this function has no effect.
f502d22 61
#define array_reserve(self, new_capacity)                 \
f502d22 62
  ((self)->contents = _array__cast(self, _array__reserve( \
f502d22 63
    (void *)(self)->contents, &(self)->capacity,          \
f502d22 64
    array_elem_size(self), new_capacity))                 \
f502d22 65
  )
5d12d71 66
5d12d71 67
/// Free any memory allocated for this array. Note that this does not free any
5d12d71 68
/// memory allocated for the array's contents.
f502d22 69
#define array_delete(self)                           \
f502d22 70
  do {                                               \
f502d22 71
    if ((self)->contents) ts_free((self)->contents); \
f502d22 72
    (self)->contents = NULL;                         \
f502d22 73
    (self)->size = 0;                                \
f502d22 74
    (self)->capacity = 0;                            \
f502d22 75
  } while (0)
5d12d71 76
5d12d71 77
/// Push a new `element` onto the end of the array.
f502d22 78
#define array_push(self, element)                                 \
f502d22 79
  do {                                                            \
f502d22 80
    (self)->contents = _array__cast(self, _array__grow(           \
f502d22 81
      (void *)(self)->contents, (self)->size, &(self)->capacity,  \
f502d22 82
      1, array_elem_size(self)                                    \
f502d22 83
    ));                                                           \
f502d22 84
   (self)->contents[(self)->size++] = (element);                  \
f502d22 85
  } while(0)
5d12d71 86
5d12d71 87
/// Increase the array's size by `count` elements.
5d12d71 88
/// New elements are zero-initialized.
f502d22 89
#define array_grow_by(self, count)                                               \
f502d22 90
  do {                                                                           \
f502d22 91
    if ((count) == 0) break;                                                     \
f502d22 92
    (self)->contents = _array__cast(self, _array__grow(                          \
f502d22 93
      (self)->contents, (self)->size, &(self)->capacity,                         \
f502d22 94
      count, array_elem_size(self)                                               \
f502d22 95
    ));                                                                          \
5d12d71 96
    memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
f502d22 97
    (self)->size += (count);                                                     \
5d12d71 98
  } while (0)
5d12d71 99
5d12d71 100
/// Append all elements from one array to the end of another.
f502d22 101
#define array_push_all(self, other) \
5d12d71 102
  array_extend((self), (other)->size, (other)->contents)
5d12d71 103
5d12d71 104
/// Append `count` elements to the end of the array, reading their values from the
5d12d71 105
/// `contents` pointer.
f502d22 106
#define array_extend(self, count, other_contents)                 \
f502d22 107
  ((self)->contents = _array__cast(self, _array__splice(          \
f502d22 108
    (void*)(self)->contents, &(self)->size, &(self)->capacity,    \
f502d22 109
    array_elem_size(self), (self)->size, 0, count, other_contents \
f502d22 110
  )))
5d12d71 111
5d12d71 112
/// Remove `old_count` elements from the array starting at the given `index`. At
5d12d71 113
/// the same index, insert `new_count` new elements, reading their values from the
5d12d71 114
/// `new_contents` pointer.
f502d22 115
#define array_splice(self, _index, old_count, new_count, new_contents) \
f502d22 116
  ((self)->contents = _array__cast(self, _array__splice(              \
f502d22 117
    (void *)(self)->contents, &(self)->size, &(self)->capacity,        \
f502d22 118
    array_elem_size(self), _index, old_count, new_count, new_contents  \
f502d22 119
  )))
5d12d71 120
5d12d71 121
/// Insert one `element` into the array at the given `index`.
f502d22 122
#define array_insert(self, _index, element)                     \
f502d22 123
  ((self)->contents = _array__cast(self, _array__splice(        \
f502d22 124
    (void *)(self)->contents, &(self)->size, &(self)->capacity, \
f502d22 125
    array_elem_size(self), _index, 0, 1, &(element)             \
f502d22 126
  )))
5d12d71 127
5d12d71 128
/// Remove one element from the array at the given `index`.
5d12d71 129
#define array_erase(self, _index) \
f502d22 130
  _array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
5d12d71 131
5d12d71 132
/// Pop the last element off the array, returning the element by value.
5d12d71 133
#define array_pop(self) ((self)->contents[--(self)->size])
5d12d71 134
5d12d71 135
/// Assign the contents of one array to another, reallocating if necessary.
f502d22 136
#define array_assign(self, other)                                   \
f502d22 137
  ((self)->contents = _array__cast(self, _array__assign(            \
f502d22 138
    (void *)(self)->contents, &(self)->size, &(self)->capacity,     \
f502d22 139
    (const void *)(other)->contents, (other)->size, array_elem_size(self) \
f502d22 140
  )))
5d12d71 141
5d12d71 142
/// Swap one array with another
f502d22 143
#define array_swap(self, other)                                     \
f502d22 144
  do {                                                              \
f502d22 145
    void *_array_swap_tmp = (void *)(self)->contents;               \
f502d22 146
    (self)->contents = (other)->contents;                           \
f502d22 147
    (other)->contents = _array__cast(other, _array_swap_tmp);       \
f502d22 148
    _array__swap(&(self)->size, &(self)->capacity,                  \
f502d22 149
                 &(other)->size, &(other)->capacity);               \
f502d22 150
  } while (0)
5d12d71 151
5d12d71 152
/// Get the size of the array contents
5d12d71 153
#define array_elem_size(self) (sizeof *(self)->contents)
5d12d71 154
5d12d71 155
/// Search a sorted array for a given `needle` value, using the given `compare`
5d12d71 156
/// callback to determine the order.
5d12d71 157
///
5d12d71 158
/// If an existing element is found to be equal to `needle`, then the `index`
5d12d71 159
/// out-parameter is set to the existing value's index, and the `exists`
5d12d71 160
/// out-parameter is set to true. Otherwise, `index` is set to an index where
5d12d71 161
/// `needle` should be inserted in order to preserve the sorting, and `exists`
5d12d71 162
/// is set to false.
5d12d71 163
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
5d12d71 164
  _array__search_sorted(self, 0, compare, , needle, _index, _exists)
5d12d71 165
5d12d71 166
/// Search a sorted array for a given `needle` value, using integer comparisons
5d12d71 167
/// of a given struct field (specified with a leading dot) to determine the order.
5d12d71 168
///
5d12d71 169
/// See also `array_search_sorted_with`.
5d12d71 170
#define array_search_sorted_by(self, field, needle, _index, _exists) \
5d12d71 171
  _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
5d12d71 172
5d12d71 173
/// Insert a given `value` into a sorted array, using the given `compare`
5d12d71 174
/// callback to determine the order.
5d12d71 175
#define array_insert_sorted_with(self, compare, value) \
5d12d71 176
  do { \
5d12d71 177
    unsigned _index, _exists; \
5d12d71 178
    array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
5d12d71 179
    if (!_exists) array_insert(self, _index, value); \
5d12d71 180
  } while (0)
5d12d71 181
5d12d71 182
/// Insert a given `value` into a sorted array, using integer comparisons of
5d12d71 183
/// a given struct field (specified with a leading dot) to determine the order.
5d12d71 184
///
5d12d71 185
/// See also `array_search_sorted_by`.
5d12d71 186
#define array_insert_sorted_by(self, field, value) \
5d12d71 187
  do { \
5d12d71 188
    unsigned _index, _exists; \
5d12d71 189
    array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
5d12d71 190
    if (!_exists) array_insert(self, _index, value); \
5d12d71 191
  } while (0)
5d12d71 192
5d12d71 193
// Private
5d12d71 194
f502d22 195
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
f502d22 196
// are passed to the various `_array__*` functions below to address strict aliasing
f502d22 197
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
f502d22 198
//
f502d22 199
// The `Array` type itself was not altered as a solution in order to avoid breakage
f502d22 200
// with existing consumers (in particular, parsers with external scanners).
5d12d71 201
5d12d71 202
/// This is not what you're looking for, see `array_erase`.
f502d22 203
static inline void _array__erase(void* self_contents, uint32_t *size,
f502d22 204
                                size_t element_size, uint32_t index) {
f502d22 205
  assert(index < *size);
f502d22 206
  char *contents = (char *)self_contents;
5d12d71 207
  memmove(contents + index * element_size, contents + (index + 1) * element_size,
f502d22 208
          (*size - index - 1) * element_size);
f502d22 209
  (*size)--;
5d12d71 210
}
5d12d71 211
5d12d71 212
/// This is not what you're looking for, see `array_reserve`.
f502d22 213
static inline void *_array__reserve(void *contents, uint32_t *capacity,
f502d22 214
                                  size_t element_size, uint32_t new_capacity) {
f502d22 215
  void *new_contents = contents;
f502d22 216
  if (new_capacity > *capacity) {
f502d22 217
    if (contents) {
f502d22 218
      new_contents = ts_realloc(contents, new_capacity * element_size);
5d12d71 219
    } else {
f502d22 220
      new_contents = ts_malloc(new_capacity * element_size);
5d12d71 221
    }
f502d22 222
    *capacity = new_capacity;
5d12d71 223
  }
f502d22 224
  return new_contents;
5d12d71 225
}
5d12d71 226
5d12d71 227
/// This is not what you're looking for, see `array_assign`.
f502d22 228
static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity,
f502d22 229
                                 const void *other_contents, uint32_t other_size, size_t element_size) {
f502d22 230
  void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
f502d22 231
  *self_size = other_size;
f502d22 232
  memcpy(new_contents, other_contents, *self_size * element_size);
f502d22 233
  return new_contents;
5d12d71 234
}
5d12d71 235
5d12d71 236
/// This is not what you're looking for, see `array_swap`.
f502d22 237
static inline void _array__swap(uint32_t *self_size, uint32_t *self_capacity,
f502d22 238
                               uint32_t *other_size, uint32_t *other_capacity) {
f502d22 239
  uint32_t tmp_size = *self_size;
f502d22 240
  uint32_t tmp_capacity = *self_capacity;
f502d22 241
  *self_size = *other_size;
f502d22 242
  *self_capacity = *other_capacity;
f502d22 243
  *other_size = tmp_size;
f502d22 244
  *other_capacity = tmp_capacity;
5d12d71 245
}
5d12d71 246
5d12d71 247
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
f502d22 248
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity,
f502d22 249
                               uint32_t count, size_t element_size) {
f502d22 250
  void *new_contents = contents;
f502d22 251
  uint32_t new_size = size + count;
f502d22 252
  if (new_size > *capacity) {
f502d22 253
    uint32_t new_capacity = *capacity * 2;
5d12d71 254
    if (new_capacity < 8) new_capacity = 8;
5d12d71 255
    if (new_capacity < new_size) new_capacity = new_size;
f502d22 256
    new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
5d12d71 257
  }
f502d22 258
  return new_contents;
5d12d71 259
}
5d12d71 260
5d12d71 261
/// This is not what you're looking for, see `array_splice`.
f502d22 262
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
f502d22 263
                                 size_t element_size,
5d12d71 264
                                 uint32_t index, uint32_t old_count,
5d12d71 265
                                 uint32_t new_count, const void *elements) {
f502d22 266
  uint32_t new_size = *size + new_count - old_count;
5d12d71 267
  uint32_t old_end = index + old_count;
5d12d71 268
  uint32_t new_end = index + new_count;
f502d22 269
  assert(old_end <= *size);
5d12d71 270
f502d22 271
  void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
5d12d71 272
f502d22 273
  char *contents = (char *)new_contents;
f502d22 274
  if (*size > old_end) {
5d12d71 275
    memmove(
5d12d71 276
      contents + new_end * element_size,
5d12d71 277
      contents + old_end * element_size,
f502d22 278
      (*size - old_end) * element_size
5d12d71 279
    );
5d12d71 280
  }
5d12d71 281
  if (new_count > 0) {
5d12d71 282
    if (elements) {
5d12d71 283
      memcpy(
5d12d71 284
        (contents + index * element_size),
5d12d71 285
        elements,
5d12d71 286
        new_count * element_size
5d12d71 287
      );
5d12d71 288
    } else {
5d12d71 289
      memset(
5d12d71 290
        (contents + index * element_size),
5d12d71 291
        0,
5d12d71 292
        new_count * element_size
5d12d71 293
      );
5d12d71 294
    }
5d12d71 295
  }
f502d22 296
  *size += new_count - old_count;
f502d22 297
f502d22 298
  return new_contents;
5d12d71 299
}
5d12d71 300
5d12d71 301
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
5d12d71 302
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
5d12d71 303
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
5d12d71 304
  do { \
5d12d71 305
    *(_index) = start; \
5d12d71 306
    *(_exists) = false; \
5d12d71 307
    uint32_t size = (self)->size - *(_index); \
5d12d71 308
    if (size == 0) break; \
5d12d71 309
    int comparison; \
5d12d71 310
    while (size > 1) { \
5d12d71 311
      uint32_t half_size = size / 2; \
5d12d71 312
      uint32_t mid_index = *(_index) + half_size; \
5d12d71 313
      comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
5d12d71 314
      if (comparison <= 0) *(_index) = mid_index; \
5d12d71 315
      size -= half_size; \
5d12d71 316
    } \
5d12d71 317
    comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
5d12d71 318
    if (comparison == 0) *(_exists) = true; \
5d12d71 319
    else if (comparison < 0) *(_index) += 1; \
5d12d71 320
  } while (0)
5d12d71 321
5d12d71 322
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
5d12d71 323
/// parameter by reference in order to work with the generic sorting function above.
5d12d71 324
#define _compare_int(a, b) ((int)*(a) - (int)(b))
5d12d71 325
5d12d71 326
#ifdef _MSC_VER
0d43379 327
#pragma warning(pop)
5d12d71 328
#elif defined(__GNUC__) || defined(__clang__)
5d12d71 329
#pragma GCC diagnostic pop
5d12d71 330
#endif
5d12d71 331
5d12d71 332
#ifdef __cplusplus
5d12d71 333
}
5d12d71 334
#endif
5d12d71 335
5d12d71 336
#endif  // TREE_SITTER_ARRAY_H_