2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include <CoreFoundation/CFBag.h>
31 #include "CFInternal.h"
33 const CFBagCallBacks kCFTypeBagCallBacks
= {0, __CFTypeCollectionRetain
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
34 const CFBagCallBacks kCFCopyStringBagCallBacks
= {0, (void *)CFStringCreateCopy
, __CFTypeCollectionRelease
, CFCopyDescription
, CFEqual
, CFHash
};
35 static const CFBagCallBacks __kCFNullBagCallBacks
= {0, NULL
, NULL
, NULL
, NULL
, NULL
};
38 static const uint32_t __CFBagCapacities
[42] = {
39 4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571, 5778, 9349,
40 15127, 24476, 39603, 64079, 103682, 167761, 271443, 439204, 710647, 1149851, 1860498,
41 3010349, 4870847, 7881196, 12752043, 20633239, 33385282, 54018521, 87403803, 141422324,
42 228826127, 370248451, 599074578, 969323029, 1568397607, 2537720636U
45 static const uint32_t __CFBagBuckets
[42] = { // primes
46 5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779, 9349, 15121,
47 24473, 39607, 64081, 103681, 167759, 271429, 439199, 710641, 1149857, 1860503, 3010349,
48 4870843, 7881193, 12752029, 20633237, 33385273, 54018521, 87403763, 141422317, 228826121,
49 370248451, 599074561, 969323023, 1568397599, 2537720629U, 4106118251U
52 CF_INLINE CFIndex
__CFBagRoundUpCapacity(CFIndex capacity
) {
54 for (idx
= 0; idx
< 42 && __CFBagCapacities
[idx
] < (uint32_t)capacity
; idx
++);
56 return __CFBagCapacities
[idx
];
59 CF_INLINE CFIndex
__CFBagNumBucketsForCapacity(CFIndex capacity
) {
61 for (idx
= 0; idx
< 42 && __CFBagCapacities
[idx
] < (uint32_t)capacity
; idx
++);
63 return __CFBagBuckets
[idx
];
67 __kCFBagImmutable
= 0, /* unchangable and fixed capacity */
68 __kCFBagMutable
= 1, /* changeable and variable capacity */
69 __kCFBagFixedMutable
= 3 /* changeable and fixed capacity */
73 __kCFBagHasNullCallBacks
= 0,
74 __kCFBagHasCFTypeCallBacks
= 1,
75 __kCFBagHasCustomCallBacks
= 3 /* callbacks are at end of header */
78 struct __CFBagBucket
{
85 CFIndex _count
; /* number of values */
86 CFIndex _capacity
; /* maximum number of values */
87 CFIndex _bucketsUsed
; /* number of slots used */
88 CFIndex _bucketsNum
; /* number of slots */
89 const void *_emptyMarker
;
90 const void *_deletedMarker
;
91 void *_context
; /* private */
92 struct __CFBagBucket
*_buckets
; /* can be NULL if not allocated yet */
95 CF_INLINE
bool __CFBagBucketIsEmpty(CFBagRef bag
, const struct __CFBagBucket
*bucket
) {
96 return (bag
->_emptyMarker
== bucket
->_key
);
99 CF_INLINE
bool __CFBagBucketIsDeleted(CFBagRef bag
, const struct __CFBagBucket
*bucket
) {
100 return (bag
->_deletedMarker
== bucket
->_key
);
103 CF_INLINE
bool __CFBagBucketIsOccupied(CFBagRef bag
, const struct __CFBagBucket
*bucket
) {
104 return (bag
->_emptyMarker
!= bucket
->_key
&& bag
->_deletedMarker
!= bucket
->_key
);
107 /* Bits 1-0 of the base reserved bits are used for mutability variety */
108 /* Bits 3-2 of the base reserved bits are used for callback indicator bits */
110 CF_INLINE CFIndex
__CFBagGetType(CFBagRef bag
) {
111 return __CFBitfieldGetValue(((const CFRuntimeBase
*)bag
)->_info
, 1, 0);
114 CF_INLINE CFIndex
__CFBagGetSizeOfType(CFIndex t
) {
115 CFIndex size
= sizeof(struct __CFBag
);
116 if (__CFBitfieldGetValue(t
, 3, 2) == __kCFBagHasCustomCallBacks
) {
117 size
+= sizeof(CFBagCallBacks
);
122 CF_INLINE
const CFBagCallBacks
*__CFBagGetCallBacks(CFBagRef bag
) {
123 CFBagCallBacks
*result
= NULL
;
124 switch (__CFBitfieldGetValue(((const CFRuntimeBase
*)bag
)->_info
, 3, 2)) {
125 case __kCFBagHasNullCallBacks
:
126 return &__kCFNullBagCallBacks
;
127 case __kCFBagHasCFTypeCallBacks
:
128 return &kCFTypeBagCallBacks
;
129 case __kCFBagHasCustomCallBacks
:
132 result
= (CFBagCallBacks
*)((uint8_t *)bag
+ sizeof(struct __CFBag
));
136 CF_INLINE
bool __CFBagCallBacksMatchNull(const CFBagCallBacks
*c
) {
138 (c
->retain
== __kCFNullBagCallBacks
.retain
&&
139 c
->release
== __kCFNullBagCallBacks
.release
&&
140 c
->copyDescription
== __kCFNullBagCallBacks
.copyDescription
&&
141 c
->equal
== __kCFNullBagCallBacks
.equal
&&
142 c
->hash
== __kCFNullBagCallBacks
.hash
));
145 CF_INLINE
bool __CFBagCallBacksMatchCFType(const CFBagCallBacks
*c
) {
146 return (&kCFTypeBagCallBacks
== c
||
147 (c
->retain
== kCFTypeBagCallBacks
.retain
&&
148 c
->release
== kCFTypeBagCallBacks
.release
&&
149 c
->copyDescription
== kCFTypeBagCallBacks
.copyDescription
&&
150 c
->equal
== kCFTypeBagCallBacks
.equal
&&
151 c
->hash
== kCFTypeBagCallBacks
.hash
));
155 static void __CFBagFindBuckets1(CFBagRef bag
, const void *key
, struct __CFBagBucket
**match
) {
156 const CFBagCallBacks
*cb
= __CFBagGetCallBacks(bag
);
157 struct __CFBagBucket
*buckets
= bag
->_buckets
;
158 CFHashCode keyHash
= cb
->hash
? (CFHashCode
)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb
->hash
), key
, bag
->_context
) : (CFHashCode
)key
;
159 UInt32 start
= keyHash
% bag
->_bucketsNum
;
160 UInt32 probe
= start
;
161 UInt32 probeskip
= 1;
164 struct __CFBagBucket
*currentBucket
= buckets
+ probe
;
165 if (__CFBagBucketIsEmpty(bag
, currentBucket
)) {
167 } else if (__CFBagBucketIsDeleted(bag
, currentBucket
)) {
169 } else if (currentBucket
->_key
== key
|| (cb
->equal
&& INVOKE_CALLBACK3((Boolean (*)(void *, void *, void *))cb
->equal
, currentBucket
->_key
, key
, bag
->_context
))) {
170 *match
= currentBucket
;
173 probe
= (probe
+ probeskip
) % bag
->_bucketsNum
;
174 if (start
== probe
) return;
178 static void __CFBagFindBuckets2(CFBagRef bag
, const void *key
, struct __CFBagBucket
**match
, struct __CFBagBucket
**nomatch
) {
179 const CFBagCallBacks
*cb
= __CFBagGetCallBacks(bag
);
180 struct __CFBagBucket
*buckets
= bag
->_buckets
;
181 CFHashCode keyHash
= cb
->hash
? (CFHashCode
)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb
->hash
), key
, bag
->_context
) : (CFHashCode
)key
;
182 UInt32 start
= keyHash
% bag
->_bucketsNum
;
183 UInt32 probe
= start
;
184 UInt32 probeskip
= 1;
188 struct __CFBagBucket
*currentBucket
= buckets
+ probe
;
189 if (__CFBagBucketIsEmpty(bag
, currentBucket
)) {
190 if (!*nomatch
) *nomatch
= currentBucket
;
192 } else if (__CFBagBucketIsDeleted(bag
, currentBucket
)) {
193 if (!*nomatch
) *nomatch
= currentBucket
;
194 } else if (!*match
&& (currentBucket
->_key
== key
|| (cb
->equal
&& INVOKE_CALLBACK3((Boolean (*)(void *, void *, void *))cb
->equal
, currentBucket
->_key
, key
, bag
->_context
)))) {
195 *match
= currentBucket
;
196 if (*nomatch
) return;
198 probe
= (probe
+ probeskip
) % bag
->_bucketsNum
;
199 if (start
== probe
) return;
203 static void __CFBagFindNewEmptyMarker(CFBagRef bag
) {
204 struct __CFBagBucket
*buckets
;
205 const void *newEmpty
;
207 CFIndex idx
, nbuckets
;
208 buckets
= bag
->_buckets
;
209 nbuckets
= bag
->_bucketsNum
;
210 newEmpty
= bag
->_emptyMarker
;
212 (intptr_t)newEmpty
-= 2;
214 for (idx
= 0; idx
< nbuckets
; idx
++) {
215 if (newEmpty
== buckets
[idx
]._key
) {
221 for (idx
= 0; idx
< nbuckets
; idx
++) {
222 if (bag
->_emptyMarker
== buckets
[idx
]._key
) {
223 buckets
[idx
]._key
= newEmpty
;
226 ((struct __CFBag
*)bag
)->_emptyMarker
= newEmpty
;
229 static void __CFBagFindNewDeletedMarker(CFBagRef bag
) {
230 struct __CFBagBucket
*buckets
;
231 const void *newDeleted
;
233 CFIndex idx
, nbuckets
;
234 buckets
= bag
->_buckets
;
235 nbuckets
= bag
->_bucketsNum
;
236 newDeleted
= bag
->_deletedMarker
;
238 (intptr_t)newDeleted
+= 2;
240 for (idx
= 0; idx
< nbuckets
; idx
++) {
241 if (newDeleted
== buckets
[idx
]._key
) {
247 for (idx
= 0; idx
< nbuckets
; idx
++) {
248 if (bag
->_deletedMarker
== buckets
[idx
]._key
) {
249 buckets
[idx
]._key
= newDeleted
;
252 ((struct __CFBag
*)bag
)->_deletedMarker
= newDeleted
;
255 static bool __CFBagEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
256 CFBagRef bag1
= (CFBagRef
)cf1
;
257 CFBagRef bag2
= (CFBagRef
)cf2
;
258 const CFBagCallBacks
*cb1
, *cb2
;
259 const struct __CFBagBucket
*buckets
;
260 CFIndex idx
, nbuckets
;
261 if (bag1
== bag2
) return true;
262 if (bag1
->_count
!= bag2
->_count
) return false;
263 cb1
= __CFBagGetCallBacks(bag1
);
264 cb2
= __CFBagGetCallBacks(bag2
);
265 if (cb1
->equal
!= cb2
->equal
) return false;
266 if (0 == bag1
->_count
) return true; /* after function comparison! */
267 buckets
= bag1
->_buckets
;
268 nbuckets
= bag1
->_bucketsNum
;
269 for (idx
= 0; idx
< nbuckets
; idx
++) {
270 if (__CFBagBucketIsOccupied(bag1
, &buckets
[idx
])) {
271 if (buckets
[idx
]._count
!= CFBagGetCountOfValue(bag2
, buckets
[idx
]._key
)) {
279 static CFHashCode
__CFBagHash(CFTypeRef cf
) {
280 CFBagRef bag
= (CFBagRef
)cf
;
284 static CFStringRef
__CFBagCopyDescription(CFTypeRef cf
) {
285 CFBagRef bag
= (CFBagRef
)cf
;
286 const CFBagCallBacks
*cb
;
287 const struct __CFBagBucket
*buckets
;
288 CFIndex idx
, nbuckets
;
289 CFMutableStringRef result
;
290 cb
= __CFBagGetCallBacks(bag
);
291 buckets
= bag
->_buckets
;
292 nbuckets
= bag
->_bucketsNum
;
293 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
294 CFStringAppendFormat(result
, NULL
, CFSTR("<CFBag %p [%p]>{count = %u, capacity = %u, values = (\n"), bag
, CFGetAllocator(bag
), bag
->_count
, bag
->_capacity
);
295 for (idx
= 0; idx
< nbuckets
; idx
++) {
296 if (__CFBagBucketIsOccupied(bag
, &buckets
[idx
])) {
297 CFStringRef desc
= NULL
;
298 if (NULL
!= cb
->copyDescription
) {
299 desc
= (CFStringRef
)INVOKE_CALLBACK2(((CFStringRef (*)(const void *, void *))cb
->copyDescription
), buckets
[idx
]._key
, bag
->_context
);
302 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : %@ (%d)\n"), idx
, desc
, buckets
[idx
]._count
);
305 CFStringAppendFormat(result
, NULL
, CFSTR("\t%u : <%p> (%d)\n"), idx
, buckets
[idx
]._key
, buckets
[idx
]._count
);
309 CFStringAppend(result
, CFSTR(")}"));
313 static void __CFBagDeallocate(CFTypeRef cf
) {
314 CFMutableBagRef bag
= (CFMutableBagRef
)cf
;
315 CFAllocatorRef allocator
= CFGetAllocator(bag
);
316 if (__CFBagGetType(bag
) == __kCFBagImmutable
) {
317 __CFBitfieldSetValue(((CFRuntimeBase
*)bag
)->_info
, 1, 0, __kCFBagFixedMutable
);
319 CFBagRemoveAllValues(bag
);
320 if (__CFBagGetType(bag
) == __kCFBagMutable
&& bag
->_buckets
) {
321 CFAllocatorDeallocate(allocator
, bag
->_buckets
);
325 static CFTypeID __kCFBagTypeID
= _kCFRuntimeNotATypeID
;
327 static const CFRuntimeClass __CFBagClass
= {
333 (void *)__CFBagEqual
,
336 __CFBagCopyDescription
339 __private_extern__
void __CFBagInitialize(void) {
340 __kCFBagTypeID
= _CFRuntimeRegisterClass(&__CFBagClass
);
343 CFTypeID
CFBagGetTypeID(void) {
344 return __kCFBagTypeID
;
347 static CFBagRef
__CFBagInit(CFAllocatorRef allocator
, UInt32 flags
, CFIndex capacity
, const CFBagCallBacks
*callBacks
) {
348 struct __CFBag
*memory
;
351 __CFBitfieldSetValue(flags
, 31, 2, 0);
352 if (__CFBagCallBacksMatchNull(callBacks
)) {
353 __CFBitfieldSetValue(flags
, 3, 2, __kCFBagHasNullCallBacks
);
354 } else if (__CFBagCallBacksMatchCFType(callBacks
)) {
355 __CFBitfieldSetValue(flags
, 3, 2, __kCFBagHasCFTypeCallBacks
);
357 __CFBitfieldSetValue(flags
, 3, 2, __kCFBagHasCustomCallBacks
);
359 size
= __CFBagGetSizeOfType(flags
) - sizeof(CFRuntimeBase
);
360 switch (__CFBitfieldGetValue(flags
, 1, 0)) {
361 case __kCFBagImmutable
:
362 case __kCFBagFixedMutable
:
363 size
+= __CFBagNumBucketsForCapacity(capacity
) * sizeof(struct __CFBagBucket
);
365 case __kCFBagMutable
:
368 memory
= (struct __CFBag
*)_CFRuntimeCreateInstance(allocator
, __kCFBagTypeID
, size
, NULL
);
369 if (NULL
== memory
) {
372 __CFBitfieldSetValue(memory
->_base
._info
, 6, 0, flags
);
374 memory
->_bucketsUsed
= 0;
375 memory
->_emptyMarker
= (const void *)0xa1b1c1d3;
376 memory
->_deletedMarker
= (const void *)0xa1b1c1d5;
377 memory
->_context
= NULL
;
378 switch (__CFBitfieldGetValue(flags
, 1, 0)) {
379 case __kCFBagImmutable
:
380 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
, "CFBag (immutable)");
381 memory
->_capacity
= capacity
; /* Don't round up capacity */
382 memory
->_bucketsNum
= __CFBagNumBucketsForCapacity(memory
->_capacity
);
383 memory
->_buckets
= (struct __CFBagBucket
*)((uint8_t *)memory
+ __CFBagGetSizeOfType(flags
));
384 for (idx
= memory
->_bucketsNum
; idx
--;) {
385 memory
->_buckets
[idx
]._key
= memory
->_emptyMarker
;
388 case __kCFBagFixedMutable
:
389 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
, "CFBag (mutable-fixed)");
390 memory
->_capacity
= capacity
; /* Don't round up capacity */
391 memory
->_bucketsNum
= __CFBagNumBucketsForCapacity(memory
->_capacity
);
392 memory
->_buckets
= (struct __CFBagBucket
*)((uint8_t *)memory
+ __CFBagGetSizeOfType(flags
));
393 for (idx
= memory
->_bucketsNum
; idx
--;) {
394 memory
->_buckets
[idx
]._key
= memory
->_emptyMarker
;
397 case __kCFBagMutable
:
398 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
, "CFBag (mutable-variable)");
399 memory
->_capacity
= __CFBagRoundUpCapacity(1);
400 memory
->_bucketsNum
= 0;
401 memory
->_buckets
= NULL
;
404 if (__kCFBagHasCustomCallBacks
== __CFBitfieldGetValue(flags
, 3, 2)) {
405 const CFBagCallBacks
*cb
= __CFBagGetCallBacks((CFBagRef
)memory
);
406 *(CFBagCallBacks
*)cb
= *callBacks
;
407 FAULT_CALLBACK((void **)&(cb
->retain
));
408 FAULT_CALLBACK((void **)&(cb
->release
));
409 FAULT_CALLBACK((void **)&(cb
->copyDescription
));
410 FAULT_CALLBACK((void **)&(cb
->equal
));
411 FAULT_CALLBACK((void **)&(cb
->hash
));
413 return (CFBagRef
)memory
;
416 CFBagRef
CFBagCreate(CFAllocatorRef allocator
, const void **values
, CFIndex numValues
, const CFBagCallBacks
*callBacks
) {
420 CFAssert2(0 <= numValues
, __kCFLogAssertion
, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__
, numValues
);
421 result
= __CFBagInit(allocator
, __kCFBagImmutable
, numValues
, callBacks
);
422 flags
= __CFBitfieldGetValue(((const CFRuntimeBase
*)result
)->_info
, 1, 0);
423 if (flags
== __kCFBagImmutable
) {
424 __CFBitfieldSetValue(((CFRuntimeBase
*)result
)->_info
, 1, 0, __kCFBagFixedMutable
);
426 for (idx
= 0; idx
< numValues
; idx
++) {
427 CFBagAddValue((CFMutableBagRef
)result
, values
[idx
]);
429 __CFBitfieldSetValue(((CFRuntimeBase
*)result
)->_info
, 1, 0, flags
);
433 CFMutableBagRef
CFBagCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
, const CFBagCallBacks
*callBacks
) {
434 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
435 return (CFMutableBagRef
)__CFBagInit(allocator
, (0 == capacity
) ? __kCFBagMutable
: __kCFBagFixedMutable
, capacity
, callBacks
);
438 CFBagRef
CFBagCreateCopy(CFAllocatorRef allocator
, CFBagRef bag
) {
440 const CFBagCallBacks
*cb
;
441 CFIndex numValues
= CFBagGetCount(bag
);
442 const void **list
, *buffer
[256];
443 list
= (numValues
<= 256) ? buffer
: CFAllocatorAllocate(allocator
, numValues
* sizeof(void *), 0);
444 if (list
!= buffer
&& __CFOASafe
) __CFSetLastAllocationEventName(list
, "CFBag (temp)");
445 CFBagGetValues(bag
, list
);
446 cb
= CF_IS_OBJC(__kCFBagTypeID
, bag
) ? &kCFTypeBagCallBacks
: __CFBagGetCallBacks(bag
);
447 result
= CFBagCreate(allocator
, list
, numValues
, cb
);
448 if (list
!= buffer
) CFAllocatorDeallocate(allocator
, list
);
452 CFMutableBagRef
CFBagCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFBagRef bag
) {
453 CFMutableBagRef result
;
454 const CFBagCallBacks
*cb
;
455 CFIndex idx
, numValues
= CFBagGetCount(bag
);
456 const void **list
, *buffer
[256];
457 CFAssert3(0 == capacity
|| numValues
<= capacity
, __kCFLogAssertion
, "%s(): for fixed-mutable bags, capacity (%d) must be greater than or equal to initial number of values (%d)", __PRETTY_FUNCTION__
, capacity
, numValues
);
458 list
= (numValues
<= 256) ? buffer
: CFAllocatorAllocate(allocator
, numValues
* sizeof(void *), 0);
459 if (list
!= buffer
&& __CFOASafe
) __CFSetLastAllocationEventName(list
, "CFBag (temp)");
460 CFBagGetValues(bag
, list
);
461 cb
= CF_IS_OBJC(__kCFBagTypeID
, bag
) ? &kCFTypeBagCallBacks
: __CFBagGetCallBacks(bag
);
462 result
= CFBagCreateMutable(allocator
, capacity
, cb
);
463 if (0 == capacity
) _CFBagSetCapacity(result
, numValues
);
464 for (idx
= 0; idx
< numValues
; idx
++) {
465 CFBagAddValue(result
, list
[idx
]);
467 if (list
!= buffer
) CFAllocatorDeallocate(allocator
, list
);
471 void _CFBagSetContext(CFBagRef bag
, void *context
) {
472 ((struct __CFBag
*)bag
)->_context
= context
;
475 CFIndex
CFBagGetCount(CFBagRef bag
) {
476 __CFGenericValidateType(bag
, __kCFBagTypeID
);
480 CFIndex
CFBagGetCountOfValue(CFBagRef bag
, const void *value
) {
481 struct __CFBagBucket
*match
;
482 __CFGenericValidateType(bag
, __kCFBagTypeID
);
483 if (0 == bag
->_count
) return 0;
484 __CFBagFindBuckets1(bag
, value
, &match
);
485 return (match
? match
->_count
: 0);
488 Boolean
CFBagContainsValue(CFBagRef bag
, const void *value
) {
489 struct __CFBagBucket
*match
;
490 __CFGenericValidateType(bag
, __kCFBagTypeID
);
491 if (0 == bag
->_count
) return false;
492 __CFBagFindBuckets1(bag
, value
, &match
);
493 return (match
? true : false);
496 const void *CFBagGetValue(CFBagRef bag
, const void *value
) {
497 struct __CFBagBucket
*match
;
498 __CFGenericValidateType(bag
, __kCFBagTypeID
);
499 if (0 == bag
->_count
) return NULL
;
500 __CFBagFindBuckets1(bag
, value
, &match
);
501 return (match
? match
->_key
: NULL
);
504 Boolean
CFBagGetValueIfPresent(CFBagRef bag
, const void *candidate
, const void **value
) {
505 struct __CFBagBucket
*match
;
506 __CFGenericValidateType(bag
, __kCFBagTypeID
);
507 if (0 == bag
->_count
) return false;
508 __CFBagFindBuckets1(bag
, candidate
, &match
);
509 return (match
? ((value
? *value
= match
->_key
: NULL
), true) : false);
512 void CFBagGetValues(CFBagRef bag
, const void **values
) {
513 struct __CFBagBucket
*buckets
;
514 CFIndex idx
, cnt
, nbuckets
;
515 __CFGenericValidateType(bag
, __kCFBagTypeID
);
516 buckets
= bag
->_buckets
;
517 nbuckets
= bag
->_bucketsNum
;
518 for (idx
= 0; idx
< nbuckets
; idx
++) {
519 if (__CFBagBucketIsOccupied(bag
, &buckets
[idx
])) {
520 for (cnt
= buckets
[idx
]._count
; cnt
--;) {
521 if (values
) *values
++ = buckets
[idx
]._key
;
527 void CFBagApplyFunction(CFBagRef bag
, CFBagApplierFunction applier
, void *context
) {
528 struct __CFBagBucket
*buckets
;
529 CFIndex idx
, cnt
, nbuckets
;
530 FAULT_CALLBACK((void **)&(applier
));
531 __CFGenericValidateType(bag
, __kCFBagTypeID
);
532 buckets
= bag
->_buckets
;
533 nbuckets
= bag
->_bucketsNum
;
534 for (idx
= 0; idx
< nbuckets
; idx
++) {
535 if (__CFBagBucketIsOccupied(bag
, &buckets
[idx
])) {
536 for (cnt
= buckets
[idx
]._count
; cnt
--;) {
537 INVOKE_CALLBACK2(applier
, buckets
[idx
]._key
, context
);
543 static void __CFBagGrow(CFMutableBagRef bag
, CFIndex numNewValues
) {
544 struct __CFBagBucket
*oldbuckets
= bag
->_buckets
;
545 CFIndex idx
, oldnbuckets
= bag
->_bucketsNum
;
546 CFIndex oldCount
= bag
->_count
;
547 bag
->_capacity
= __CFBagRoundUpCapacity(oldCount
+ numNewValues
);
548 bag
->_bucketsNum
= __CFBagNumBucketsForCapacity(bag
->_capacity
);
549 bag
->_buckets
= CFAllocatorAllocate(CFGetAllocator(bag
), bag
->_bucketsNum
* sizeof(struct __CFBagBucket
), 0);
550 if (__CFOASafe
) __CFSetLastAllocationEventName(bag
->_buckets
, "CFBag (store)");
551 if (NULL
== bag
->_buckets
) HALT
;
552 for (idx
= bag
->_bucketsNum
; idx
--;) {
553 bag
->_buckets
[idx
]._key
= bag
->_emptyMarker
;
555 if (NULL
== oldbuckets
) return;
556 for (idx
= 0; idx
< oldnbuckets
; idx
++) {
557 if (__CFBagBucketIsOccupied(bag
, &oldbuckets
[idx
])) {
558 struct __CFBagBucket
*match
, *nomatch
;
559 __CFBagFindBuckets2(bag
, oldbuckets
[idx
]._key
, &match
, &nomatch
);
560 CFAssert3(!match
, __kCFLogAssertion
, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__
, oldbuckets
[idx
]._key
, match
->_key
);
561 nomatch
->_key
= oldbuckets
[idx
]._key
;
562 nomatch
->_count
= oldbuckets
[idx
]._count
;
565 CFAssert1(bag
->_count
== oldCount
, __kCFLogAssertion
, "%s(): bag count differs after rehashing; error", __PRETTY_FUNCTION__
);
566 CFAllocatorDeallocate(CFGetAllocator(bag
), oldbuckets
);
569 // This function is for Foundation's benefit; no one else should use it.
570 void _CFBagSetCapacity(CFMutableBagRef bag
, CFIndex cap
) {
571 if (CF_IS_OBJC(__kCFBagTypeID
, bag
)) return;
573 __CFGenericValidateType(bag
, __kCFBagTypeID
);
574 CFAssert1(__CFBagGetType(bag
) != __kCFBagImmutable
&& __CFBagGetType(bag
) != __kCFBagFixedMutable
, __kCFLogAssertion
, "%s(): bag is immutable or fixed-mutable", __PRETTY_FUNCTION__
);
575 CFAssert3(bag
->_count
<= cap
, __kCFLogAssertion
, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__
, cap
, bag
->_count
);
577 __CFBagGrow(bag
, cap
- bag
->_count
);
580 void CFBagAddValue(CFMutableBagRef bag
, const void *value
) {
581 struct __CFBagBucket
*match
, *nomatch
;
582 const CFBagCallBacks
*cb
;
583 const void *newValue
;
584 __CFGenericValidateType(bag
, __kCFBagTypeID
);
585 switch (__CFBagGetType(bag
)) {
586 case __kCFBagMutable
:
587 if (bag
->_bucketsUsed
== bag
->_capacity
|| NULL
== bag
->_buckets
) {
591 case __kCFBagFixedMutable
:
592 CFAssert3(bag
->_count
< bag
->_capacity
, __kCFLogAssertion
, "%s(): capacity exceeded on fixed-capacity bag %p (capacity = %d)", __PRETTY_FUNCTION__
, bag
, bag
->_capacity
);
595 CFAssert2(__CFBagGetType(bag
) != __kCFBagImmutable
, __kCFLogAssertion
, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__
, bag
);
598 __CFBagFindBuckets2(bag
, value
, &match
, &nomatch
);
600 match
->_count
++; bag
->_count
++;
602 cb
= __CFBagGetCallBacks(bag
);
604 newValue
= (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef
, const void *, void *))cb
->retain
), CFGetAllocator(bag
), value
, bag
->_context
);
608 if (bag
->_emptyMarker
== newValue
) {
609 __CFBagFindNewEmptyMarker(bag
);
611 if (bag
->_deletedMarker
== newValue
) {
612 __CFBagFindNewDeletedMarker(bag
);
614 nomatch
->_key
= newValue
;
621 void CFBagReplaceValue(CFMutableBagRef bag
, const void *value
) {
622 struct __CFBagBucket
*match
;
623 const CFBagCallBacks
*cb
;
624 const void *newValue
;
625 __CFGenericValidateType(bag
, __kCFBagTypeID
);
626 switch (__CFBagGetType(bag
)) {
627 case __kCFBagMutable
:
628 case __kCFBagFixedMutable
:
631 CFAssert2(__CFBagGetType(bag
) != __kCFBagImmutable
, __kCFLogAssertion
, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__
, bag
);
634 if (0 == bag
->_count
) return;
635 __CFBagFindBuckets1(bag
, value
, &match
);
637 cb
= __CFBagGetCallBacks(bag
);
639 newValue
= (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef
, const void *, void *))cb
->retain
), CFGetAllocator(bag
), value
, bag
->_context
);
644 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, const void *, void *))cb
->release
), CFGetAllocator(bag
), match
->_key
, bag
->_context
);
645 match
->_key
= bag
->_deletedMarker
;
647 if (bag
->_emptyMarker
== newValue
) {
648 __CFBagFindNewEmptyMarker(bag
);
650 if (bag
->_deletedMarker
== newValue
) {
651 __CFBagFindNewDeletedMarker(bag
);
653 match
->_key
= newValue
;
656 void CFBagSetValue(CFMutableBagRef bag
, const void *value
) {
657 struct __CFBagBucket
*match
, *nomatch
;
658 const CFBagCallBacks
*cb
;
659 const void *newValue
;
660 __CFGenericValidateType(bag
, __kCFBagTypeID
);
661 switch (__CFBagGetType(bag
)) {
662 case __kCFBagMutable
:
663 if (bag
->_bucketsUsed
== bag
->_capacity
|| NULL
== bag
->_buckets
) {
667 case __kCFBagFixedMutable
:
670 CFAssert2(__CFBagGetType(bag
) != __kCFBagImmutable
, __kCFLogAssertion
, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__
, bag
);
673 __CFBagFindBuckets2(bag
, value
, &match
, &nomatch
);
674 cb
= __CFBagGetCallBacks(bag
);
676 newValue
= (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef
, const void *, void *))cb
->retain
), CFGetAllocator(bag
), value
, bag
->_context
);
682 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, const void *, void *))cb
->release
), CFGetAllocator(bag
), match
->_key
, bag
->_context
);
683 match
->_key
= bag
->_deletedMarker
;
685 if (bag
->_emptyMarker
== newValue
) {
686 __CFBagFindNewEmptyMarker(bag
);
688 if (bag
->_deletedMarker
== newValue
) {
689 __CFBagFindNewDeletedMarker(bag
);
691 match
->_key
= newValue
;
693 CFAssert3(__kCFBagFixedMutable
!= __CFBagGetType(bag
) || bag
->_count
< bag
->_capacity
, __kCFLogAssertion
, "%s(): capacity exceeded on fixed-capacity bag %p (capacity = %d)", __PRETTY_FUNCTION__
, bag
, bag
->_capacity
);
694 if (bag
->_emptyMarker
== newValue
) {
695 __CFBagFindNewEmptyMarker(bag
);
697 if (bag
->_deletedMarker
== newValue
) {
698 __CFBagFindNewDeletedMarker(bag
);
700 nomatch
->_key
= newValue
;
707 void CFBagRemoveValue(CFMutableBagRef bag
, const void *value
) {
708 struct __CFBagBucket
*match
;
709 const CFBagCallBacks
*cb
;
710 __CFGenericValidateType(bag
, __kCFBagTypeID
);
711 switch (__CFBagGetType(bag
)) {
712 case __kCFBagMutable
:
713 case __kCFBagFixedMutable
:
716 CFAssert2(__CFBagGetType(bag
) != __kCFBagImmutable
, __kCFLogAssertion
, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__
, bag
);
719 if (0 == bag
->_count
) return;
720 __CFBagFindBuckets1(bag
, value
, &match
);
722 match
->_count
--; bag
->_count
--;
723 if (0 == match
->_count
) {
724 cb
= __CFBagGetCallBacks(bag
);
726 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, const void *, void *))cb
->release
), CFGetAllocator(bag
), match
->_key
, bag
->_context
);
728 match
->_key
= bag
->_deletedMarker
;
733 void CFBagRemoveAllValues(CFMutableBagRef bag
) {
734 struct __CFBagBucket
*buckets
;
735 const CFBagCallBacks
*cb
;
736 CFAllocatorRef allocator
;
737 CFIndex idx
, nbuckets
;
738 __CFGenericValidateType(bag
, __kCFBagTypeID
);
739 switch (__CFBagGetType(bag
)) {
740 case __kCFBagMutable
:
741 case __kCFBagFixedMutable
:
744 CFAssert2(__CFBagGetType(bag
) != __kCFBagImmutable
, __kCFLogAssertion
, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__
, bag
);
747 if (0 == bag
->_count
) return;
748 buckets
= bag
->_buckets
;
749 nbuckets
= bag
->_bucketsNum
;
750 cb
= __CFBagGetCallBacks(bag
);
751 allocator
= CFGetAllocator(bag
);
752 for (idx
= 0; idx
< nbuckets
; idx
++) {
753 if (__CFBagBucketIsOccupied(bag
, &buckets
[idx
])) {
755 INVOKE_CALLBACK3(((void (*)(CFAllocatorRef
, const void *, void *))cb
->release
), allocator
, buckets
[idx
]._key
, bag
->_context
);
757 buckets
[idx
]._key
= bag
->_emptyMarker
;
758 buckets
[idx
]._count
= 0;
761 bag
->_bucketsUsed
= 0;