in Frameworks/CoreFoundation/Collections.subproj/CFBag.c [122:211]
static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) {
CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing
flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0);
if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { // all this crap is just for figuring out two flags for GC in the way done historically; it probably simplifies down to three lines, but we let the compiler worry about that
Boolean set_cb = false;
Boolean std_cb = false;
const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL;
void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL;
const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL;
void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL;
if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) {
Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain;
Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release;
Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal;
Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash;
Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription;
Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull);
Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull);
Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull);
Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull);
Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain;
Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release;
Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal;
Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash;
Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription;
Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd);
Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd);
Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd);
Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd);
if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) {
set_cb = true;
if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) {
std_cb = true;
} else {
// just set these to tickle the GC Strong logic below in a way that mimics past practice
key_retain = keyCallBacks ? keyCallBacks->retain : NULL;
key_release = keyCallBacks ? keyCallBacks->release : NULL;
if (useValueCB) {
value_retain = valueCallBacks ? valueCallBacks->retain : NULL;
value_release = valueCallBacks ? valueCallBacks->release : NULL;
} else {
value_retain = key_retain;
value_release = key_release;
}
}
}
}
if (!set_cb) {
key_retain = keyCallBacks ? keyCallBacks->retain : NULL;
key_release = keyCallBacks ? keyCallBacks->release : NULL;
if (useValueCB) {
value_retain = valueCallBacks ? valueCallBacks->retain : NULL;
value_release = valueCallBacks ? valueCallBacks->release : NULL;
} else {
value_retain = key_retain;
value_release = key_release;
}
}
if (std_cb || value_retain != NULL || value_release != NULL) {
flags |= kCFBasicHashStrongValues;
}
if (std_cb || key_retain != NULL || key_release != NULL) {
flags |= kCFBasicHashStrongKeys;
}
}
CFBasicHashCallbacks callbacks;
callbacks.retainKey = keyCallBacks ? (uintptr_t (*)(CFAllocatorRef, uintptr_t))keyCallBacks->retain : NULL;
callbacks.releaseKey = keyCallBacks ? (void (*)(CFAllocatorRef, uintptr_t))keyCallBacks->release : NULL;
callbacks.equateKeys = keyCallBacks ? (Boolean (*)(uintptr_t, uintptr_t))keyCallBacks->equal : NULL;
callbacks.hashKey = keyCallBacks ? (CFHashCode (*)(uintptr_t))keyCallBacks->hash : NULL;
callbacks.getIndirectKey = NULL;
callbacks.copyKeyDescription = keyCallBacks ? (CFStringRef (*)(uintptr_t))keyCallBacks->copyDescription : NULL;
callbacks.retainValue = useValueCB ? (valueCallBacks ? (uintptr_t (*)(CFAllocatorRef, uintptr_t))valueCallBacks->retain : NULL) : (callbacks.retainKey);
callbacks.releaseValue = useValueCB ? (valueCallBacks ? (void (*)(CFAllocatorRef, uintptr_t))valueCallBacks->release : NULL) : (callbacks.releaseKey);
callbacks.equateValues = useValueCB ? (valueCallBacks ? (Boolean (*)(uintptr_t, uintptr_t))valueCallBacks->equal : NULL) : (callbacks.equateKeys);
callbacks.copyValueDescription = useValueCB ? (valueCallBacks ? (CFStringRef (*)(uintptr_t))valueCallBacks->copyDescription : NULL) : (callbacks.copyKeyDescription);
CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, &callbacks);
return ht;
}