krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Sources/TreeSitterScanners/lua/tree_sitter/array.h

191ddb506f3a91b93c755ba6e8123a4e8ac4f90d
orgstar/Sources/TreeSitterScanners/lua/tree_sitter/array.h history · blame · raw

330 lines · 13269 bytes

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