]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
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. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
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 | ||
91447636 A |
52 | #define EXT_CAST(obj) \ |
53 | reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj)) | |
54 | ||
0a7de745 A |
55 | extern "C" { |
56 | void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); | |
57 | } | |
58 | ||
59 | int | |
60 | OSDictionary::dictEntry::compare(const void *_e1, const void *_e2) | |
61 | { | |
62 | const OSDictionary::dictEntry *e1 = (const OSDictionary::dictEntry *)_e1; | |
63 | const OSDictionary::dictEntry *e2 = (const OSDictionary::dictEntry *)_e2; | |
64 | ||
65 | if ((uintptr_t)e1->key == (uintptr_t)e2->key) { | |
66 | return 0; | |
67 | } | |
68 | ||
69 | return (uintptr_t)e1->key > (uintptr_t)e2->key ? 1 : -1; | |
70 | } | |
71 | ||
72 | void | |
73 | OSDictionary::sortBySymbol(void) | |
1c79356b | 74 | { |
0a7de745 A |
75 | qsort(dictionary, count, sizeof(OSDictionary::dictEntry), |
76 | &OSDictionary::dictEntry::compare); | |
77 | } | |
78 | ||
79 | bool | |
80 | OSDictionary::initWithCapacity(unsigned int inCapacity) | |
81 | { | |
82 | if (!super::init()) { | |
83 | return false; | |
84 | } | |
1c79356b | 85 | |
0a7de745 A |
86 | if (inCapacity > (UINT_MAX / sizeof(dictEntry))) { |
87 | return false; | |
88 | } | |
1c79356b | 89 | |
0a7de745 | 90 | unsigned int size = inCapacity * sizeof(dictEntry); |
316670eb A |
91 | //fOptions |= kSort; |
92 | ||
0a7de745 A |
93 | dictionary = (dictEntry *) kalloc_container(size); |
94 | if (!dictionary) { | |
95 | return false; | |
96 | } | |
1c79356b | 97 | |
0a7de745 A |
98 | bzero(dictionary, size); |
99 | OSCONTAINER_ACCUMSIZE(size); | |
1c79356b | 100 | |
0a7de745 A |
101 | count = 0; |
102 | capacity = inCapacity; | |
103 | capacityIncrement = (inCapacity)? inCapacity : 16; | |
1c79356b | 104 | |
0a7de745 | 105 | return true; |
1c79356b A |
106 | } |
107 | ||
0a7de745 A |
108 | bool |
109 | OSDictionary::initWithObjects(const OSObject *objects[], | |
110 | const OSSymbol *keys[], | |
111 | unsigned int theCount, | |
112 | unsigned int theCapacity) | |
1c79356b | 113 | { |
0a7de745 A |
114 | unsigned int newCapacity = theCount; |
115 | ||
116 | if (!objects || !keys) { | |
117 | return false; | |
118 | } | |
1c79356b | 119 | |
0a7de745 A |
120 | if (theCapacity) { |
121 | if (theCount > theCapacity) { | |
122 | return false; | |
123 | } | |
1c79356b | 124 | |
0a7de745 A |
125 | newCapacity = theCapacity; |
126 | } | |
1c79356b | 127 | |
0a7de745 A |
128 | if (!initWithCapacity(newCapacity)) { |
129 | return false; | |
130 | } | |
1c79356b | 131 | |
0a7de745 A |
132 | for (unsigned int i = 0; i < theCount; i++) { |
133 | const OSMetaClassBase *newObject = *objects++; | |
1c79356b | 134 | |
0a7de745 A |
135 | if (!newObject || !keys[i] || !setObject(keys[i], newObject)) { |
136 | return false; | |
137 | } | |
138 | } | |
1c79356b | 139 | |
0a7de745 | 140 | return true; |
1c79356b A |
141 | } |
142 | ||
0a7de745 A |
143 | bool |
144 | OSDictionary::initWithObjects(const OSObject *objects[], | |
145 | const OSString *keys[], | |
146 | unsigned int theCount, | |
147 | unsigned int theCapacity) | |
1c79356b | 148 | { |
0a7de745 | 149 | unsigned int newCapacity = theCount; |
1c79356b | 150 | |
0a7de745 A |
151 | if (!objects || !keys) { |
152 | return false; | |
153 | } | |
1c79356b | 154 | |
0a7de745 A |
155 | if (theCapacity) { |
156 | if (theCount > theCapacity) { | |
157 | return false; | |
158 | } | |
1c79356b | 159 | |
0a7de745 A |
160 | newCapacity = theCapacity; |
161 | } | |
1c79356b | 162 | |
0a7de745 A |
163 | if (!initWithCapacity(newCapacity)) { |
164 | return false; | |
165 | } | |
1c79356b | 166 | |
0a7de745 A |
167 | for (unsigned int i = 0; i < theCount; i++) { |
168 | const OSSymbol *key = OSSymbol::withString(*keys++); | |
169 | const OSMetaClassBase *newObject = *objects++; | |
1c79356b | 170 | |
0a7de745 A |
171 | if (!key) { |
172 | return false; | |
173 | } | |
1c79356b | 174 | |
0a7de745 A |
175 | if (!newObject || !setObject(key, newObject)) { |
176 | key->release(); | |
177 | return false; | |
178 | } | |
1c79356b | 179 | |
0a7de745 A |
180 | key->release(); |
181 | } | |
1c79356b | 182 | |
0a7de745 | 183 | return true; |
1c79356b A |
184 | } |
185 | ||
0a7de745 A |
186 | bool |
187 | OSDictionary::initWithDictionary(const OSDictionary *dict, | |
188 | unsigned int theCapacity) | |
1c79356b | 189 | { |
0a7de745 | 190 | unsigned int newCapacity; |
1c79356b | 191 | |
0a7de745 A |
192 | if (!dict) { |
193 | return false; | |
194 | } | |
1c79356b | 195 | |
0a7de745 | 196 | newCapacity = dict->count; |
1c79356b | 197 | |
0a7de745 A |
198 | if (theCapacity) { |
199 | if (dict->count > theCapacity) { | |
200 | return false; | |
201 | } | |
1c79356b | 202 | |
0a7de745 A |
203 | newCapacity = theCapacity; |
204 | } | |
1c79356b | 205 | |
0a7de745 | 206 | if (!initWithCapacity(newCapacity)) { |
316670eb | 207 | return false; |
316670eb | 208 | } |
316670eb | 209 | |
0a7de745 A |
210 | count = dict->count; |
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)); | |
215 | } | |
1c79356b | 216 | |
0a7de745 A |
217 | if ((kSort & fOptions) && !(kSort & dict->fOptions)) { |
218 | sortBySymbol(); | |
219 | } | |
220 | ||
221 | return true; | |
1c79356b A |
222 | } |
223 | ||
0a7de745 A |
224 | OSDictionary * |
225 | OSDictionary::withCapacity(unsigned int capacity) | |
1c79356b | 226 | { |
0a7de745 | 227 | OSDictionary *me = new OSDictionary; |
1c79356b | 228 | |
0a7de745 A |
229 | if (me && !me->initWithCapacity(capacity)) { |
230 | me->release(); | |
231 | return 0; | |
232 | } | |
1c79356b | 233 | |
0a7de745 | 234 | return me; |
1c79356b A |
235 | } |
236 | ||
0a7de745 A |
237 | OSDictionary * |
238 | OSDictionary::withObjects(const OSObject *objects[], | |
239 | const OSSymbol *keys[], | |
240 | unsigned int count, | |
241 | unsigned int capacity) | |
1c79356b | 242 | { |
0a7de745 | 243 | OSDictionary *me = new OSDictionary; |
1c79356b | 244 | |
0a7de745 A |
245 | if (me && !me->initWithObjects(objects, keys, count, capacity)) { |
246 | me->release(); | |
247 | return 0; | |
248 | } | |
1c79356b | 249 | |
0a7de745 | 250 | return me; |
1c79356b A |
251 | } |
252 | ||
0a7de745 A |
253 | OSDictionary * |
254 | OSDictionary::withObjects(const OSObject *objects[], | |
255 | const OSString *keys[], | |
256 | unsigned int count, | |
257 | unsigned int capacity) | |
1c79356b | 258 | { |
0a7de745 | 259 | OSDictionary *me = new OSDictionary; |
1c79356b | 260 | |
0a7de745 A |
261 | if (me && !me->initWithObjects(objects, keys, count, capacity)) { |
262 | me->release(); | |
263 | return 0; | |
264 | } | |
1c79356b | 265 | |
0a7de745 | 266 | return me; |
1c79356b A |
267 | } |
268 | ||
0a7de745 A |
269 | OSDictionary * |
270 | OSDictionary::withDictionary(const OSDictionary *dict, | |
271 | unsigned int capacity) | |
1c79356b | 272 | { |
0a7de745 | 273 | OSDictionary *me = new OSDictionary; |
1c79356b | 274 | |
0a7de745 A |
275 | if (me && !me->initWithDictionary(dict, capacity)) { |
276 | me->release(); | |
277 | return 0; | |
278 | } | |
1c79356b | 279 | |
0a7de745 | 280 | return me; |
1c79356b A |
281 | } |
282 | ||
0a7de745 A |
283 | void |
284 | OSDictionary::free() | |
1c79356b | 285 | { |
0a7de745 A |
286 | (void) super::setOptions(0, kImmutable); |
287 | flushCollection(); | |
288 | if (dictionary) { | |
289 | kfree(dictionary, capacity * sizeof(dictEntry)); | |
290 | OSCONTAINER_ACCUMSIZE( -(capacity * sizeof(dictEntry))); | |
291 | } | |
1c79356b | 292 | |
0a7de745 | 293 | super::free(); |
1c79356b A |
294 | } |
295 | ||
0a7de745 A |
296 | unsigned int |
297 | OSDictionary::getCount() const | |
298 | { | |
299 | return count; | |
300 | } | |
301 | unsigned int | |
302 | OSDictionary::getCapacity() const | |
303 | { | |
304 | return capacity; | |
305 | } | |
1c79356b | 306 | |
0a7de745 A |
307 | unsigned int |
308 | OSDictionary::getCapacityIncrement() const | |
1c79356b | 309 | { |
0a7de745 | 310 | return capacityIncrement; |
1c79356b A |
311 | } |
312 | ||
0a7de745 A |
313 | unsigned int |
314 | OSDictionary::setCapacityIncrement(unsigned int increment) | |
1c79356b | 315 | { |
0a7de745 | 316 | capacityIncrement = (increment)? increment : 16; |
1c79356b | 317 | |
0a7de745 | 318 | return capacityIncrement; |
1c79356b A |
319 | } |
320 | ||
0a7de745 A |
321 | unsigned int |
322 | OSDictionary::ensureCapacity(unsigned int newCapacity) | |
1c79356b | 323 | { |
0a7de745 A |
324 | dictEntry *newDict; |
325 | unsigned int finalCapacity; | |
326 | vm_size_t oldSize, newSize; | |
1c79356b | 327 | |
0a7de745 A |
328 | if (newCapacity <= capacity) { |
329 | return capacity; | |
330 | } | |
331 | ||
332 | // round up | |
333 | finalCapacity = (((newCapacity - 1) / capacityIncrement) + 1) | |
334 | * capacityIncrement; | |
1c79356b | 335 | |
0a7de745 A |
336 | // integer overflow check |
337 | if (finalCapacity < newCapacity || (finalCapacity > (UINT_MAX / sizeof(dictEntry)))) { | |
338 | return capacity; | |
339 | } | |
fe8ab488 | 340 | |
0a7de745 | 341 | newSize = sizeof(dictEntry) * finalCapacity; |
1c79356b | 342 | |
0a7de745 A |
343 | newDict = (dictEntry *) kallocp_container(&newSize); |
344 | if (newDict) { | |
345 | // use all of the actual allocation size | |
346 | finalCapacity = newSize / sizeof(dictEntry); | |
39037602 | 347 | |
0a7de745 | 348 | oldSize = sizeof(dictEntry) * capacity; |
1c79356b | 349 | |
0a7de745 A |
350 | bcopy(dictionary, newDict, oldSize); |
351 | bzero(&newDict[capacity], newSize - oldSize); | |
1c79356b | 352 | |
0a7de745 A |
353 | OSCONTAINER_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize)); |
354 | kfree(dictionary, oldSize); | |
1c79356b | 355 | |
0a7de745 A |
356 | dictionary = newDict; |
357 | capacity = finalCapacity; | |
358 | } | |
1c79356b | 359 | |
0a7de745 | 360 | return capacity; |
1c79356b A |
361 | } |
362 | ||
0a7de745 A |
363 | void |
364 | OSDictionary::flushCollection() | |
1c79356b | 365 | { |
0a7de745 | 366 | haveUpdated(); |
1c79356b | 367 | |
0a7de745 A |
368 | for (unsigned int i = 0; i < count; i++) { |
369 | dictionary[i].key->taggedRelease(OSTypeID(OSCollection)); | |
370 | dictionary[i].value->taggedRelease(OSTypeID(OSCollection)); | |
371 | } | |
372 | count = 0; | |
1c79356b A |
373 | } |
374 | ||
0a7de745 A |
375 | bool |
376 | OSDictionary:: | |
ecc0ceb4 | 377 | setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject, bool onlyAdd) |
1c79356b | 378 | { |
0a7de745 A |
379 | unsigned int i; |
380 | bool exists; | |
316670eb | 381 | |
0a7de745 A |
382 | if (!anObject || !aKey) { |
383 | return false; | |
384 | } | |
1c79356b | 385 | |
0a7de745 A |
386 | // if the key exists, replace the object |
387 | ||
388 | if (fOptions & kSort) { | |
389 | i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0])); | |
390 | exists = (i < count) && (aKey == dictionary[i].key); | |
391 | } else { | |
392 | for (exists = false, i = 0; i < count; i++) { | |
393 | if ((exists = (aKey == dictionary[i].key))) { | |
394 | break; | |
395 | } | |
396 | } | |
397 | } | |
91447636 | 398 | |
0a7de745 A |
399 | if (exists) { |
400 | if (onlyAdd) { | |
401 | return false; | |
402 | } | |
1c79356b | 403 | |
0a7de745 | 404 | const OSMetaClassBase *oldObject = dictionary[i].value; |
ecc0ceb4 | 405 | |
0a7de745 | 406 | haveUpdated(); |
ecc0ceb4 | 407 | |
0a7de745 A |
408 | anObject->taggedRetain(OSTypeID(OSCollection)); |
409 | dictionary[i].value = anObject; | |
1c79356b | 410 | |
0a7de745 A |
411 | oldObject->taggedRelease(OSTypeID(OSCollection)); |
412 | return true; | |
413 | } | |
1c79356b | 414 | |
0a7de745 A |
415 | // add new key, possibly extending our capacity |
416 | if (count >= capacity && count >= ensureCapacity(count + 1)) { | |
417 | return false; | |
418 | } | |
91447636 | 419 | |
0a7de745 A |
420 | haveUpdated(); |
421 | ||
422 | bcopy(&dictionary[i], &dictionary[i + 1], (count - i) * sizeof(dictionary[0])); | |
316670eb | 423 | |
0a7de745 A |
424 | aKey->taggedRetain(OSTypeID(OSCollection)); |
425 | anObject->taggedRetain(OSTypeID(OSCollection)); | |
426 | dictionary[i].key = aKey; | |
427 | dictionary[i].value = anObject; | |
428 | count++; | |
1c79356b | 429 | |
0a7de745 | 430 | return true; |
1c79356b A |
431 | } |
432 | ||
0a7de745 A |
433 | bool |
434 | OSDictionary:: | |
ecc0ceb4 A |
435 | setObject(const OSSymbol *aKey, const OSMetaClassBase *anObject) |
436 | { | |
0a7de745 | 437 | return setObject(aKey, anObject, false); |
ecc0ceb4 A |
438 | } |
439 | ||
0a7de745 A |
440 | void |
441 | OSDictionary::removeObject(const OSSymbol *aKey) | |
1c79356b | 442 | { |
0a7de745 A |
443 | unsigned int i; |
444 | bool exists; | |
316670eb | 445 | |
0a7de745 A |
446 | if (!aKey) { |
447 | return; | |
448 | } | |
1c79356b | 449 | |
0a7de745 A |
450 | // if the key exists, remove the object |
451 | ||
452 | if (fOptions & kSort) { | |
453 | i = OSSymbol::bsearch(aKey, &dictionary[0], count, sizeof(dictionary[0])); | |
454 | exists = (i < count) && (aKey == dictionary[i].key); | |
455 | } else { | |
456 | for (exists = false, i = 0; i < count; i++) { | |
457 | if ((exists = (aKey == dictionary[i].key))) { | |
458 | break; | |
459 | } | |
460 | } | |
461 | } | |
1c79356b | 462 | |
0a7de745 A |
463 | if (exists) { |
464 | dictEntry oldEntry = dictionary[i]; | |
1c79356b | 465 | |
0a7de745 | 466 | haveUpdated(); |
1c79356b | 467 | |
0a7de745 A |
468 | count--; |
469 | bcopy(&dictionary[i + 1], &dictionary[i], (count - i) * sizeof(dictionary[0])); | |
316670eb | 470 | |
0a7de745 A |
471 | oldEntry.key->taggedRelease(OSTypeID(OSCollection)); |
472 | oldEntry.value->taggedRelease(OSTypeID(OSCollection)); | |
473 | return; | |
474 | } | |
1c79356b A |
475 | } |
476 | ||
477 | ||
478 | // Returns true on success, false on an error condition. | |
0a7de745 A |
479 | bool |
480 | OSDictionary::merge(const OSDictionary *srcDict) | |
1c79356b | 481 | { |
0a7de745 A |
482 | const OSSymbol * sym; |
483 | OSCollectionIterator * iter; | |
1c79356b | 484 | |
0a7de745 A |
485 | if (!OSDynamicCast(OSDictionary, srcDict)) { |
486 | return false; | |
487 | } | |
9bccf70c | 488 | |
0a7de745 A |
489 | iter = OSCollectionIterator::withCollection(const_cast<OSDictionary *>(srcDict)); |
490 | if (!iter) { | |
491 | return false; | |
492 | } | |
1c79356b | 493 | |
0a7de745 A |
494 | while ((sym = (const OSSymbol *)iter->getNextObject())) { |
495 | const OSMetaClassBase * obj; | |
1c79356b | 496 | |
0a7de745 A |
497 | obj = srcDict->getObject(sym); |
498 | if (!setObject(sym, obj)) { | |
499 | iter->release(); | |
500 | return false; | |
501 | } | |
502 | } | |
503 | iter->release(); | |
1c79356b | 504 | |
0a7de745 | 505 | return true; |
1c79356b A |
506 | } |
507 | ||
0a7de745 A |
508 | OSObject * |
509 | OSDictionary::getObject(const OSSymbol *aKey) const | |
1c79356b | 510 | { |
0a7de745 | 511 | unsigned int i, l = 0, r = count; |
316670eb | 512 | |
0a7de745 A |
513 | if (!aKey) { |
514 | return 0; | |
515 | } | |
316670eb | 516 | |
0a7de745 A |
517 | // if the key exists, return the object |
518 | // | |
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 | |
522 | // | |
523 | // If we have less than 4 objects, scanning is faster. | |
524 | if (count > 4 && (fOptions & kSort)) { | |
525 | while (l < r) { | |
526 | i = (l + r) / 2; | |
527 | if (aKey == dictionary[i].key) { | |
528 | return const_cast<OSObject *> ((const OSObject *)dictionary[i].value); | |
529 | } | |
530 | ||
531 | if ((uintptr_t)aKey < (uintptr_t)dictionary[i].key) { | |
532 | r = i; | |
533 | } else { | |
534 | l = i + 1; | |
535 | } | |
536 | } | |
537 | } else { | |
538 | for (i = l; i < r; i++) { | |
539 | if (aKey == dictionary[i].key) { | |
540 | return const_cast<OSObject *> ((const OSObject *)dictionary[i].value); | |
541 | } | |
542 | } | |
543 | } | |
1c79356b | 544 | |
0a7de745 | 545 | return NULL; |
1c79356b A |
546 | } |
547 | ||
548 | // Wrapper macros | |
0a7de745 A |
549 | #define OBJECT_WRAP_1(cmd, k) \ |
550 | { \ | |
551 | const OSSymbol *tmpKey = k; \ | |
552 | OSObject *retObj = NULL; \ | |
553 | if (tmpKey) { \ | |
554 | retObj = cmd(tmpKey); \ | |
555 | tmpKey->release(); \ | |
556 | } \ | |
557 | return retObj; \ | |
1c79356b A |
558 | } |
559 | ||
0a7de745 A |
560 | #define OBJECT_WRAP_2(cmd, k, o) \ |
561 | { \ | |
562 | const OSSymbol *tmpKey = k; \ | |
563 | bool ret = cmd(tmpKey, o); \ | |
564 | \ | |
565 | tmpKey->release(); \ | |
566 | return ret; \ | |
1c79356b A |
567 | } |
568 | ||
0a7de745 A |
569 | #define OBJECT_WRAP_3(cmd, k) \ |
570 | { \ | |
571 | const OSSymbol *tmpKey = k; \ | |
572 | if (tmpKey) { \ | |
573 | cmd(tmpKey); \ | |
574 | tmpKey->release(); \ | |
575 | } \ | |
1c79356b A |
576 | } |
577 | ||
578 | ||
0a7de745 A |
579 | bool |
580 | OSDictionary::setObject(const OSString *aKey, const OSMetaClassBase *anObject) | |
581 | OBJECT_WRAP_2(setObject, OSSymbol::withString(aKey), anObject) | |
582 | bool | |
583 | OSDictionary::setObject(const char *aKey, const OSMetaClassBase *anObject) | |
584 | OBJECT_WRAP_2(setObject, OSSymbol::withCString(aKey), anObject) | |
1c79356b | 585 | |
0a7de745 A |
586 | OSObject *OSDictionary::getObject(const OSString * aKey) const |
587 | OBJECT_WRAP_1(getObject, OSSymbol::existingSymbolForString(aKey)) | |
1c79356b | 588 | OSObject *OSDictionary::getObject(const char *aKey) const |
0a7de745 | 589 | OBJECT_WRAP_1(getObject, OSSymbol::existingSymbolForCString(aKey)) |
1c79356b | 590 | |
0a7de745 A |
591 | void |
592 | OSDictionary::removeObject(const OSString *aKey) | |
593 | OBJECT_WRAP_3(removeObject, OSSymbol::existingSymbolForString(aKey)) | |
594 | void | |
595 | OSDictionary::removeObject(const char *aKey) | |
596 | OBJECT_WRAP_3(removeObject, OSSymbol::existingSymbolForCString(aKey)) | |
1c79356b A |
597 | |
598 | bool | |
9bccf70c | 599 | OSDictionary::isEqualTo(const OSDictionary *srcDict, const OSCollection *keys) const |
1c79356b | 600 | { |
0a7de745 A |
601 | OSCollectionIterator * iter; |
602 | unsigned int keysCount; | |
603 | const OSMetaClassBase * obj1; | |
604 | const OSMetaClassBase * obj2; | |
605 | OSString * aKey; | |
606 | bool ret; | |
607 | ||
608 | if (this == srcDict) { | |
609 | return true; | |
610 | } | |
1c79356b | 611 | |
0a7de745 A |
612 | keysCount = keys->getCount(); |
613 | if ((count < keysCount) || (srcDict->getCount() < keysCount)) { | |
614 | return false; | |
615 | } | |
1c79356b | 616 | |
0a7de745 A |
617 | iter = OSCollectionIterator::withCollection(keys); |
618 | if (!iter) { | |
619 | return false; | |
620 | } | |
1c79356b | 621 | |
0a7de745 A |
622 | ret = true; |
623 | while ((aKey = OSDynamicCast(OSString, iter->getNextObject()))) { | |
624 | obj1 = getObject(aKey); | |
625 | obj2 = srcDict->getObject(aKey); | |
626 | if (!obj1 || !obj2) { | |
627 | ret = false; | |
628 | break; | |
629 | } | |
630 | ||
631 | if (!obj1->isEqualTo(obj2)) { | |
632 | ret = false; | |
633 | break; | |
634 | } | |
635 | } | |
636 | iter->release(); | |
1c79356b | 637 | |
0a7de745 | 638 | return ret; |
1c79356b A |
639 | } |
640 | ||
0a7de745 A |
641 | bool |
642 | OSDictionary::isEqualTo(const OSDictionary *srcDict) const | |
1c79356b | 643 | { |
0a7de745 A |
644 | unsigned int i; |
645 | const OSMetaClassBase * obj; | |
1c79356b | 646 | |
0a7de745 A |
647 | if (this == srcDict) { |
648 | return true; | |
649 | } | |
1c79356b | 650 | |
0a7de745 A |
651 | if (count != srcDict->getCount()) { |
652 | return false; | |
653 | } | |
1c79356b | 654 | |
0a7de745 A |
655 | for (i = 0; i < count; i++) { |
656 | obj = srcDict->getObject(dictionary[i].key); | |
657 | if (!obj) { | |
658 | return false; | |
659 | } | |
660 | ||
661 | if (!dictionary[i].value->isEqualTo(obj)) { | |
662 | return false; | |
663 | } | |
664 | } | |
665 | ||
666 | return true; | |
1c79356b A |
667 | } |
668 | ||
0a7de745 A |
669 | bool |
670 | OSDictionary::isEqualTo(const OSMetaClassBase *anObject) const | |
1c79356b | 671 | { |
0a7de745 | 672 | OSDictionary *dict; |
1c79356b | 673 | |
0a7de745 A |
674 | dict = OSDynamicCast(OSDictionary, anObject); |
675 | if (dict) { | |
676 | return isEqualTo(dict); | |
677 | } else { | |
678 | return false; | |
679 | } | |
1c79356b A |
680 | } |
681 | ||
0a7de745 A |
682 | unsigned int |
683 | OSDictionary::iteratorSize() const | |
1c79356b | 684 | { |
0a7de745 | 685 | return sizeof(unsigned int); |
1c79356b A |
686 | } |
687 | ||
0a7de745 A |
688 | bool |
689 | OSDictionary::initIterator(void *inIterator) const | |
1c79356b | 690 | { |
0a7de745 | 691 | unsigned int *iteratorP = (unsigned int *) inIterator; |
1c79356b | 692 | |
0a7de745 A |
693 | *iteratorP = 0; |
694 | return true; | |
1c79356b A |
695 | } |
696 | ||
0a7de745 A |
697 | bool |
698 | OSDictionary::getNextObjectForIterator(void *inIterator, OSObject **ret) const | |
1c79356b | 699 | { |
0a7de745 A |
700 | unsigned int *iteratorP = (unsigned int *) inIterator; |
701 | unsigned int index = (*iteratorP)++; | |
1c79356b | 702 | |
0a7de745 A |
703 | if (index < count) { |
704 | *ret = (OSObject *) dictionary[index].key; | |
705 | } else { | |
706 | *ret = 0; | |
707 | } | |
1c79356b | 708 | |
0a7de745 | 709 | return *ret != 0; |
1c79356b A |
710 | } |
711 | ||
0a7de745 A |
712 | bool |
713 | OSDictionary::serialize(OSSerialize *s) const | |
1c79356b | 714 | { |
0a7de745 A |
715 | if (s->previouslySerialized(this)) { |
716 | return true; | |
717 | } | |
1c79356b | 718 | |
0a7de745 A |
719 | if (!s->addXMLStartTag(this, "dict")) { |
720 | return false; | |
721 | } | |
1c79356b | 722 | |
0a7de745 A |
723 | for (unsigned i = 0; i < count; i++) { |
724 | const OSSymbol *key = dictionary[i].key; | |
725 | ||
726 | // due the nature of the XML syntax, this must be a symbol | |
727 | if (!key->metaCast("OSSymbol")) { | |
728 | return false; | |
729 | } | |
730 | if (!s->addString("<key>")) { | |
731 | return false; | |
732 | } | |
733 | const char *c = key->getCStringNoCopy(); | |
734 | while (*c) { | |
735 | if (*c == '<') { | |
736 | if (!s->addString("<")) { | |
737 | return false; | |
738 | } | |
739 | } else if (*c == '>') { | |
740 | if (!s->addString(">")) { | |
741 | return false; | |
742 | } | |
743 | } else if (*c == '&') { | |
744 | if (!s->addString("&")) { | |
745 | return false; | |
746 | } | |
747 | } else { | |
748 | if (!s->addChar(*c)) { | |
749 | return false; | |
750 | } | |
751 | } | |
752 | c++; | |
753 | } | |
754 | if (!s->addXMLEndTag("key")) { | |
755 | return false; | |
756 | } | |
757 | ||
758 | if (!dictionary[i].value->serialize(s)) { | |
759 | return false; | |
760 | } | |
761 | } | |
1c79356b | 762 | |
0a7de745 | 763 | return s->addXMLEndTag("dict"); |
1c79356b | 764 | } |
91447636 | 765 | |
0a7de745 A |
766 | unsigned |
767 | OSDictionary::setOptions(unsigned options, unsigned mask, void *) | |
91447636 | 768 | { |
0a7de745 A |
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); | |
774 | if (v) { | |
775 | v->setOptions(options, mask); | |
776 | } | |
777 | } | |
778 | } | |
91447636 | 779 | |
0a7de745 A |
780 | if (!(old & kSort) && (fOptions & kSort)) { |
781 | sortBySymbol(); | |
91447636 | 782 | } |
91447636 | 783 | |
0a7de745 | 784 | return old; |
91447636 A |
785 | } |
786 | ||
0a7de745 A |
787 | OSCollection * |
788 | OSDictionary::copyCollection(OSDictionary *cycleDict) | |
91447636 | 789 | { |
0a7de745 A |
790 | bool allocDict = !cycleDict; |
791 | OSCollection *ret = 0; | |
792 | OSDictionary *newDict = 0; | |
793 | ||
794 | if (allocDict) { | |
795 | cycleDict = OSDictionary::withCapacity(16); | |
796 | if (!cycleDict) { | |
797 | return 0; | |
798 | } | |
799 | } | |
91447636 | 800 | |
0a7de745 A |
801 | do { |
802 | // Check for a cycle | |
803 | ret = super::copyCollection(cycleDict); | |
804 | if (ret) { | |
805 | continue; | |
806 | } | |
91447636 | 807 | |
0a7de745 A |
808 | newDict = OSDictionary::withDictionary(this); |
809 | if (!newDict) { | |
810 | continue; | |
811 | } | |
91447636 | 812 | |
0a7de745 A |
813 | // Insert object into cycle Dictionary |
814 | cycleDict->setObject((const OSSymbol *) this, newDict); | |
91447636 | 815 | |
0a7de745 A |
816 | for (unsigned int i = 0; i < count; i++) { |
817 | const OSMetaClassBase *obj = dictionary[i].value; | |
818 | OSCollection *coll = OSDynamicCast(OSCollection, EXT_CAST(obj)); | |
91447636 | 819 | |
0a7de745 A |
820 | if (coll) { |
821 | OSCollection *newColl = coll->copyCollection(cycleDict); | |
822 | if (!newColl) { | |
823 | goto abortCopy; | |
824 | } | |
91447636 | 825 | |
0a7de745 | 826 | newDict->dictionary[i].value = newColl; |
91447636 | 827 | |
0a7de745 A |
828 | coll->taggedRelease(OSTypeID(OSCollection)); |
829 | newColl->taggedRetain(OSTypeID(OSCollection)); | |
830 | newColl->release(); | |
831 | } | |
832 | ; | |
833 | } | |
91447636 | 834 | |
0a7de745 A |
835 | ret = newDict; |
836 | newDict = 0; | |
837 | } while (false); | |
91447636 A |
838 | |
839 | abortCopy: | |
0a7de745 A |
840 | if (newDict) { |
841 | newDict->release(); | |
842 | } | |
91447636 | 843 | |
0a7de745 A |
844 | if (allocDict) { |
845 | cycleDict->release(); | |
846 | } | |
91447636 | 847 | |
0a7de745 | 848 | return ret; |
91447636 A |
849 | } |
850 | ||
0a7de745 A |
851 | OSArray * |
852 | OSDictionary::copyKeys(void) | |
39037602 | 853 | { |
0a7de745 | 854 | OSArray * array; |
39037602 A |
855 | |
856 | array = OSArray::withCapacity(count); | |
0a7de745 A |
857 | if (!array) { |
858 | return 0; | |
859 | } | |
39037602 | 860 | |
0a7de745 A |
861 | for (unsigned int i = 0; i < count; i++) { |
862 | if (!array->setObject(i, dictionary[i].key)) { | |
863 | array->release(); | |
864 | array = 0; | |
865 | break; | |
866 | } | |
39037602 | 867 | } |
0a7de745 | 868 | return array; |
39037602 | 869 | } |
d9a64523 | 870 | |
0a7de745 A |
871 | bool |
872 | OSDictionary::iterateObjects(void * refcon, bool (*callback)(void * refcon, const OSSymbol * key, OSObject * object)) | |
d9a64523 | 873 | { |
0a7de745 A |
874 | unsigned int initialUpdateStamp; |
875 | bool done; | |
d9a64523 | 876 | |
0a7de745 A |
877 | initialUpdateStamp = updateStamp; |
878 | done = false; | |
879 | for (unsigned int i = 0; i < count; i++) { | |
880 | done = callback(refcon, dictionary[i].key, EXT_CAST(dictionary[i].value)); | |
881 | if (done) { | |
882 | break; | |
883 | } | |
884 | if (initialUpdateStamp != updateStamp) { | |
885 | break; | |
886 | } | |
887 | } | |
d9a64523 | 888 | |
0a7de745 | 889 | return initialUpdateStamp == updateStamp; |
d9a64523 A |
890 | } |
891 | ||
0a7de745 A |
892 | static bool |
893 | OSDictionaryIterateObjectsBlock(void * refcon, const OSSymbol * key, OSObject * object) | |
d9a64523 | 894 | { |
0a7de745 A |
895 | bool (^block)(const OSSymbol * key, OSObject * object) = (typeof(block))refcon; |
896 | return block(key, object); | |
d9a64523 A |
897 | } |
898 | ||
0a7de745 A |
899 | bool |
900 | OSDictionary::iterateObjects(bool (^block)(const OSSymbol * key, OSObject * object)) | |
d9a64523 | 901 | { |
0a7de745 | 902 | return iterateObjects((void *)block, &OSDictionaryIterateObjectsBlock); |
d9a64523 | 903 | } |