/**
 * Array library
 * 
 *
 * ***** BEGIN GPL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2008 Blender Foundation.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): Geoffrey Bantle.
 *
 * ***** END GPL LICENSE BLOCK *****
 */

/*
this library needs to be changed to not use macros quite so heavily,
and to be more of a complete array API.  The way arrays are
exposed to client code as normal C arrays is very useful though, imho.
it does require some use of macros, however.  

anyway, it's used a bit too heavily to simply rewrite as a 
more "correct" solution without macros entirely.  I originally wrote this
to be very easy to use, without the normal pain of most array libraries.
This was especially helpful when it came to the massive refactors necessary for
bmesh, and really helped to speed the process up. - joeedh
  
little array macro library.  example of usage:

int *arr = NULL;
BLI_array_declare(arr);
int i;

for (i=0; i<10; i++) {
	BLI_array_growone(arr);
	arr[i] = something;
}
BLI_array_free(arr);

arrays are buffered, using double-buffering (so on each reallocation,
the array size is doubled).  supposedly this should give good Big Oh
behaviour, though it may not be the best in practice.
*/

#define BLI_array_declare(arr) int _##arr##_count=0; void *_##arr##_tmp; void *_##arr##_static = NULL

/*this will use stack space, up to maxstatic array elements, befoe
  switching to dynamic heap allocation*/
#define BLI_array_staticdeclare(arr, maxstatic) int _##arr##_count=0; void *_##arr##_tmp; char _##arr##_static[maxstatic*sizeof(arr)]

/*this returns the entire size of the array, including any buffering.*/
#define BLI_array_totalsize_dyn(arr) ((arr)==NULL ? 0 : MEM_allocN_len(arr) / sizeof(*arr))
#define BLI_array_totalsize(arr) ((signed int)((arr == _##arr##_static && arr != NULL) ? (sizeof(_##arr##_static) / sizeof(*arr)) : BLI_array_totalsize_dyn(arr)))

/*this returns the logical size of the array, not including buffering.*/
#define BLI_array_count(arr) _##arr##_count

/*grow the array by one.  zeroes the new elements.*/
#define _BLI_array_growone(arr) \
	BLI_array_totalsize(arr) > _##arr##_count ? ++_##arr##_count : \
	((_##arr##_tmp = MEM_callocN(sizeof(*arr)*(_##arr##_count*2+2), #arr " " __FILE__ " ")),\
	(arr && memcpy(_##arr##_tmp, arr, sizeof(*arr) * _##arr##_count)),\
	(arr && (arr != (void*)_##arr##_static ? (MEM_freeN(arr), arr) : arr)),\
	(arr = _##arr##_tmp),\
	_##arr##_count++)

/*returns length of array*/
#define BLI_array_growone(arr) (arr==NULL && _##arr##_static != NULL  ?  ((arr=(void*)_##arr##_static), ++_##arr##_count) : _BLI_array_growone(arr))

	/*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(arr, item) (BLI_array_growone(arr), (arr[_##arr##_count-1] = item), (arr+(_##arr##_count-1)))

/*grow an array by a specified number of items.*/
#define BLI_array_growitems(arr, num) {int _i; for (_i=0; _i<(num); _i++) {BLI_array_growone(arr);}}
#define BLI_array_free(arr) if (arr && arr != _##arr##_static) MEM_freeN(arr)

/*resets the logical size of an array to zero, but doesn't
  free the memory.*/
#define BLI_array_empty(arr) _##arr##_count=0

/*set the count 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_set_length(arr, count) _##arr##_count = (count)
