186 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
 * Copyright 2008 Blender Foundation. All rights reserved. */
 | 
						|
 | 
						|
#pragma once
 | 
						|
 | 
						|
/** \file
 | 
						|
 * \ingroup bli
 | 
						|
 * \brief A (mainly) macro array library.
 | 
						|
 */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Internal defines
 | 
						|
 * \{ */
 | 
						|
 | 
						|
/** This returns the entire size of the array, including any buffering. */
 | 
						|
#define _bli_array_totalsize_dynamic(arr) \
 | 
						|
  (((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr)))
 | 
						|
 | 
						|
#define _bli_array_totalsize_static(arr) (sizeof(_##arr##_static) / sizeof(*(arr)))
 | 
						|
 | 
						|
#define _bli_array_totalsize(arr) \
 | 
						|
  ((size_t)(((void *)(arr) == (void *)_##arr##_static && (void *)(arr) != NULL) ? \
 | 
						|
                _bli_array_totalsize_static(arr) : \
 | 
						|
                _bli_array_totalsize_dynamic(arr)))
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/**
 | 
						|
 * BLI_array.c
 | 
						|
 *
 | 
						|
 * Doing the reallocation in a macro isn't so simple,
 | 
						|
 * so use a function the macros can use.
 | 
						|
 *
 | 
						|
 * This function is only to be called via macros.
 | 
						|
 *
 | 
						|
 * \note The caller must adjust \a arr_len
 | 
						|
 */
 | 
						|
void _bli_array_grow_func(void **arr_p,
 | 
						|
                          const void *arr_static,
 | 
						|
                          int sizeof_arr_p,
 | 
						|
                          int arr_len,
 | 
						|
                          int num,
 | 
						|
                          const char *alloc_str);
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Public defines
 | 
						|
 * \{ */
 | 
						|
 | 
						|
/** use `sizeof(*(arr))` to ensure the array exists and is an array */
 | 
						|
#define BLI_array_declare(arr) \
 | 
						|
  int _##arr##_len = ((void)(sizeof(*(arr))), 0); \
 | 
						|
  void *_##arr##_static = NULL
 | 
						|
 | 
						|
/**
 | 
						|
 * This will use stack space, up to `maxstatic` array elements,
 | 
						|
 * before switching to dynamic heap allocation.
 | 
						|
 */
 | 
						|
#define BLI_array_staticdeclare(arr, maxstatic) \
 | 
						|
  int _##arr##_len = 0; \
 | 
						|
  char _##arr##_static[maxstatic * sizeof(*(arr))]
 | 
						|
 | 
						|
/** returns the logical size of the array, not including buffering. */
 | 
						|
#define BLI_array_len(arr) ((void)0, _##arr##_len)
 | 
						|
 | 
						|
/**
 | 
						|
 * Grow the array by a fixed number of items.
 | 
						|
 *
 | 
						|
 * Allow for a large 'num' value when the new size is more than double
 | 
						|
 * to allocate the exact sized array.
 | 
						|
 */
 | 
						|
#define BLI_array_reserve(arr, num) \
 | 
						|
  (void)((((void *)(arr) == NULL) && \
 | 
						|
          ((void *)(_##arr##_static) != \
 | 
						|
           NULL) && /* don't add _##arr##_len below because it must be zero */ \
 | 
						|
          (_bli_array_totalsize_static(arr) >= \
 | 
						|
           (size_t)(_##arr##_len + \
 | 
						|
                    (num)))) ? /* we have an empty array and a static var big enough */ \
 | 
						|
             (void)(arr = (void *)_##arr##_static) : /* use existing static array or allocate */ \
 | 
						|
             (LIKELY(_bli_array_totalsize(arr) >= (size_t)(_##arr##_len + (num))) ? \
 | 
						|
                  (void)0 /* do nothing */ : \
 | 
						|
                  _bli_array_grow_func((void **)&(arr), \
 | 
						|
                                       _##arr##_static, \
 | 
						|
                                       sizeof(*(arr)), \
 | 
						|
                                       _##arr##_len, \
 | 
						|
                                       num, \
 | 
						|
                                       "BLI_array." #arr)))
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns length of array.
 | 
						|
 */
 | 
						|
#define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num))
 | 
						|
 | 
						|
#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
 | 
						|
 | 
						|
/**
 | 
						|
 * Appends an item to the array.
 | 
						|
 */
 | 
						|
#define BLI_array_append(arr, item) \
 | 
						|
  ((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item))
 | 
						|
 | 
						|
/**
 | 
						|
 * Appends an item to the array and returns a pointer to the item in the array.
 | 
						|
 * item is not a pointer, but actual data value.
 | 
						|
 */
 | 
						|
#define BLI_array_append_r(arr, item) \
 | 
						|
  ((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1]))
 | 
						|
 | 
						|
/**
 | 
						|
 * Appends (grows) & returns a pointer to the uninitialized memory.
 | 
						|
 */
 | 
						|
#define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
 | 
						|
 | 
						|
#define BLI_array_free(arr) \
 | 
						|
  { \
 | 
						|
    if (arr && (char *)arr != _##arr##_static) { \
 | 
						|
      BLI_array_fake_user(arr); \
 | 
						|
      MEM_freeN((void *)arr); \
 | 
						|
    } \
 | 
						|
  } \
 | 
						|
  ((void)0)
 | 
						|
 | 
						|
#define BLI_array_pop(arr) ((arr && _##arr##_len) ? arr[--_##arr##_len] : NULL)
 | 
						|
 | 
						|
/**
 | 
						|
 * Resets the logical size of an array to zero, but doesn't
 | 
						|
 * free the memory.
 | 
						|
 */
 | 
						|
#define BLI_array_clear(arr) \
 | 
						|
  { \
 | 
						|
    _##arr##_len = 0; \
 | 
						|
  } \
 | 
						|
  ((void)0)
 | 
						|
 | 
						|
/**
 | 
						|
 * Set the length of the array, doesn't actually increase the allocated array size.
 | 
						|
 * Don't use this unless you know what you're doing.
 | 
						|
 */
 | 
						|
#define BLI_array_len_set(arr, len) \
 | 
						|
  { \
 | 
						|
    _##arr##_len = (len); \
 | 
						|
  } \
 | 
						|
  ((void)0)
 | 
						|
 | 
						|
/**
 | 
						|
 * Only to prevent unused warnings.
 | 
						|
 */
 | 
						|
#define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static)
 | 
						|
 | 
						|
/**
 | 
						|
 * Trim excess items from the array (when they exist).
 | 
						|
 */
 | 
						|
#define BLI_array_trim(arr) \
 | 
						|
  { \
 | 
						|
    if (_bli_array_totalsize_dynamic(arr) != _##arr##_len) { \
 | 
						|
      arr = MEM_reallocN(arr, sizeof(*arr) * _##arr##_len); \
 | 
						|
    } \
 | 
						|
  } \
 | 
						|
  ((void)0)
 | 
						|
 | 
						|
/** \} */
 | 
						|
 | 
						|
/* -------------------------------------------------------------------- */
 | 
						|
/** \name Generic Array Utils
 | 
						|
 *
 | 
						|
 * Other useful defines (unrelated to the main array macros).
 | 
						|
 * \{ */
 | 
						|
 | 
						|
/**
 | 
						|
 * Not part of the 'API' but handy functions, same purpose as #BLI_array_staticdeclare()
 | 
						|
 * but use when the max size is known ahead of time.
 | 
						|
 */
 | 
						|
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
 | 
						|
  char _##arr##_static[maxstatic * sizeof(*(arr))]; \
 | 
						|
  const bool _##arr##_is_static = ((void *)_##arr##_static) != \
 | 
						|
                                  (arr = ((realsize) <= maxstatic) ? \
 | 
						|
                                             (void *)_##arr##_static : \
 | 
						|
                                             MEM_mallocN(sizeof(*(arr)) * (realsize), allocstr))
 | 
						|
 | 
						|
#define BLI_array_fixedstack_free(arr) \
 | 
						|
  if (_##arr##_is_static) { \
 | 
						|
    MEM_freeN(arr); \
 | 
						|
  } \
 | 
						|
  ((void)0)
 | 
						|
 | 
						|
/** \} */
 |