2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* OSDictionary.m created by rsulack on Fri 12-Sep-1997 */
29 /* OSDictionary.cpp converted to C++ by gvdl on Fri 1998-10-30 */
30 /* OSDictionary.cpp rewritten by gvdl on Fri 1998-10-30 */
33 #include <libkern/c++/OSDictionary.h>
34 #include <libkern/c++/OSArray.h>
35 #include <libkern/c++/OSSymbol.h>
36 #include <libkern/c++/OSSerialize.h>
37 #include <libkern/c++/OSLib.h>
38 #include <libkern/c++/OSCollectionIterator.h>
40 #define super OSCollection
42 OSDefineMetaClassAndStructors(OSDictionary
, OSCollection
)
43 OSMetaClassDefineReservedUnused(OSDictionary
, 0);
44 OSMetaClassDefineReservedUnused(OSDictionary
, 1);
45 OSMetaClassDefineReservedUnused(OSDictionary
, 2);
46 OSMetaClassDefineReservedUnused(OSDictionary
, 3);
47 OSMetaClassDefineReservedUnused(OSDictionary
, 4);
48 OSMetaClassDefineReservedUnused(OSDictionary
, 5);
49 OSMetaClassDefineReservedUnused(OSDictionary
, 6);
50 OSMetaClassDefineReservedUnused(OSDictionary
, 7);
52 #define EXT_CAST(obj) \
53 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
56 void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
60 OSDictionary::dictEntry::compare(const void *_e1
, const void *_e2
)
62 const OSDictionary::dictEntry
*e1
= (const OSDictionary::dictEntry
*)_e1
;
63 const OSDictionary::dictEntry
*e2
= (const OSDictionary::dictEntry
*)_e2
;
65 if ((uintptr_t)e1
->key
== (uintptr_t)e2
->key
) {
69 return (uintptr_t)e1
->key
> (uintptr_t)e2
->key
? 1 : -1;
73 OSDictionary::sortBySymbol(void)
75 qsort(dictionary
, count
, sizeof(OSDictionary::dictEntry
),
76 &OSDictionary::dictEntry::compare
);
80 OSDictionary::initWithCapacity(unsigned int inCapacity
)
86 if (inCapacity
> (UINT_MAX
/ sizeof(dictEntry
))) {
90 unsigned int size
= inCapacity
* sizeof(dictEntry
);
93 dictionary
= (dictEntry
*) kalloc_container(size
);
98 bzero(dictionary
, size
);
99 OSCONTAINER_ACCUMSIZE(size
);
102 capacity
= inCapacity
;
103 capacityIncrement
= (inCapacity
)? inCapacity
: 16;
109 OSDictionary::initWithObjects(const OSObject
*objects
[],
110 const OSSymbol
*keys
[],
111 unsigned int theCount
,
112 unsigned int theCapacity
)
114 unsigned int newCapacity
= theCount
;
116 if (!objects
|| !keys
) {
121 if (theCount
> theCapacity
) {
125 newCapacity
= theCapacity
;
128 if (!initWithCapacity(newCapacity
)) {
132 for (unsigned int i
= 0; i
< theCount
; i
++) {
133 const OSMetaClassBase
*newObject
= *objects
++;
135 if (!newObject
|| !keys
[i
] || !setObject(keys
[i
], newObject
)) {
144 OSDictionary::initWithObjects(const OSObject
*objects
[],
145 const OSString
*keys
[],
146 unsigned int theCount
,
147 unsigned int theCapacity
)
149 unsigned int newCapacity
= theCount
;
151 if (!objects
|| !keys
) {
156 if (theCount
> theCapacity
) {
160 newCapacity
= theCapacity
;
163 if (!initWithCapacity(newCapacity
)) {
167 for (unsigned int i
= 0; i
< theCount
; i
++) {
168 const OSSymbol
*key
= OSSymbol::withString(*keys
++);
169 const OSMetaClassBase
*newObject
= *objects
++;
175 if (!newObject
|| !setObject(key
, newObject
)) {
187 OSDictionary::initWithDictionary(const OSDictionary
*dict
,
188 unsigned int theCapacity
)
190 unsigned int newCapacity
;
196 newCapacity
= dict
->count
;
199 if (dict
->count
> theCapacity
) {
203 newCapacity
= theCapacity
;
206 if (!initWithCapacity(newCapacity
)) {
211 bcopy(dict
->dictionary
, dictionary
, count
* sizeof(dictEntry
));
212 for (unsigned int i
= 0; i
< count
; i
++) {
213 dictionary
[i
].key
->taggedRetain(OSTypeID(OSCollection
));
214 dictionary
[i
].value
->taggedRetain(OSTypeID(OSCollection
));
217 if ((kSort
& fOptions
) && !(kSort
& dict
->fOptions
)) {
225 OSDictionary::withCapacity(unsigned int capacity
)
227 OSDictionary
*me
= new OSDictionary
;
229 if (me
&& !me
->initWithCapacity(capacity
)) {
238 OSDictionary::withObjects(const OSObject
*objects
[],
239 const OSSymbol
*keys
[],
241 unsigned int capacity
)
243 OSDictionary
*me
= new OSDictionary
;
245 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
254 OSDictionary::withObjects(const OSObject
*objects
[],
255 const OSString
*keys
[],
257 unsigned int capacity
)
259 OSDictionary
*me
= new OSDictionary
;
261 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
270 OSDictionary::withDictionary(const OSDictionary
*dict
,
271 unsigned int capacity
)
273 OSDictionary
*me
= new OSDictionary
;
275 if (me
&& !me
->initWithDictionary(dict
, capacity
)) {
286 (void) super::setOptions(0, kImmutable
);
289 kfree(dictionary
, capacity
* sizeof(dictEntry
));
290 OSCONTAINER_ACCUMSIZE( -(capacity
* sizeof(dictEntry
)));
297 OSDictionary::getCount() const
302 OSDictionary::getCapacity() const
308 OSDictionary::getCapacityIncrement() const
310 return capacityIncrement
;
314 OSDictionary::setCapacityIncrement(unsigned int increment
)
316 capacityIncrement
= (increment
)? increment
: 16;
318 return capacityIncrement
;
322 OSDictionary::ensureCapacity(unsigned int newCapacity
)
325 unsigned int finalCapacity
;
326 vm_size_t oldSize
, newSize
;
328 if (newCapacity
<= capacity
) {
333 finalCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1)
336 // integer overflow check
337 if (finalCapacity
< newCapacity
|| (finalCapacity
> (UINT_MAX
/ sizeof(dictEntry
)))) {
341 newSize
= sizeof(dictEntry
) * finalCapacity
;
343 newDict
= (dictEntry
*) kallocp_container(&newSize
);
345 // use all of the actual allocation size
346 finalCapacity
= newSize
/ sizeof(dictEntry
);
348 oldSize
= sizeof(dictEntry
) * capacity
;
350 bcopy(dictionary
, newDict
, oldSize
);
351 bzero(&newDict
[capacity
], newSize
- oldSize
);
353 OSCONTAINER_ACCUMSIZE(((size_t)newSize
) - ((size_t)oldSize
));
354 kfree(dictionary
, oldSize
);
356 dictionary
= newDict
;
357 capacity
= finalCapacity
;
364 OSDictionary::flushCollection()
368 for (unsigned int i
= 0; i
< count
; i
++) {
369 dictionary
[i
].key
->taggedRelease(OSTypeID(OSCollection
));
370 dictionary
[i
].value
->taggedRelease(OSTypeID(OSCollection
));
377 setObject(const OSSymbol
*aKey
, const OSMetaClassBase
*anObject
, bool onlyAdd
)
382 if (!anObject
|| !aKey
) {
386 // if the key exists, replace the object
388 if (fOptions
& kSort
) {
389 i
= OSSymbol::bsearch(aKey
, &dictionary
[0], count
, sizeof(dictionary
[0]));
390 exists
= (i
< count
) && (aKey
== dictionary
[i
].key
);
392 for (exists
= false, i
= 0; i
< count
; i
++) {
393 if ((exists
= (aKey
== dictionary
[i
].key
))) {
404 const OSMetaClassBase
*oldObject
= dictionary
[i
].value
;
408 anObject
->taggedRetain(OSTypeID(OSCollection
));
409 dictionary
[i
].value
= anObject
;
411 oldObject
->taggedRelease(OSTypeID(OSCollection
));
415 // add new key, possibly extending our capacity
416 if (count
>= capacity
&& count
>= ensureCapacity(count
+ 1)) {
422 bcopy(&dictionary
[i
], &dictionary
[i
+ 1], (count
- i
) * sizeof(dictionary
[0]));
424 aKey
->taggedRetain(OSTypeID(OSCollection
));
425 anObject
->taggedRetain(OSTypeID(OSCollection
));
426 dictionary
[i
].key
= aKey
;
427 dictionary
[i
].value
= anObject
;
435 setObject(const OSSymbol
*aKey
, const OSMetaClassBase
*anObject
)
437 return setObject(aKey
, anObject
, false);
441 OSDictionary::removeObject(const OSSymbol
*aKey
)
450 // if the key exists, remove the object
452 if (fOptions
& kSort
) {
453 i
= OSSymbol::bsearch(aKey
, &dictionary
[0], count
, sizeof(dictionary
[0]));
454 exists
= (i
< count
) && (aKey
== dictionary
[i
].key
);
456 for (exists
= false, i
= 0; i
< count
; i
++) {
457 if ((exists
= (aKey
== dictionary
[i
].key
))) {
464 dictEntry oldEntry
= dictionary
[i
];
469 bcopy(&dictionary
[i
+ 1], &dictionary
[i
], (count
- i
) * sizeof(dictionary
[0]));
471 oldEntry
.key
->taggedRelease(OSTypeID(OSCollection
));
472 oldEntry
.value
->taggedRelease(OSTypeID(OSCollection
));
478 // Returns true on success, false on an error condition.
480 OSDictionary::merge(const OSDictionary
*srcDict
)
482 const OSSymbol
* sym
;
483 OSCollectionIterator
* iter
;
485 if (!OSDynamicCast(OSDictionary
, srcDict
)) {
489 iter
= OSCollectionIterator::withCollection(const_cast<OSDictionary
*>(srcDict
));
494 while ((sym
= (const OSSymbol
*)iter
->getNextObject())) {
495 const OSMetaClassBase
* obj
;
497 obj
= srcDict
->getObject(sym
);
498 if (!setObject(sym
, obj
)) {
509 OSDictionary::getObject(const OSSymbol
*aKey
) const
511 unsigned int i
, l
= 0, r
= count
;
517 // if the key exists, return the object
519 // inline OSSymbol::bsearch in this performance critical codepath
520 // for performance, the compiler can't do that due to the genericity
521 // of OSSymbol::bsearch
523 // If we have less than 4 objects, scanning is faster.
524 if (count
> 4 && (fOptions
& kSort
)) {
527 if (aKey
== dictionary
[i
].key
) {
528 return const_cast<OSObject
*> ((const OSObject
*)dictionary
[i
].value
);
531 if ((uintptr_t)aKey
< (uintptr_t)dictionary
[i
].key
) {
538 for (i
= l
; i
< r
; i
++) {
539 if (aKey
== dictionary
[i
].key
) {
540 return const_cast<OSObject
*> ((const OSObject
*)dictionary
[i
].value
);
549 #define OBJECT_WRAP_1(cmd, k) \
551 const OSSymbol *tmpKey = k; \
552 OSObject *retObj = NULL; \
554 retObj = cmd(tmpKey); \
560 #define OBJECT_WRAP_2(cmd, k, o) \
562 const OSSymbol *tmpKey = k; \
563 bool ret = cmd(tmpKey, o); \
569 #define OBJECT_WRAP_3(cmd, k) \
571 const OSSymbol *tmpKey = k; \
580 OSDictionary::setObject(const OSString
*aKey
, const OSMetaClassBase
*anObject
)
581 OBJECT_WRAP_2(setObject
, OSSymbol::withString(aKey
), anObject
)
583 OSDictionary::setObject(const char *aKey
, const OSMetaClassBase
*anObject
)
584 OBJECT_WRAP_2(setObject
, OSSymbol::withCString(aKey
), anObject
)
586 OSObject
*OSDictionary::getObject(const OSString
* aKey
) const
587 OBJECT_WRAP_1(getObject
, OSSymbol::existingSymbolForString(aKey
))
588 OSObject
*OSDictionary::getObject(const char *aKey
) const
589 OBJECT_WRAP_1(getObject
, OSSymbol::existingSymbolForCString(aKey
))
592 OSDictionary::removeObject(const OSString
*aKey
)
593 OBJECT_WRAP_3(removeObject
, OSSymbol::existingSymbolForString(aKey
))
595 OSDictionary::removeObject(const char *aKey
)
596 OBJECT_WRAP_3(removeObject
, OSSymbol::existingSymbolForCString(aKey
))
599 OSDictionary::isEqualTo(const OSDictionary
*srcDict
, const OSCollection
*keys
) const
601 OSCollectionIterator
* iter
;
602 unsigned int keysCount
;
603 const OSMetaClassBase
* obj1
;
604 const OSMetaClassBase
* obj2
;
608 if (this == srcDict
) {
612 keysCount
= keys
->getCount();
613 if ((count
< keysCount
) || (srcDict
->getCount() < keysCount
)) {
617 iter
= OSCollectionIterator::withCollection(keys
);
623 while ((aKey
= OSDynamicCast(OSString
, iter
->getNextObject()))) {
624 obj1
= getObject(aKey
);
625 obj2
= srcDict
->getObject(aKey
);
626 if (!obj1
|| !obj2
) {
631 if (!obj1
->isEqualTo(obj2
)) {
642 OSDictionary::isEqualTo(const OSDictionary
*srcDict
) const
645 const OSMetaClassBase
* obj
;
647 if (this == srcDict
) {
651 if (count
!= srcDict
->getCount()) {
655 for (i
= 0; i
< count
; i
++) {
656 obj
= srcDict
->getObject(dictionary
[i
].key
);
661 if (!dictionary
[i
].value
->isEqualTo(obj
)) {
670 OSDictionary::isEqualTo(const OSMetaClassBase
*anObject
) const
674 dict
= OSDynamicCast(OSDictionary
, anObject
);
676 return isEqualTo(dict
);
683 OSDictionary::iteratorSize() const
685 return sizeof(unsigned int);
689 OSDictionary::initIterator(void *inIterator
) const
691 unsigned int *iteratorP
= (unsigned int *) inIterator
;
698 OSDictionary::getNextObjectForIterator(void *inIterator
, OSObject
**ret
) const
700 unsigned int *iteratorP
= (unsigned int *) inIterator
;
701 unsigned int index
= (*iteratorP
)++;
704 *ret
= (OSObject
*) dictionary
[index
].key
;
713 OSDictionary::serialize(OSSerialize
*s
) const
715 if (s
->previouslySerialized(this)) {
719 if (!s
->addXMLStartTag(this, "dict")) {
723 for (unsigned i
= 0; i
< count
; i
++) {
724 const OSSymbol
*key
= dictionary
[i
].key
;
726 // due the nature of the XML syntax, this must be a symbol
727 if (!key
->metaCast("OSSymbol")) {
730 if (!s
->addString("<key>")) {
733 const char *c
= key
->getCStringNoCopy();
736 if (!s
->addString("<")) {
739 } else if (*c
== '>') {
740 if (!s
->addString(">")) {
743 } else if (*c
== '&') {
744 if (!s
->addString("&")) {
748 if (!s
->addChar(*c
)) {
754 if (!s
->addXMLEndTag("key")) {
758 if (!dictionary
[i
].value
->serialize(s
)) {
763 return s
->addXMLEndTag("dict");
767 OSDictionary::setOptions(unsigned options
, unsigned mask
, void *)
769 unsigned old
= super::setOptions(options
, mask
);
770 if ((old
^ options
) & mask
) {
771 // Value changed need to recurse over all of the child collections
772 for (unsigned i
= 0; i
< count
; i
++) {
773 OSCollection
*v
= OSDynamicCast(OSCollection
, dictionary
[i
].value
);
775 v
->setOptions(options
, mask
);
780 if (!(old
& kSort
) && (fOptions
& kSort
)) {
788 OSDictionary::copyCollection(OSDictionary
*cycleDict
)
790 bool allocDict
= !cycleDict
;
791 OSCollection
*ret
= 0;
792 OSDictionary
*newDict
= 0;
795 cycleDict
= OSDictionary::withCapacity(16);
803 ret
= super::copyCollection(cycleDict
);
808 newDict
= OSDictionary::withDictionary(this);
813 // Insert object into cycle Dictionary
814 cycleDict
->setObject((const OSSymbol
*) this, newDict
);
816 for (unsigned int i
= 0; i
< count
; i
++) {
817 const OSMetaClassBase
*obj
= dictionary
[i
].value
;
818 OSCollection
*coll
= OSDynamicCast(OSCollection
, EXT_CAST(obj
));
821 OSCollection
*newColl
= coll
->copyCollection(cycleDict
);
826 newDict
->dictionary
[i
].value
= newColl
;
828 coll
->taggedRelease(OSTypeID(OSCollection
));
829 newColl
->taggedRetain(OSTypeID(OSCollection
));
845 cycleDict
->release();
852 OSDictionary::copyKeys(void)
856 array
= OSArray::withCapacity(count
);
861 for (unsigned int i
= 0; i
< count
; i
++) {
862 if (!array
->setObject(i
, dictionary
[i
].key
)) {
872 OSDictionary::iterateObjects(void * refcon
, bool (*callback
)(void * refcon
, const OSSymbol
* key
, OSObject
* object
))
874 unsigned int initialUpdateStamp
;
877 initialUpdateStamp
= updateStamp
;
879 for (unsigned int i
= 0; i
< count
; i
++) {
880 done
= callback(refcon
, dictionary
[i
].key
, EXT_CAST(dictionary
[i
].value
));
884 if (initialUpdateStamp
!= updateStamp
) {
889 return initialUpdateStamp
== updateStamp
;
893 OSDictionaryIterateObjectsBlock(void * refcon
, const OSSymbol
* key
, OSObject
* object
)
895 bool (^block
)(const OSSymbol
* key
, OSObject
* object
) = (typeof(block
))refcon
;
896 return block(key
, object
);
900 OSDictionary::iterateObjects(bool (^block
)(const OSSymbol
* key
, OSObject
* object
))
902 return iterateObjects((void *)block
, &OSDictionaryIterateObjectsBlock
);