Cedro
array.h
Go to the documentation of this file.
1 /* -*- coding: utf-8 c-basic-offset: 2 tab-width: 2 indent-tabs-mode: nil -*- */ /* Array template definition. */
3 
13 #define DEFINE_ARRAY_OF(T, PADDING, DESTRUCT_BLOCK) \
14  \
21 typedef struct T##_array { \
22  \
23  size_t len; \
24  \
25  size_t capacity; \
26  \
27  T##_mut_p start; \
28 } mut_##T##_array, * const mut_##T##_array_p, * mut_##T##_array_mut_p; \
29 typedef const struct T##_array \
30 /* */ T##_array, * const T##_array_p, * T##_array_mut_p; \
31  \
32  \
38 typedef struct T##_array_slice { \
39  \
40  T##_mut_p start_p; \
41  \
42  T##_mut_p end_p; \
43 } mut_##T##_array_slice, * const mut_##T##_array_slice_p, \
44  * mut_##T##_array_slice_mut_p; \
45 typedef const struct T##_array_slice \
46 /* */ T##_array_slice, * const T##_array_slice_p, \
47  * T##_array_slice_mut_p; \
48  \
49  \
62 typedef struct T##_array_mut_slice { \
63  \
64  mut_##T##_mut_p start_p; \
65  \
66  mut_##T##_mut_p end_p; \
67 } /* Mutable slice of a mutable array whose items are read-only. \
68  */ mut_##T##_array_mut_slice, \
69  /* Pointer to mutable slice of a mutable array of read-only items. */ \
70  * const mut_##T##_array_mut_slice_p, \
71  /* Mutable pointer to mutable slice of mutable read-only array.*/ \
72  * mut_##T##_array_mut_slice_mut_p; \
73  \
86 typedef struct T##_array_mut_slice \
87 /* Slice of a mutable array whose items are read-only. \
88  */ T##_array_mut_slice, \
89  /* Pointer to mutable slice of a mutable array of read-only items. */ \
90  * const T##_array_mut_slice_p, \
91  /* Mutable pointer to mutable slice of mutable read-only array.*/ \
92  * T##_array_mut_slice_mut_p; \
93  \
94  \
97 static void \
98 init_##T##_array_slice(mut_##T##_array_slice_p _, \
99  T##_array_p array_p, \
100  size_t start, size_t end) \
101 { \
102  _->start_p = array_p->start + start; \
103  if (end) _->end_p = array_p->start + end; \
104  else _->end_p = array_p->start + array_p->len; \
105 } \
106  \
107  \
110 static void \
111 init_##T##_array_mut_slice(mut_##T##_array_mut_slice_p _, \
112  mut_##T##_array_mut_p array_p, \
113  size_t start, size_t end) \
114 { \
115  _->start_p = (mut_##T##_mut_p) array_p->start + start; \
116  if (end) _->end_p = (mut_##T##_mut_p) array_p->start + end; \
117  else _->end_p = (mut_##T##_mut_p) array_p->start + array_p->len; \
118 } \
119  \
120 static void \
121 destruct_##T##_block(mut_##T##_mut_p cursor, T##_p end) \
122 { \
123  DESTRUCT_BLOCK \
124 } \
125  \
126  \
135 static void \
136 init_##T##_array(mut_##T##_array_p _, size_t initial_capacity) \
137 { \
138  _->len = 0; \
139  _->capacity = initial_capacity + PADDING; \
140  _->start = _->capacity? malloc(_->capacity * sizeof(*_->start)): NULL;\
141  /* Used malloc() here instead of calloc() because we need realloc() \
142  later anyway, so better keep the exact same behaviour. */ \
143 } \
144  \
155 static void \
156 init_from_constant_##T##_array(mut_##T##_array_p _, \
157  T* items, size_t len) \
158 { \
159  _->len = len; \
160  _->capacity = 0; \
161  _->start = items; \
162  /* Used malloc() here instead of calloc() because we need realloc() \
163  later anyway, so better keep the exact same behaviour. */ \
164 } \
165  \
167 static mut_##T##_array \
168 new_##T##_array(size_t initial_capacity) \
169 { \
170  mut_##T##_array _; \
171  init_##T##_array(&_, initial_capacity); \
172  return _; \
173 } \
174  \
176 static mut_##T##_array_p \
177 new_##T##_array_p(size_t initial_capacity) \
178 { \
179  mut_##T##_array_p _ = malloc(sizeof(T##_array)); \
180  if (_) init_##T##_array(_, initial_capacity); \
181  return _; \
182 } \
183  \
187 static void \
188 destruct_##T##_array(mut_##T##_array_p _) \
189 { \
190  if (_->capacity is_not 0) { \
191  /* _->capacity == 0 means that _->start is a non-owned pointer. */ \
192  destruct_##T##_block((mut_##T##_p) _->start, _->start + _->len); \
193  free((mut_##T##_mut_p) (_->start)); \
194  *((mut_##T##_mut_p *) &(_->start)) = NULL; \
195  _->capacity = 0; \
196  } \
197  _->len = 0; \
198 } \
199  \
205 static void \
206 free_##T##_array(mut_##T##_array_p _) \
207 { \
208  destruct_##T##_array(_); \
209  free(_); \
210 } \
211  \
223 static mut_##T##_array \
224 move_##T##_array(mut_##T##_array_p _) \
225 { \
226  mut_##T##_array transferred_copy = *_; \
227  _->len = 0; \
228  _->capacity = 0; \
229  *((mut_##T##_mut_p *) &(_->start)) = NULL; \
230  return transferred_copy; \
231 } \
232  \
233  \
235 static void \
236 ensure_capacity_##T##_array(mut_##T##_array_p _, size_t minimum) \
237 { \
238  minimum += PADDING; \
239  if (minimum <= _->capacity) return; \
240  if (_->capacity is 0) { \
241  /* _->capacity == 0 means that _->start is a non-owned pointer. */ \
242  _->capacity = minimum + PADDING; \
243  _->start = malloc(_->capacity * sizeof(*_->start)); \
244  } else { \
245  _->capacity = 2*_->capacity + PADDING; \
246  if (minimum > _->capacity) _->capacity = minimum; \
247  _->start = realloc((void*) _->start, \
248  _->capacity * sizeof(*_->start)); \
249  } \
250 } \
251  \
252  \
254 static void \
255 push_##T##_array(mut_##T##_array_p _, T item) \
256 { \
257  ensure_capacity_##T##_array(_, _->len + 1); \
258  *((mut_##T##_p) _->start + _->len++) = item; \
259 } \
260  \
261  \
269 static void \
270 splice_##T##_array(mut_##T##_array_p _, \
271  size_t position, size_t delete, \
272  mut_##T##_array_p deleted, \
273  T##_array_slice insert) \
274 { \
275  assert(position + delete <= _->len); \
276  if (deleted) { \
277  T##_array_slice slice = { \
278  .start_p = (mut_##T##_p) _->start + position, \
279  .end_p = (mut_##T##_p) _->start + position + delete \
280  }; \
281  splice_##T##_array(deleted, deleted->len, 0, NULL, slice); \
282  } else { \
283  destruct_##T##_block((mut_##T##_p) _->start + position, \
284  _->start + position + delete); \
285  } \
286  \
287  size_t insert_len = 0; \
288  size_t new_len = _->len - delete; \
289  if (insert.start_p is_not insert.end_p) { \
290  assert(_->start > insert.end_p || \
291  _->start + _->len < insert.start_p); \
292  assert(insert.end_p >= insert.start_p); \
293  insert_len = (size_t)(insert.end_p - insert.start_p); \
294  new_len += insert_len; \
295  ensure_capacity_##T##_array(_, new_len); \
296  } \
297  \
298  size_t gap_end = position + insert_len; \
299  memmove((void*) (_->start + gap_end), \
300  _->start + position + delete, \
301  (_->len - delete - position) * sizeof(*_->start)); \
302  _->len = _->len + insert_len - delete; \
303  if (insert_len) { \
304  memcpy((void*) (_->start + position), \
305  insert.start_p, \
306  insert_len * sizeof(*_->start)); \
307  } \
308 } \
309  \
310  \
313 static void \
314 append_##T##_array(mut_##T##_array_p _, T##_array_slice insert) \
315 { \
316  splice_##T##_array(_, _->len, 0, NULL, insert); \
317 } \
318  \
319  \
322 static void \
323 delete_##T##_array(mut_##T##_array_p _, size_t position, size_t delete) \
324 { \
325  assert(position + delete <= _->len); \
326  destruct_##T##_block((mut_##T##_p) _->start + position, \
327  _->start + position + delete); \
328  \
329  memmove((void*) (_->start + position), \
330  _->start + position + delete, \
331  (_->len - delete - position) * sizeof(*_->start)); \
332  _->len -= delete; \
333 } \
334  \
335  \
339 static void \
340 pop_##T##_array(mut_##T##_array_p _, mut_##T##_p item_p) \
341 { \
342  if (not _->len) return; \
343  mut_##T##_p last_p = (mut_##T##_p) _->start + _->len - 1; \
344  if (item_p) memmove((void*) last_p, item_p, sizeof(*_->start)); \
345  else destruct_##T##_block((mut_##T##_p) last_p, last_p + 1); \
346  --_->len; \
347 } \
348  \
349  \
351 static T##_p \
352 get_##T##_array(T##_array_p _, size_t position) \
353 { \
354  assert(position < _->len); \
355  return _->start + position; \
356 } \
357  \
358  \
360 static mut_##T##_p \
361 get_mut_##T##_array(T##_array_p _, size_t position) \
362 { \
363  assert(position < _->len); \
364  return (mut_##T##_p) _->start + position; \
365 } \
366  \
367  \
368 static T##_p \
369 start_of_##T##_array(T##_array_p _) \
370 { \
371  return _->start; \
372 } \
373  \
374  \
375 static T##_p \
376 end_of_##T##_array(T##_array_p _) \
377 { \
378  return _->start + _->len; \
379 } \
380  \
381  \
382 static T##_array_slice \
383 bounds_of_##T##_array(T##_array_p _) \
384 { \
385  return (T##_array_slice){ _->start, _->start + _->len }; \
386 } \
387  \
388  \
389 static mut_##T##_p \
390 start_of_mut_##T##_array(mut_##T##_array_p _) \
391 { \
392  return (mut_##T##_p) _->start; \
393 } \
394  \
395  \
396 static mut_##T##_p \
397 end_of_mut_##T##_array(mut_##T##_array_p _) \
398 { \
399  return (mut_##T##_p) _->start + _->len; \
400 } \
401  \
402  \
403 static mut_##T##_array_slice \
404 bounds_of_mut_##T##_array(mut_##T##_array_p _) \
405 { \
406  return (mut_##T##_array_slice){ _->start, _->start + _->len }; \
407 } \
408  \
409  \
410 static size_t \
411 index_##T##_array(T##_array_p _, T##_p pointer) \
412 { \
413  return (size_t)(pointer - _->start); \
414 } \
415 static const size_t PADDING_##T##_ARRAY = PADDING//; commented out to avoid ;;.