1
/* A fast (Inline) array implementation without objc method overhead.
2
* Copyright (C) 1998,1999 Free Software Foundation, Inc.
4
* Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
7
* This file is part of the GNUstep Base Library.
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Library General Public
11
* License as published by the Free Software Foundation; either
12
* version 2 of the License, or (at your option) any later version.
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Library General Public License for more details.
19
* You should have received a copy of the GNU Library General Public
20
* License along with this library; if not, write to the Free
21
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23
#include <Foundation/NSObject.h>
24
#include <Foundation/NSZone.h>
26
/* To easily un-inline functions for debugging */
31
/* To turn assertions on, define GSI_ARRAY_CHECKS */
32
#ifdef GSI_ARRAY_CHECKS
33
#define GSI_ARRAY_CHECK NSCAssert(array->count <= array->cap && array->old <= array->cap && array->old >= 1, NSInternalInconsistencyException)
35
#define GSI_ARRAY_CHECK
39
This file should be INCLUDED in files wanting to use the GSIArray
40
* functions - these are all declared inline for maximum performance.
42
* The file including this one may predefine some macros to alter
43
* the behaviour (default macros assume the items are NSObjects
44
* that are to be retained in the array) ...
47
* Macro to retain an array item
50
* Macro to release the item.
52
* The next two values can be defined in order to let us optimise
53
* even further when either retain or release operations are not needed.
55
* GSI_ARRAY_NO_RELEASE
56
* Defined if no release operation is needed for an item
58
* Defined if no retain operation is needed for a an item
60
* The value GSI_ARRAY_EXTRA may be defined as the type of an extra
61
* field produced in every array. The name of this field is 'extra'.
63
* The value GSI_ARRAY_TYPE may be defined as an additional type
64
* which must be valid as an array element. Otherwise the types are
65
* controlled by the mechanism in GSUnion.h
69
#ifdef GSI_ARRAY_NO_RETAIN
70
#ifdef GSI_ARRAY_RETAIN
71
#undef GSI_ARRAY_RETAIN
73
#define GSI_ARRAY_RETAIN(A, X)
75
#ifndef GSI_ARRAY_RETAIN
76
#define GSI_ARRAY_RETAIN(A, X) [(X).obj retain]
80
#ifdef GSI_ARRAY_NO_RELEASE
81
#ifdef GSI_ARRAY_RELEASE
82
#undef GSI_ARRAY_RELEASE
84
#define GSI_ARRAY_RELEASE(A, X)
86
#ifndef GSI_ARRAY_RELEASE
87
#define GSI_ARRAY_RELEASE(A, X) [(X).obj release]
92
* If there is no bitmask defined to supply the types that
93
* may be stored in the array, default to permitting all types.
95
#ifndef GSI_ARRAY_TYPES
96
#define GSI_ARRAY_TYPES GSUNION_ALL
100
* Set up the name of the union to store array elements.
105
#define GSUNION GSIArrayItem
108
* Set up the types that will be storable in the union.
109
* See 'GSUnion.h' for details.
114
#define GSUNION_TYPES GSI_ARRAY_TYPES
120
* Override extra type used in array value
122
#ifdef GSI_ARRAY_TYPE
123
#define GSUNION_EXTRA GSI_ARRAY_TYPE
127
* Generate the union typedef
129
#include <GNUstepBase/GSUnion.h>
137
#ifdef GSI_ARRAY_EXTRA
138
GSI_ARRAY_EXTRA extra;
141
typedef struct _GSIArray GSIArray_t;
142
typedef struct _GSIArray *GSIArray;
144
static INLINE unsigned
145
GSIArrayCapacity(GSIArray array)
150
static INLINE unsigned
151
GSIArrayCount(GSIArray array)
157
GSIArrayGrow(GSIArray array)
166
* Statically initialised buffer ... copy into new heap buffer.
168
array->old = array->cap / 2;
173
next = array->cap + array->old;
174
size = next*sizeof(GSIArrayItem);
175
tmp = NSZoneMalloc(array->zone, size);
176
memcpy(tmp, array->ptr, array->count * sizeof(GSIArrayItem));
180
next = array->cap + array->old;
181
size = next*sizeof(GSIArrayItem);
182
tmp = NSZoneRealloc(array->zone, array->ptr, size);
187
[NSException raise: NSMallocException
188
format: @"failed to grow GSIArray"];
191
array->old = array->cap;
196
GSIArrayGrowTo(GSIArray array, unsigned next)
201
if (next < array->count)
203
[NSException raise: NSInvalidArgumentException
204
format: @"attempt to shrink below count"];
206
size = next*sizeof(GSIArrayItem);
207
tmp = NSZoneRealloc(array->zone, array->ptr, size);
211
[NSException raise: NSMallocException
212
format: @"failed to grow GSIArray"];
215
array->old = array->cap;
220
GSIArrayInsertItem(GSIArray array, GSIArrayItem item, unsigned index)
224
GSI_ARRAY_RETAIN(array, item);
226
if (array->count == array->cap)
230
for (i = array->count++; i > index; i--)
232
array->ptr[i] = array->ptr[i-1];
234
array->ptr[i] = item;
239
GSIArrayInsertItemNoRetain(GSIArray array, GSIArrayItem item, unsigned index)
244
if (array->count == array->cap)
248
for (i = array->count++; i > index; i--)
250
array->ptr[i] = array->ptr[i-1];
252
array->ptr[i] = item;
257
GSIArrayAddItem(GSIArray array, GSIArrayItem item)
259
GSI_ARRAY_RETAIN(array, item);
261
if (array->count == array->cap)
265
array->ptr[array->count++] = item;
270
GSIArrayAddItemNoRetain(GSIArray array, GSIArrayItem item)
273
if (array->count == array->cap)
277
array->ptr[array->count++] = item;
282
* The comparator function takes two items as arguments, the first is the
283
* item to be added, the second is the item already in the array.
284
* The function should return NSOrderedAscending if the item to be
285
* added is 'less than' the item in the array, NSOrderedDescending
286
* if it is greater, and NSOrderedSame if it is equal.
288
static INLINE unsigned
289
GSIArrayInsertionPosition(GSIArray array, GSIArrayItem item,
290
NSComparisonResult (*sorter)(GSIArrayItem, GSIArrayItem))
292
unsigned int upper = array->count;
293
unsigned int lower = 0;
297
* Binary search for an item equal to the one to be inserted.
299
for (index = upper/2; upper != lower; index = (upper+lower)/2)
301
NSComparisonResult comparison;
303
comparison = (*sorter)(item, (array->ptr[index]));
304
if (comparison == NSOrderedAscending)
308
else if (comparison == NSOrderedDescending)
318
* Now skip past any equal items so the insertion point is AFTER any
319
* items that are equal to the new one.
321
while (index < array->count
322
&& (*sorter)(item, (array->ptr[index])) != NSOrderedAscending)
326
#ifdef GSI_ARRAY_CHECKS
327
NSCAssert(index <= array->count, NSInternalInconsistencyException);
332
#ifdef GSI_ARRAY_CHECKS
334
GSIArrayCheckSort(GSIArray array,
335
NSComparisonResult (*sorter)(GSIArrayItem, GSIArrayItem))
339
for (i = 1; i < array->count; i++)
341
#ifdef GSI_ARRAY_CHECKS
342
NSCAssert(((*sorter)(array->ptr[i-1], array->ptr[i])
344
!= NSOrderedDecending), NSInvalidArgumentException);
350
GSIArrayInsertSorted(GSIArray array, GSIArrayItem item,
351
NSComparisonResult (*sorter)(GSIArrayItem, GSIArrayItem))
355
index = GSIArrayInsertionPosition(array, item, sorter);
356
GSIArrayInsertItem(array, item, index);
357
#ifdef GSI_ARRAY_CHECKS
358
GSIArrayCheckSort(array, sorter);
363
GSIArrayInsertSortedNoRetain(GSIArray array, GSIArrayItem item,
364
NSComparisonResult (*sorter)(GSIArrayItem, GSIArrayItem))
368
index = GSIArrayInsertionPosition(array, item, sorter);
369
GSIArrayInsertItemNoRetain(array, item, index);
370
#ifdef GSI_ARRAY_CHECKS
371
GSIArrayCheckSort(array, sorter);
376
GSIArrayRemoveItemAtIndex(GSIArray array, unsigned index)
379
#ifdef GSI_ARRAY_CHECKS
380
NSCAssert(index < array->count, NSInvalidArgumentException);
382
tmp = array->ptr[index];
383
while (++index < array->count)
384
array->ptr[index-1] = array->ptr[index];
386
GSI_ARRAY_RELEASE(array, tmp);
390
GSIArrayRemoveLastItem(GSIArray array)
392
#ifdef GSI_ARRAY_CHECKS
393
NSCAssert(array->count, NSInvalidArgumentException);
395
GSI_ARRAY_RELEASE(array, array->ptr[array->count-1]);
400
GSIArrayRemoveItemAtIndexNoRelease(GSIArray array, unsigned index)
403
#ifdef GSI_ARRAY_CHECKS
404
NSCAssert(index < array->count, NSInvalidArgumentException);
406
tmp = array->ptr[index];
407
while (++index < array->count)
408
array->ptr[index-1] = array->ptr[index];
413
GSIArraySetItemAtIndex(GSIArray array, GSIArrayItem item, unsigned index)
416
#ifdef GSI_ARRAY_CHECKS
417
NSCAssert(index < array->count, NSInvalidArgumentException);
419
tmp = array->ptr[index];
420
GSI_ARRAY_RETAIN(array, item);
421
array->ptr[index] = item;
422
GSI_ARRAY_RELEASE(array, tmp);
426
* For direct access ... unsafe if you change the array in any way while
427
* examining the contents of this buffer.
429
static INLINE GSIArrayItem *
430
GSIArrayItems(GSIArray array)
435
static INLINE GSIArrayItem
436
GSIArrayItemAtIndex(GSIArray array, unsigned index)
438
#ifdef GSI_ARRAY_CHECKS
439
NSCAssert(index < array->count, NSInvalidArgumentException);
441
return array->ptr[index];
444
static INLINE GSIArrayItem
445
GSIArrayLastItem(GSIArray array)
447
#ifdef GSI_ARRAY_CHECKS
448
NSCAssert(array->count, NSInvalidArgumentException);
450
return array->ptr[array->count-1];
454
GSIArrayClear(GSIArray array)
459
* Only free memory if it was dynamically initialised (old > 0)
463
NSZoneFree(array->zone, (void*)array->ptr);
471
GSIArrayRemoveItemsFromIndex(GSIArray array, unsigned index)
473
if (index < array->count)
475
#ifndef GSI_ARRAY_NO_RELEASE
476
while (array->count-- > index)
478
GSI_ARRAY_RELEASE(array, array->ptr[array->count]);
481
array->count = index;
486
GSIArrayRemoveAllItems(GSIArray array)
488
#ifndef GSI_ARRAY_NO_RELEASE
489
while (array->count--)
491
GSI_ARRAY_RELEASE(array, array->ptr[array->count]);
498
GSIArrayEmpty(GSIArray array)
500
GSIArrayRemoveAllItems(array);
501
GSIArrayClear(array);
504
static INLINE GSIArray
505
GSIArrayInitWithZoneAndCapacity(GSIArray array, NSZone *zone, size_t capacity)
513
array->cap = capacity;
514
array->old = capacity/2;
515
size = capacity*sizeof(GSIArrayItem);
516
array->ptr = (GSIArrayItem*)NSZoneMalloc(zone, size);
520
static INLINE GSIArray
521
GSIArrayInitWithZoneAndStaticCapacity(GSIArray array, NSZone *zone,
522
size_t capacity, GSIArrayItem *buffer)
526
array->cap = capacity;
532
static INLINE GSIArray
533
GSIArrayCopyWithZone(GSIArray array, NSZone *zone)
537
new = NSZoneMalloc(zone, sizeof(GSIArray_t));
538
GSIArrayInitWithZoneAndCapacity(new, zone, array->count);
540
for (i = 0; i < array->count; i++)
542
GSI_ARRAY_RETAIN(array, array->ptr[i]);
543
new->ptr[new->count++] = array->ptr[i];