]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSDictionary.cpp
7329f3a4ec82a16595a8c2e6e75633d7f92233f6
[apple/xnu.git] / libkern / c++ / OSDictionary.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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 */
31
32
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>
39
40 #define super OSCollection
41
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);
51
52 #if OSALLOCDEBUG
53 extern "C" {
54 extern int debug_container_malloc_size;
55 };
56 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
57 #else
58 #define ACCUMSIZE(s)
59 #endif
60
61 #define EXT_CAST(obj) \
62 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj))
63
64 bool OSDictionary::initWithCapacity(unsigned int inCapacity)
65 {
66 if (!super::init())
67 return false;
68
69 int size = inCapacity * sizeof(dictEntry);
70
71 //fOptions |= kSort;
72
73 dictionary = (dictEntry *) kalloc(size);
74 if (!dictionary)
75 return false;
76
77 bzero(dictionary, size);
78 ACCUMSIZE(size);
79
80 count = 0;
81 capacity = inCapacity;
82 capacityIncrement = (inCapacity)? inCapacity : 16;
83
84 return true;
85 }
86
87 bool OSDictionary::initWithObjects(const OSObject *objects[],
88 const OSSymbol *keys[],
89 unsigned int theCount,
90 unsigned int theCapacity)
91 {
92 unsigned int newCapacity = theCount;
93
94 if (!objects || !keys)
95 return false;
96
97 if ( theCapacity ) {
98 if (theCount > theCapacity)
99 return false;
100
101 newCapacity = theCapacity;
102 }
103
104 if (!initWithCapacity(newCapacity))
105 return false;
106
107 for (unsigned int i = 0; i < theCount; i++) {
108 const OSMetaClassBase *newObject = *objects++;
109
110 if (!newObject || !keys[i] || !setObject(keys[i], newObject))
111 return false;
112 }
113
114 return true;
115 }
116
117 bool OSDictionary::initWithObjects(const OSObject *objects[],
118 const OSString *keys[],
119 unsigned int theCount,
120 unsigned int theCapacity)
121 {
122 unsigned int newCapacity = theCount;
123
124 if (!objects || !keys)
125 return false;
126
127 if ( theCapacity ) {
128 if (theCount > theCapacity)
129 return false;
130
131 newCapacity = theCapacity;
132 }
133
134 if (!initWithCapacity(newCapacity))
135 return false;
136
137 for (unsigned int i = 0; i < theCount; i++) {
138 const OSSymbol *key = OSSymbol::withString(*keys++);
139 const OSMetaClassBase *newObject = *objects++;
140
141 if (!key)
142 return false;
143
144 if (!newObject || !setObject(key, newObject)) {
145 key->release();
146 return false;
147 }
148
149 key->release();
150 }
151
152 return true;
153 }
154
155 bool OSDictionary::initWithDictionary(const OSDictionary *dict,
156 unsigned int theCapacity)
157 {
158 unsigned int newCapacity;
159
160 if ( !dict )
161 return false;
162
163 newCapacity = dict->count;
164
165 if ( theCapacity ) {
166 if ( dict->count > theCapacity )
167 return false;
168
169 newCapacity = theCapacity;
170 }
171
172 if (!initWithCapacity(newCapacity))
173 return false;
174
175 if ((kSort & fOptions) && !(kSort & dict->fOptions)) {
176 for (unsigned int i = 0; i < dict->count; i++) {
177 if (!setObject(dict->dictionary[i].key, dict->dictionary[i].value)) {
178 return false;
179 }
180 }
181 return true;
182 }
183
184 count = dict->count;
185 bcopy(dict->dictionary, dictionary, count * sizeof(dictEntry));
186 for (unsigned int i = 0; i < count; i++) {
187 dictionary[i].key->taggedRetain(OSTypeID(OSCollection));
188 dictionary[i].value->taggedRetain(OSTypeID(OSCollection));
189 }
190
191 return true;
192 }
193
194 OSDictionary *OSDictionary::withCapacity(unsigned int capacity)
195 {
196 OSDictionary *me = new OSDictionary;
197
198 if (me && !me->initWithCapacity(capacity)) {
199 me->release();
200 return 0;
201 }
202
203 return me;
204 }
205
206 OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
207 const OSSymbol *keys[],
208 unsigned int count,
209 unsigned int capacity)
210 {
211 OSDictionary *me = new OSDictionary;
212
213 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
214 me->release();
215 return 0;
216 }
217
218 return me;
219 }
220
221 OSDictionary *OSDictionary::withObjects(const OSObject *objects[],
222 const OSString *keys[],
223 unsigned int count,
224 unsigned int capacity)
225 {
226 OSDictionary *me = new OSDictionary;
227
228 if (me && !me->initWithObjects(objects, keys, count, capacity)) {
229 me->release();
230 return 0;
231 }
232
233 return me;
234 }
235
236 OSDictionary *OSDictionary::withDictionary(const OSDictionary *dict,
237 unsigned int capacity)
238 {
239 OSDictionary *me = new OSDictionary;
240
241 if (me && !me->initWithDictionary(dict, capacity)) {
242 me->release();
243 return 0;
244 }
245
246 return me;
247 }
248
249 void OSDictionary::free()
250 {
251 (void) super::setOptions(0, kImmutable);
252 flushCollection();
253 if (dictionary) {
254 kfree(dictionary, capacity * sizeof(dictEntry));
255 ACCUMSIZE( -(capacity * sizeof(dictEntry)) );
256 }
257
258 super::free();
259 }
260
261 unsigned int OSDictionary::getCount() const { return count; }
262 unsigned int OSDictionary::getCapacity() const { return capacity; }
263
264 unsigned int OSDictionary::getCapacityIncrement() const
265 {
266 return capacityIncrement;
267 }
268
269 unsigned int OSDictionary::setCapacityIncrement(unsigned int increment)
270 {
271 capacityIncrement = (increment)? increment : 16;
272
273 return capacityIncrement;
274 }
275
276 unsigned int OSDictionary::ensureCapacity(unsigned int newCapacity)
277 {
278 dictEntry *newDict;
279 int oldSize, newSize;
280
281 if (newCapacity <= capacity)
282 return capacity;
283
284 // round up
285 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
286 * capacityIncrement;
287 newSize = sizeof(dictEntry) * newCapacity;
288
289 newDict = (dictEntry *) kalloc(newSize);
290 if (newDict) {
291 oldSize = sizeof(dictEntry) * capacity;
292
293 bcopy(dictionary, newDict, oldSize);
294 bzero(&newDict[capacity], newSize - oldSize);
295
296 ACCUMSIZE(newSize - oldSize);
297 kfree(dictionary, oldSize);
298
299 dictionary = newDict;
300 capacity = newCapacity;
301 }
302
303 return capacity;
304 }
305
306 void OSDictionary::flushCollection()
307 {
308 haveUpdated();
309
310 for (unsigned int i = 0; i < count; i++) {
311 dictionary[i].key->taggedRelease(OSTypeID(OSCollection));
312 dictionary[i].value->taggedRelease(OSTypeID(OSCollection));
313 }
314 count = 0;
315 }
316
317 bool OSDictionary::
318 setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject)
319 {
320 unsigned int i;
321 bool exists;
322
323 if (!anObject || !aKey)
324 return false;
325
326 // if the key exists, replace the object
327
328 if (fOptions & kSort) {
329 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
330 exists = (i < count) && (aKey == dictionary[i].key);
331 } else for (exists = false, i = 0; i < count; i++) {
332 if ((exists = (aKey == dictionary[i].key))) break;
333 }
334
335 if (exists) {
336 const OSMetaClassBase *oldObject = dictionary[i].value;
337
338 haveUpdated();
339
340 anObject->taggedRetain(OSTypeID(OSCollection));
341 dictionary[i].value = anObject;
342
343 oldObject->taggedRelease(OSTypeID(OSCollection));
344 return true;
345 }
346
347 // add new key, possibly extending our capacity
348 if (count >= capacity && count >= ensureCapacity(count+1))
349 return false;
350
351 haveUpdated();
352
353 bcopy(&dictionary[i], &dictionary[i+1], (count - i) * sizeof(dictionary[0]));
354
355 aKey->taggedRetain(OSTypeID(OSCollection));
356 anObject->taggedRetain(OSTypeID(OSCollection));
357 dictionary[i].key = aKey;
358 dictionary[i].value = anObject;
359 count++;
360
361 return true;
362 }
363
364 void OSDictionary::removeObject(const OSSymbol *aKey)
365 {
366 unsigned int i;
367 bool exists;
368
369 if (!aKey)
370 return;
371
372 // if the key exists, remove the object
373
374 if (fOptions & kSort) {
375 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
376 exists = (i < count) && (aKey == dictionary[i].key);
377 } else for (exists = false, i = 0; i < count; i++) {
378 if ((exists = (aKey == dictionary[i].key))) break;
379 }
380
381 if (exists) {
382 dictEntry oldEntry = dictionary[i];
383
384 haveUpdated();
385
386 count--;
387 bcopy(&dictionary[i+1], &dictionary[i], (count - i) * sizeof(dictionary[0]));
388
389 oldEntry.key->taggedRelease(OSTypeID(OSCollection));
390 oldEntry.value->taggedRelease(OSTypeID(OSCollection));
391 return;
392 }
393 }
394
395
396 // Returns true on success, false on an error condition.
397 bool OSDictionary::merge(const OSDictionary *srcDict)
398 {
399 const OSSymbol * sym;
400 OSCollectionIterator * iter;
401
402 if ( !OSDynamicCast(OSDictionary, srcDict) )
403 return false;
404
405 iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict));
406 if ( !iter )
407 return false;
408
409 while ( (sym = (const OSSymbol *)iter->getNextObject()) ) {
410 const OSMetaClassBase * obj;
411
412 obj = srcDict->getObject(sym);
413 if ( !setObject(sym, obj) ) {
414 iter->release();
415 return false;
416 }
417 }
418 iter->release();
419
420 return true;
421 }
422
423 OSObject *OSDictionary::getObject(const OSSymbol *aKey) const
424 {
425 unsigned int i;
426 bool exists;
427
428 if (!aKey)
429 return 0;
430
431 // if the key exists, return the object
432
433 if (fOptions & kSort) {
434 i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0]));
435 exists = (i < count) && (aKey == dictionary[i].key);
436 } else for (exists = false, i = 0; i < count; i++) {
437 if ((exists = (aKey == dictionary[i].key))) break;
438 }
439
440 if (exists) {
441 return (const_cast<OSObject *> ((const OSObject *)dictionary[i].value));
442 }
443
444 return 0;
445 }
446
447 // Wrapper macros
448 #define OBJECT_WRAP_1(cmd, k) \
449 { \
450 const OSSymbol *tmpKey = k; \
451 OSObject *retObj = cmd(tmpKey); \
452 \
453 tmpKey->release(); \
454 return retObj; \
455 }
456
457 #define OBJECT_WRAP_2(cmd, k, o) \
458 { \
459 const OSSymbol *tmpKey = k; \
460 bool ret = cmd(tmpKey, o); \
461 \
462 tmpKey->release(); \
463 return ret; \
464 }
465
466 #define OBJECT_WRAP_3(cmd, k) \
467 { \
468 const OSSymbol *tmpKey = k; \
469 cmd(tmpKey); \
470 tmpKey->release(); \
471 }
472
473
474 bool OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject)
475 OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject)
476 bool OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject)
477 OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject)
478
479 OSObject *OSDictionary::getObject(const OSString *aKey) const
480 OBJECT_WRAP_1(getObject, OSSymbol::withString(aKey))
481 OSObject *OSDictionary::getObject(const char *aKey) const
482 OBJECT_WRAP_1(getObject, OSSymbol::withCString(aKey))
483
484 void OSDictionary::removeObject(const OSString *aKey)
485 OBJECT_WRAP_3(removeObject, OSSymbol::withString(aKey))
486 void OSDictionary::removeObject(const char *aKey)
487 OBJECT_WRAP_3(removeObject, OSSymbol::withCString(aKey))
488
489 bool
490 OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const
491 {
492 OSCollectionIterator * iter;
493 unsigned int keysCount;
494 const OSMetaClassBase * obj1;
495 const OSMetaClassBase * obj2;
496 OSString * aKey;
497 bool ret;
498
499 if ( this == srcDict )
500 return true;
501
502 keysCount = keys->getCount();
503 if ( (count < keysCount) || (srcDict->getCount() < keysCount) )
504 return false;
505
506 iter = OSCollectionIterator::withCollection(keys);
507 if ( !iter )
508 return false;
509
510 ret = true;
511 while ( (aKey = OSDynamicCast(OSString, iter->getNextObject())) ) {
512 obj1 = getObject(aKey);
513 obj2 = srcDict->getObject(aKey);
514 if ( !obj1 || !obj2 ) {
515 ret = false;
516 break;
517 }
518
519 if ( !obj1->isEqualTo(obj2) ) {
520 ret = false;
521 break;
522 }
523 }
524 iter->release();
525
526 return ret;
527 }
528
529 bool OSDictionary::isEqualTo(const OSDictionary *srcDict) const
530 {
531 unsigned int i;
532 const OSMetaClassBase * obj;
533
534 if ( this == srcDict )
535 return true;
536
537 if ( count != srcDict->getCount() )
538 return false;
539
540 for ( i = 0; i < count; i++ ) {
541 obj = srcDict->getObject(dictionary[i].key);
542 if ( !obj )
543 return false;
544
545 if ( !dictionary[i].value->isEqualTo(obj) )
546 return false;
547 }
548
549 return true;
550 }
551
552 bool OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const
553 {
554 OSDictionary *dict;
555
556 dict = OSDynamicCast(OSDictionary, anObject);
557 if ( dict )
558 return isEqualTo(dict);
559 else
560 return false;
561 }
562
563 unsigned int OSDictionary::iteratorSize() const
564 {
565 return sizeof(unsigned int);
566 }
567
568 bool OSDictionary::initIterator(void *inIterator) const
569 {
570 unsigned int *iteratorP = (unsigned int *) inIterator;
571
572 *iteratorP = 0;
573 return true;
574 }
575
576 bool OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const
577 {
578 unsigned int *iteratorP = (unsigned int *) inIterator;
579 unsigned int index = (*iteratorP)++;
580
581 if (index < count)
582 *ret = (OSObject *) dictionary[index].key;
583 else
584 *ret = 0;
585
586 return (*ret != 0);
587 }
588
589 bool OSDictionary::serialize(OSSerialize *s) const
590 {
591 if (s->previouslySerialized(this)) return true;
592
593 if (!s->addXMLStartTag(this, "dict")) return false;
594
595 for (unsigned i = 0; i < count; i++) {
596 const OSSymbol *key = dictionary[i].key;
597
598 // due the nature of the XML syntax, this must be a symbol
599 if (!key->metaCast("OSSymbol")) {
600 return false;
601 }
602 if (!s->addString("<key>")) return false;
603 const char *c = key->getCStringNoCopy();
604 while (*c) {
605 if (*c == '<') {
606 if (!s->addString("&lt;")) return false;
607 } else if (*c == '>') {
608 if (!s->addString("&gt;")) return false;
609 } else if (*c == '&') {
610 if (!s->addString("&amp;")) return false;
611 } else {
612 if (!s->addChar(*c)) return false;
613 }
614 c++;
615 }
616 if (!s->addXMLEndTag("key")) return false;
617
618 if (!dictionary[i].value->serialize(s)) return false;
619 }
620
621 return s->addXMLEndTag("dict");
622 }
623
624 unsigned OSDictionary::setOptions(unsigned options, unsigned mask, void *)
625 {
626 unsigned old = super::setOptions(options, mask);
627 if ((old ^ options) & mask) {
628
629 // Value changed need to recurse over all of the child collections
630 for ( unsigned i = 0; i < count; i++ ) {
631 OSCollection *v = OSDynamicCast(OSCollection, dictionary[i].value);
632 if (v)
633 v->setOptions(options, mask);
634 }
635 }
636
637 return old;
638 }
639
640 OSCollection * OSDictionary::copyCollection(OSDictionary *cycleDict)
641 {
642 bool allocDict = !cycleDict;
643 OSCollection *ret = 0;
644 OSDictionary *newDict = 0;
645
646 if (allocDict) {
647 cycleDict = OSDictionary::withCapacity(16);
648 if (!cycleDict)
649 return 0;
650 }
651
652 do {
653 // Check for a cycle
654 ret = super::copyCollection(cycleDict);
655 if (ret)
656 continue;
657
658 newDict = OSDictionary::withDictionary(this);
659 if (!newDict)
660 continue;
661
662 // Insert object into cycle Dictionary
663 cycleDict->setObject((const OSSymbol *) this, newDict);
664
665 for (unsigned int i = 0; i < count; i++) {
666 const OSMetaClassBase *obj = dictionary[i].value;
667 OSCollection *coll = OSDynamicCast(OSCollection, EXT_CAST(obj));
668
669 if (coll) {
670 OSCollection *newColl = coll->copyCollection(cycleDict);
671 if (!newColl)
672 goto abortCopy;
673
674 newDict->dictionary[i].value = newColl;
675
676 coll->taggedRelease(OSTypeID(OSCollection));
677 newColl->taggedRetain(OSTypeID(OSCollection));
678 newColl->release();
679 };
680 }
681
682 ret = newDict;
683 newDict = 0;
684
685 } while (false);
686
687 abortCopy:
688 if (newDict)
689 newDict->release();
690
691 if (allocDict)
692 cycleDict->release();
693
694 return ret;
695 }
696