2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* OSDictionary.m created by rsulack on Fri 12-Sep-1997 */
24 /* OSDictionary.cpp converted to C++ by gvdl on Fri 1998-10-30 */
25 /* OSDictionary.cpp rewritten by gvdl on Fri 1998-10-30 */
28 #include <libkern/c++/OSDictionary.h>
29 #include <libkern/c++/OSArray.h>
30 #include <libkern/c++/OSSymbol.h>
31 #include <libkern/c++/OSSerialize.h>
32 #include <libkern/c++/OSLib.h>
33 #include <libkern/c++/OSCollectionIterator.h>
35 #define super OSCollection
37 OSDefineMetaClassAndStructors(OSDictionary
, OSCollection
)
38 OSMetaClassDefineReservedUnused(OSDictionary
, 0);
39 OSMetaClassDefineReservedUnused(OSDictionary
, 1);
40 OSMetaClassDefineReservedUnused(OSDictionary
, 2);
41 OSMetaClassDefineReservedUnused(OSDictionary
, 3);
42 OSMetaClassDefineReservedUnused(OSDictionary
, 4);
43 OSMetaClassDefineReservedUnused(OSDictionary
, 5);
44 OSMetaClassDefineReservedUnused(OSDictionary
, 6);
45 OSMetaClassDefineReservedUnused(OSDictionary
, 7);
49 extern int debug_container_malloc_size
;
51 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
56 #define EXT_CAST(obj) \
57 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
59 bool OSDictionary::initWithCapacity(unsigned int inCapacity
)
64 int size
= inCapacity
* sizeof(dictEntry
);
66 dictionary
= (dictEntry
*) kalloc(size
);
70 bzero(dictionary
, size
);
74 capacity
= inCapacity
;
75 capacityIncrement
= (inCapacity
)? inCapacity
: 16;
80 bool OSDictionary::initWithObjects(const OSObject
*objects
[],
81 const OSSymbol
*keys
[],
82 unsigned int theCount
,
83 unsigned int theCapacity
)
85 unsigned int capacity
= theCount
;
87 if (!objects
|| !keys
)
91 if (theCount
> theCapacity
)
94 capacity
= theCapacity
;
97 if (!initWithCapacity(capacity
))
100 for (unsigned int i
= 0; i
< theCount
; i
++) {
101 const OSMetaClassBase
*newObject
= *objects
++;
103 if (!newObject
|| !keys
[i
] || !setObject(keys
[i
], newObject
))
110 bool OSDictionary::initWithObjects(const OSObject
*objects
[],
111 const OSString
*keys
[],
112 unsigned int theCount
,
113 unsigned int theCapacity
)
115 unsigned int capacity
= theCount
;
117 if (!objects
|| !keys
)
121 if (theCount
> theCapacity
)
124 capacity
= theCapacity
;
127 if (!initWithCapacity(capacity
))
130 for (unsigned int i
= 0; i
< theCount
; i
++) {
131 const OSSymbol
*key
= OSSymbol::withString(*keys
++);
132 const OSMetaClassBase
*newObject
= *objects
++;
137 if (!newObject
|| !setObject(key
, newObject
)) {
148 bool OSDictionary::initWithDictionary(const OSDictionary
*dict
,
149 unsigned int theCapacity
)
151 unsigned int capacity
;
156 capacity
= dict
->count
;
159 if ( dict
->count
> theCapacity
)
162 capacity
= theCapacity
;
165 if (!initWithCapacity(capacity
))
169 bcopy(dict
->dictionary
, dictionary
, count
* sizeof(dictEntry
));
170 for (unsigned int i
= 0; i
< count
; i
++) {
171 dictionary
[i
].key
->taggedRetain(OSTypeID(OSCollection
));
172 dictionary
[i
].value
->taggedRetain(OSTypeID(OSCollection
));
178 OSDictionary
*OSDictionary::withCapacity(unsigned int capacity
)
180 OSDictionary
*me
= new OSDictionary
;
182 if (me
&& !me
->initWithCapacity(capacity
)) {
190 OSDictionary
*OSDictionary::withObjects(const OSObject
*objects
[],
191 const OSSymbol
*keys
[],
193 unsigned int capacity
)
195 OSDictionary
*me
= new OSDictionary
;
197 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
205 OSDictionary
*OSDictionary::withObjects(const OSObject
*objects
[],
206 const OSString
*keys
[],
208 unsigned int capacity
)
210 OSDictionary
*me
= new OSDictionary
;
212 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
220 OSDictionary
*OSDictionary::withDictionary(const OSDictionary
*dict
,
221 unsigned int capacity
)
223 OSDictionary
*me
= new OSDictionary
;
225 if (me
&& !me
->initWithDictionary(dict
, capacity
)) {
233 void OSDictionary::free()
235 (void) super::setOptions(0, kImmutable
);
238 kfree((vm_offset_t
)dictionary
, capacity
* sizeof(dictEntry
));
239 ACCUMSIZE( -(capacity
* sizeof(dictEntry
)) );
245 unsigned int OSDictionary::getCount() const { return count
; }
246 unsigned int OSDictionary::getCapacity() const { return capacity
; }
248 unsigned int OSDictionary::getCapacityIncrement() const
250 return capacityIncrement
;
253 unsigned int OSDictionary::setCapacityIncrement(unsigned int increment
)
255 capacityIncrement
= (increment
)? increment
: 16;
257 return capacityIncrement
;
260 unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity
)
263 int oldSize
, newSize
;
265 if (newCapacity
<= capacity
)
269 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1)
271 newSize
= sizeof(dictEntry
) * newCapacity
;
273 newDict
= (dictEntry
*) kalloc(newSize
);
275 oldSize
= sizeof(dictEntry
) * capacity
;
277 bcopy(dictionary
, newDict
, oldSize
);
278 bzero(&newDict
[capacity
], newSize
- oldSize
);
280 ACCUMSIZE(newSize
- oldSize
);
281 kfree((vm_offset_t
)dictionary
, oldSize
);
283 dictionary
= newDict
;
284 capacity
= newCapacity
;
290 void OSDictionary::flushCollection()
294 for (unsigned int i
= 0; i
< count
; i
++) {
295 dictionary
[i
].key
->taggedRelease(OSTypeID(OSCollection
));
296 dictionary
[i
].value
->taggedRelease(OSTypeID(OSCollection
));
302 setObject(const OSSymbol
*aKey
, const OSMetaClassBase
*anObject
)
304 if (!anObject
|| !aKey
)
307 // if the key exists, replace the object
308 for (unsigned int i
= 0; i
< count
; i
++) {
309 if (aKey
== dictionary
[i
].key
) {
310 const OSMetaClassBase
*oldObject
= dictionary
[i
].value
;
314 anObject
->taggedRetain(OSTypeID(OSCollection
));
315 dictionary
[i
].value
= anObject
;
317 oldObject
->taggedRelease(OSTypeID(OSCollection
));
322 // add new key, possibly extending our capacity
323 if (count
>= capacity
&& count
>= ensureCapacity(count
+1))
328 aKey
->taggedRetain(OSTypeID(OSCollection
));
329 anObject
->taggedRetain(OSTypeID(OSCollection
));
330 dictionary
[count
].key
= aKey
;
331 dictionary
[count
].value
= anObject
;
337 void OSDictionary::removeObject(const OSSymbol
*aKey
)
342 // if the key exists, remove the object
343 for (unsigned int i
= 0; i
< count
; i
++)
344 if (aKey
== dictionary
[i
].key
) {
345 dictEntry oldEntry
= dictionary
[i
];
350 for (; i
< count
; i
++)
351 dictionary
[i
] = dictionary
[i
+1];
353 oldEntry
.key
->taggedRelease(OSTypeID(OSCollection
));
354 oldEntry
.value
->taggedRelease(OSTypeID(OSCollection
));
360 // Returns true on success, false on an error condition.
361 bool OSDictionary::merge(const OSDictionary
*srcDict
)
363 const OSSymbol
* sym
;
364 OSCollectionIterator
* iter
;
366 if ( !OSDynamicCast(OSDictionary
, srcDict
) )
369 iter
= OSCollectionIterator::withCollection((OSDictionary
*)srcDict
);
373 while ( (sym
= (const OSSymbol
*)iter
->getNextObject()) ) {
374 const OSMetaClassBase
* obj
;
376 obj
= srcDict
->getObject(sym
);
377 if ( !setObject(sym
, obj
) ) {
387 OSObject
*OSDictionary::getObject(const OSSymbol
*aKey
) const
392 // if the key exists, remove the object
393 for (unsigned int i
= 0; i
< count
; i
++)
394 if (aKey
== dictionary
[i
].key
)
395 return (OSObject
*) dictionary
[i
].value
;
401 #define OBJECT_WRAP_1(cmd, k) \
403 const OSSymbol *tmpKey = k; \
404 OSObject *retObj = cmd(tmpKey); \
410 #define OBJECT_WRAP_2(cmd, k, o) \
412 const OSSymbol *tmpKey = k; \
413 bool ret = cmd(tmpKey, o); \
419 #define OBJECT_WRAP_3(cmd, k) \
421 const OSSymbol *tmpKey = k; \
427 bool OSDictionary::setObject(const OSString
*aKey
, const OSMetaClassBase
*anObject
)
428 OBJECT_WRAP_2(setObject
, OSSymbol::withString(aKey
), anObject
)
429 bool OSDictionary::setObject(const char *aKey
, const OSMetaClassBase
*anObject
)
430 OBJECT_WRAP_2(setObject
, OSSymbol::withCString(aKey
), anObject
)
432 OSObject
*OSDictionary::getObject(const OSString
*aKey
) const
433 OBJECT_WRAP_1(getObject
, OSSymbol::withString(aKey
))
434 OSObject
*OSDictionary::getObject(const char *aKey
) const
435 OBJECT_WRAP_1(getObject
, OSSymbol::withCString(aKey
))
437 void OSDictionary::removeObject(const OSString
*aKey
)
438 OBJECT_WRAP_3(removeObject
, OSSymbol::withString(aKey
))
439 void OSDictionary::removeObject(const char *aKey
)
440 OBJECT_WRAP_3(removeObject
, OSSymbol::withCString(aKey
))
443 OSDictionary::isEqualTo(const OSDictionary
*srcDict
, const OSCollection
*keys
) const
445 OSCollectionIterator
* iter
;
446 unsigned int keysCount
;
447 const OSMetaClassBase
* obj1
;
448 const OSMetaClassBase
* obj2
;
452 if ( this == srcDict
)
455 keysCount
= keys
->getCount();
456 if ( (count
< keysCount
) || (srcDict
->getCount() < keysCount
) )
459 iter
= OSCollectionIterator::withCollection(keys
);
464 while ( (aKey
= OSDynamicCast(OSString
, iter
->getNextObject())) ) {
465 obj1
= getObject(aKey
);
466 obj2
= srcDict
->getObject(aKey
);
467 if ( !obj1
|| !obj2
) {
472 if ( !obj1
->isEqualTo(obj2
) ) {
482 bool OSDictionary::isEqualTo(const OSDictionary
*srcDict
) const
485 const OSMetaClassBase
* obj
;
487 if ( this == srcDict
)
490 if ( count
!= srcDict
->getCount() )
493 for ( i
= 0; i
< count
; i
++ ) {
494 obj
= srcDict
->getObject(dictionary
[i
].key
);
498 if ( !dictionary
[i
].value
->isEqualTo(obj
) )
505 bool OSDictionary::isEqualTo(const OSMetaClassBase
*anObject
) const
509 dict
= OSDynamicCast(OSDictionary
, anObject
);
511 return isEqualTo(dict
);
516 unsigned int OSDictionary::iteratorSize() const
518 return sizeof(unsigned int);
521 bool OSDictionary::initIterator(void *inIterator
) const
523 unsigned int *iteratorP
= (unsigned int *) inIterator
;
529 bool OSDictionary::getNextObjectForIterator(void *inIterator
, OSObject
**ret
) const
531 unsigned int *iteratorP
= (unsigned int *) inIterator
;
532 unsigned int index
= (*iteratorP
)++;
535 *ret
= (OSObject
*) dictionary
[index
].key
;
542 bool OSDictionary::serialize(OSSerialize
*s
) const
544 if (s
->previouslySerialized(this)) return true;
546 if (!s
->addXMLStartTag(this, "dict")) return false;
548 for (unsigned i
= 0; i
< count
; i
++) {
549 const OSSymbol
*key
= dictionary
[i
].key
;
551 // due the nature of the XML syntax, this must be a symbol
552 if (!key
->metaCast("OSSymbol")) {
555 if (!s
->addString("<key>")) return false;
556 const char *c
= key
->getCStringNoCopy();
559 if (!s
->addString("<")) return false;
560 } else if (*c
== '>') {
561 if (!s
->addString(">")) return false;
562 } else if (*c
== '&') {
563 if (!s
->addString("&")) return false;
565 if (!s
->addChar(*c
)) return false;
569 if (!s
->addXMLEndTag("key")) return false;
571 if (!dictionary
[i
].value
->serialize(s
)) return false;
574 return s
->addXMLEndTag("dict");
577 unsigned OSDictionary::setOptions(unsigned options
, unsigned mask
, void *)
579 unsigned old
= super::setOptions(options
, mask
);
580 if ((old
^ options
) & mask
) {
582 // Value changed need to recurse over all of the child collections
583 for ( unsigned i
= 0; i
< count
; i
++ ) {
584 OSCollection
*v
= OSDynamicCast(OSCollection
, dictionary
[i
].value
);
586 v
->setOptions(options
, mask
);
593 OSCollection
* OSDictionary::copyCollection(OSDictionary
*cycleDict
)
595 bool allocDict
= !cycleDict
;
596 OSCollection
*ret
= 0;
597 OSDictionary
*newDict
= 0;
600 cycleDict
= OSDictionary::withCapacity(16);
607 ret
= super::copyCollection(cycleDict
);
611 newDict
= OSDictionary::withDictionary(this);
615 // Insert object into cycle Dictionary
616 cycleDict
->setObject((const OSSymbol
*) this, newDict
);
618 for (unsigned int i
= 0; i
< count
; i
++) {
619 const OSMetaClassBase
*obj
= dictionary
[i
].value
;
620 OSCollection
*coll
= OSDynamicCast(OSCollection
, EXT_CAST(obj
));
623 OSCollection
*newColl
= coll
->copyCollection(cycleDict
);
627 newDict
->dictionary
[i
].value
= newColl
;
629 coll
->taggedRelease(OSTypeID(OSCollection
));
630 newColl
->taggedRetain(OSTypeID(OSCollection
));
645 cycleDict
->release();