2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* OSDictionary.m created by rsulack on Fri 12-Sep-1997 */
31 /* OSDictionary.cpp converted to C++ by gvdl on Fri 1998-10-30 */
32 /* OSDictionary.cpp rewritten by gvdl on Fri 1998-10-30 */
35 #include <libkern/c++/OSDictionary.h>
36 #include <libkern/c++/OSArray.h>
37 #include <libkern/c++/OSSymbol.h>
38 #include <libkern/c++/OSSerialize.h>
39 #include <libkern/c++/OSLib.h>
40 #include <libkern/c++/OSCollectionIterator.h>
42 #define super OSCollection
44 OSDefineMetaClassAndStructors(OSDictionary
, OSCollection
)
45 OSMetaClassDefineReservedUnused(OSDictionary
, 0);
46 OSMetaClassDefineReservedUnused(OSDictionary
, 1);
47 OSMetaClassDefineReservedUnused(OSDictionary
, 2);
48 OSMetaClassDefineReservedUnused(OSDictionary
, 3);
49 OSMetaClassDefineReservedUnused(OSDictionary
, 4);
50 OSMetaClassDefineReservedUnused(OSDictionary
, 5);
51 OSMetaClassDefineReservedUnused(OSDictionary
, 6);
52 OSMetaClassDefineReservedUnused(OSDictionary
, 7);
56 extern int debug_container_malloc_size
;
58 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
63 #define EXT_CAST(obj) \
64 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
66 bool OSDictionary::initWithCapacity(unsigned int inCapacity
)
71 int size
= inCapacity
* sizeof(dictEntry
);
73 dictionary
= (dictEntry
*) kalloc(size
);
77 bzero(dictionary
, size
);
81 capacity
= inCapacity
;
82 capacityIncrement
= (inCapacity
)? inCapacity
: 16;
87 bool OSDictionary::initWithObjects(const OSObject
*objects
[],
88 const OSSymbol
*keys
[],
89 unsigned int theCount
,
90 unsigned int theCapacity
)
92 unsigned int capacity
= theCount
;
94 if (!objects
|| !keys
)
98 if (theCount
> theCapacity
)
101 capacity
= theCapacity
;
104 if (!initWithCapacity(capacity
))
107 for (unsigned int i
= 0; i
< theCount
; i
++) {
108 const OSMetaClassBase
*newObject
= *objects
++;
110 if (!newObject
|| !keys
[i
] || !setObject(keys
[i
], newObject
))
117 bool OSDictionary::initWithObjects(const OSObject
*objects
[],
118 const OSString
*keys
[],
119 unsigned int theCount
,
120 unsigned int theCapacity
)
122 unsigned int capacity
= theCount
;
124 if (!objects
|| !keys
)
128 if (theCount
> theCapacity
)
131 capacity
= theCapacity
;
134 if (!initWithCapacity(capacity
))
137 for (unsigned int i
= 0; i
< theCount
; i
++) {
138 const OSSymbol
*key
= OSSymbol::withString(*keys
++);
139 const OSMetaClassBase
*newObject
= *objects
++;
144 if (!newObject
|| !setObject(key
, newObject
)) {
155 bool OSDictionary::initWithDictionary(const OSDictionary
*dict
,
156 unsigned int theCapacity
)
158 unsigned int capacity
;
163 capacity
= dict
->count
;
166 if ( dict
->count
> theCapacity
)
169 capacity
= theCapacity
;
172 if (!initWithCapacity(capacity
))
176 bcopy(dict
->dictionary
, dictionary
, count
* sizeof(dictEntry
));
177 for (unsigned int i
= 0; i
< count
; i
++) {
178 dictionary
[i
].key
->taggedRetain(OSTypeID(OSCollection
));
179 dictionary
[i
].value
->taggedRetain(OSTypeID(OSCollection
));
185 OSDictionary
*OSDictionary::withCapacity(unsigned int capacity
)
187 OSDictionary
*me
= new OSDictionary
;
189 if (me
&& !me
->initWithCapacity(capacity
)) {
197 OSDictionary
*OSDictionary::withObjects(const OSObject
*objects
[],
198 const OSSymbol
*keys
[],
200 unsigned int capacity
)
202 OSDictionary
*me
= new OSDictionary
;
204 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
212 OSDictionary
*OSDictionary::withObjects(const OSObject
*objects
[],
213 const OSString
*keys
[],
215 unsigned int capacity
)
217 OSDictionary
*me
= new OSDictionary
;
219 if (me
&& !me
->initWithObjects(objects
, keys
, count
, capacity
)) {
227 OSDictionary
*OSDictionary::withDictionary(const OSDictionary
*dict
,
228 unsigned int capacity
)
230 OSDictionary
*me
= new OSDictionary
;
232 if (me
&& !me
->initWithDictionary(dict
, capacity
)) {
240 void OSDictionary::free()
242 (void) super::setOptions(0, kImmutable
);
245 kfree(dictionary
, capacity
* sizeof(dictEntry
));
246 ACCUMSIZE( -(capacity
* sizeof(dictEntry
)) );
252 unsigned int OSDictionary::getCount() const { return count
; }
253 unsigned int OSDictionary::getCapacity() const { return capacity
; }
255 unsigned int OSDictionary::getCapacityIncrement() const
257 return capacityIncrement
;
260 unsigned int OSDictionary::setCapacityIncrement(unsigned int increment
)
262 capacityIncrement
= (increment
)? increment
: 16;
264 return capacityIncrement
;
267 unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity
)
270 int oldSize
, newSize
;
272 if (newCapacity
<= capacity
)
276 newCapacity
= (((newCapacity
- 1) / capacityIncrement
) + 1)
278 newSize
= sizeof(dictEntry
) * newCapacity
;
280 newDict
= (dictEntry
*) kalloc(newSize
);
282 oldSize
= sizeof(dictEntry
) * capacity
;
284 bcopy(dictionary
, newDict
, oldSize
);
285 bzero(&newDict
[capacity
], newSize
- oldSize
);
287 ACCUMSIZE(newSize
- oldSize
);
288 kfree(dictionary
, oldSize
);
290 dictionary
= newDict
;
291 capacity
= newCapacity
;
297 void OSDictionary::flushCollection()
301 for (unsigned int i
= 0; i
< count
; i
++) {
302 dictionary
[i
].key
->taggedRelease(OSTypeID(OSCollection
));
303 dictionary
[i
].value
->taggedRelease(OSTypeID(OSCollection
));
309 setObject(const OSSymbol
*aKey
, const OSMetaClassBase
*anObject
)
311 if (!anObject
|| !aKey
)
314 // if the key exists, replace the object
315 for (unsigned int i
= 0; i
< count
; i
++) {
316 if (aKey
== dictionary
[i
].key
) {
317 const OSMetaClassBase
*oldObject
= dictionary
[i
].value
;
321 anObject
->taggedRetain(OSTypeID(OSCollection
));
322 dictionary
[i
].value
= anObject
;
324 oldObject
->taggedRelease(OSTypeID(OSCollection
));
329 // add new key, possibly extending our capacity
330 if (count
>= capacity
&& count
>= ensureCapacity(count
+1))
335 aKey
->taggedRetain(OSTypeID(OSCollection
));
336 anObject
->taggedRetain(OSTypeID(OSCollection
));
337 dictionary
[count
].key
= aKey
;
338 dictionary
[count
].value
= anObject
;
344 void OSDictionary::removeObject(const OSSymbol
*aKey
)
349 // if the key exists, remove the object
350 for (unsigned int i
= 0; i
< count
; i
++)
351 if (aKey
== dictionary
[i
].key
) {
352 dictEntry oldEntry
= dictionary
[i
];
357 for (; i
< count
; i
++)
358 dictionary
[i
] = dictionary
[i
+1];
360 oldEntry
.key
->taggedRelease(OSTypeID(OSCollection
));
361 oldEntry
.value
->taggedRelease(OSTypeID(OSCollection
));
367 // Returns true on success, false on an error condition.
368 bool OSDictionary::merge(const OSDictionary
*srcDict
)
370 const OSSymbol
* sym
;
371 OSCollectionIterator
* iter
;
373 if ( !OSDynamicCast(OSDictionary
, srcDict
) )
376 iter
= OSCollectionIterator::withCollection((OSDictionary
*)srcDict
);
380 while ( (sym
= (const OSSymbol
*)iter
->getNextObject()) ) {
381 const OSMetaClassBase
* obj
;
383 obj
= srcDict
->getObject(sym
);
384 if ( !setObject(sym
, obj
) ) {
394 OSObject
*OSDictionary::getObject(const OSSymbol
*aKey
) const
399 // if the key exists, remove the object
400 for (unsigned int i
= 0; i
< count
; i
++)
401 if (aKey
== dictionary
[i
].key
)
402 return (OSObject
*) dictionary
[i
].value
;
408 #define OBJECT_WRAP_1(cmd, k) \
410 const OSSymbol *tmpKey = k; \
411 OSObject *retObj = cmd(tmpKey); \
417 #define OBJECT_WRAP_2(cmd, k, o) \
419 const OSSymbol *tmpKey = k; \
420 bool ret = cmd(tmpKey, o); \
426 #define OBJECT_WRAP_3(cmd, k) \
428 const OSSymbol *tmpKey = k; \
434 bool OSDictionary::setObject(const OSString
*aKey
, const OSMetaClassBase
*anObject
)
435 OBJECT_WRAP_2(setObject
, OSSymbol::withString(aKey
), anObject
)
436 bool OSDictionary::setObject(const char *aKey
, const OSMetaClassBase
*anObject
)
437 OBJECT_WRAP_2(setObject
, OSSymbol::withCString(aKey
), anObject
)
439 OSObject
*OSDictionary::getObject(const OSString
*aKey
) const
440 OBJECT_WRAP_1(getObject
, OSSymbol::withString(aKey
))
441 OSObject
*OSDictionary::getObject(const char *aKey
) const
442 OBJECT_WRAP_1(getObject
, OSSymbol::withCString(aKey
))
444 void OSDictionary::removeObject(const OSString
*aKey
)
445 OBJECT_WRAP_3(removeObject
, OSSymbol::withString(aKey
))
446 void OSDictionary::removeObject(const char *aKey
)
447 OBJECT_WRAP_3(removeObject
, OSSymbol::withCString(aKey
))
450 OSDictionary::isEqualTo(const OSDictionary
*srcDict
, const OSCollection
*keys
) const
452 OSCollectionIterator
* iter
;
453 unsigned int keysCount
;
454 const OSMetaClassBase
* obj1
;
455 const OSMetaClassBase
* obj2
;
459 if ( this == srcDict
)
462 keysCount
= keys
->getCount();
463 if ( (count
< keysCount
) || (srcDict
->getCount() < keysCount
) )
466 iter
= OSCollectionIterator::withCollection(keys
);
471 while ( (aKey
= OSDynamicCast(OSString
, iter
->getNextObject())) ) {
472 obj1
= getObject(aKey
);
473 obj2
= srcDict
->getObject(aKey
);
474 if ( !obj1
|| !obj2
) {
479 if ( !obj1
->isEqualTo(obj2
) ) {
489 bool OSDictionary::isEqualTo(const OSDictionary
*srcDict
) const
492 const OSMetaClassBase
* obj
;
494 if ( this == srcDict
)
497 if ( count
!= srcDict
->getCount() )
500 for ( i
= 0; i
< count
; i
++ ) {
501 obj
= srcDict
->getObject(dictionary
[i
].key
);
505 if ( !dictionary
[i
].value
->isEqualTo(obj
) )
512 bool OSDictionary::isEqualTo(const OSMetaClassBase
*anObject
) const
516 dict
= OSDynamicCast(OSDictionary
, anObject
);
518 return isEqualTo(dict
);
523 unsigned int OSDictionary::iteratorSize() const
525 return sizeof(unsigned int);
528 bool OSDictionary::initIterator(void *inIterator
) const
530 unsigned int *iteratorP
= (unsigned int *) inIterator
;
536 bool OSDictionary::getNextObjectForIterator(void *inIterator
, OSObject
**ret
) const
538 unsigned int *iteratorP
= (unsigned int *) inIterator
;
539 unsigned int index
= (*iteratorP
)++;
542 *ret
= (OSObject
*) dictionary
[index
].key
;
549 bool OSDictionary::serialize(OSSerialize
*s
) const
551 if (s
->previouslySerialized(this)) return true;
553 if (!s
->addXMLStartTag(this, "dict")) return false;
555 for (unsigned i
= 0; i
< count
; i
++) {
556 const OSSymbol
*key
= dictionary
[i
].key
;
558 // due the nature of the XML syntax, this must be a symbol
559 if (!key
->metaCast("OSSymbol")) {
562 if (!s
->addString("<key>")) return false;
563 const char *c
= key
->getCStringNoCopy();
566 if (!s
->addString("<")) return false;
567 } else if (*c
== '>') {
568 if (!s
->addString(">")) return false;
569 } else if (*c
== '&') {
570 if (!s
->addString("&")) return false;
572 if (!s
->addChar(*c
)) return false;
576 if (!s
->addXMLEndTag("key")) return false;
578 if (!dictionary
[i
].value
->serialize(s
)) return false;
581 return s
->addXMLEndTag("dict");
584 unsigned OSDictionary::setOptions(unsigned options
, unsigned mask
, void *)
586 unsigned old
= super::setOptions(options
, mask
);
587 if ((old
^ options
) & mask
) {
589 // Value changed need to recurse over all of the child collections
590 for ( unsigned i
= 0; i
< count
; i
++ ) {
591 OSCollection
*v
= OSDynamicCast(OSCollection
, dictionary
[i
].value
);
593 v
->setOptions(options
, mask
);
600 OSCollection
* OSDictionary::copyCollection(OSDictionary
*cycleDict
)
602 bool allocDict
= !cycleDict
;
603 OSCollection
*ret
= 0;
604 OSDictionary
*newDict
= 0;
607 cycleDict
= OSDictionary::withCapacity(16);
614 ret
= super::copyCollection(cycleDict
);
618 newDict
= OSDictionary::withDictionary(this);
622 // Insert object into cycle Dictionary
623 cycleDict
->setObject((const OSSymbol
*) this, newDict
);
625 for (unsigned int i
= 0; i
< count
; i
++) {
626 const OSMetaClassBase
*obj
= dictionary
[i
].value
;
627 OSCollection
*coll
= OSDynamicCast(OSCollection
, EXT_CAST(obj
));
630 OSCollection
*newColl
= coll
->copyCollection(cycleDict
);
634 newDict
->dictionary
[i
].value
= newColl
;
636 coll
->taggedRelease(OSTypeID(OSCollection
));
637 newColl
->taggedRetain(OSTypeID(OSCollection
));
652 cycleDict
->release();