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 /* IOArray.m created by rsulack on Fri 12-Sep-1997 */ 29 /* IOArray.cpp converted to C++ by gvdl on Fri 1998-10-30 */ 30 31 32 #include <libkern/c++/OSArray.h> 33 #include <libkern/c++/OSDictionary.h> 34 #include <libkern/c++/OSSerialize.h> 35 #include <libkern/c++/OSLib.h> 36 37 #define super OSCollection 38 39 OSDefineMetaClassAndStructors(OSArray, OSCollection) 40 OSMetaClassDefineReservedUnused(OSArray, 0); 41 OSMetaClassDefineReservedUnused(OSArray, 1); 42 OSMetaClassDefineReservedUnused(OSArray, 2); 43 OSMetaClassDefineReservedUnused(OSArray, 3); 44 OSMetaClassDefineReservedUnused(OSArray, 4); 45 OSMetaClassDefineReservedUnused(OSArray, 5); 46 OSMetaClassDefineReservedUnused(OSArray, 6); 47 OSMetaClassDefineReservedUnused(OSArray, 7); 48 49 #if OSALLOCDEBUG 50 extern "C" { 51 extern int debug_container_malloc_size; 52 }; 53 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) 54 #else 55 #define ACCUMSIZE(s) 56 #endif 57 58 #define EXT_CAST(obj) \ 59 reinterpret_cast<OSObject *>(const_cast<OSMetaClassBase *>(obj)) 60 61 bool OSArray::initWithCapacity(unsigned int inCapacity) 62 { 63 int size; 64 65 if (!super::init()) 66 return false; 67 68 size = sizeof(const OSMetaClassBase *) * inCapacity; 69 array = (const OSMetaClassBase **) kalloc(size); 70 if (!array) 71 return false; 72 73 count = 0; 74 capacity = inCapacity; 75 capacityIncrement = (inCapacity)? inCapacity : 16; 76 77 bzero(array, size); 78 ACCUMSIZE(size); 79 80 return true; 81 } 82 83 bool OSArray::initWithObjects(const OSObject *objects[], 84 unsigned int theCount, 85 unsigned int theCapacity) 86 { 87 unsigned int initCapacity; 88 89 if (!theCapacity) 90 initCapacity = theCount; 91 else if (theCount > theCapacity) 92 return false; 93 else 94 initCapacity = theCapacity; 95 96 if (!objects || !initWithCapacity(initCapacity)) 97 return false; 98 99 for ( unsigned int i = 0; i < theCount; i++ ) { 100 const OSMetaClassBase *newObject = *objects++; 101 102 if (!newObject) 103 return false; 104 105 array[count++] = newObject; 106 newObject->taggedRetain(OSTypeID(OSCollection)); 107 } 108 109 return true; 110 } 111 112 bool OSArray::initWithArray(const OSArray *anArray, 113 unsigned int theCapacity) 114 { 115 if ( !anArray ) 116 return false; 117 118 return initWithObjects((const OSObject **) anArray->array, 119 anArray->count, theCapacity); 120 } 121 122 OSArray *OSArray::withCapacity(unsigned int capacity) 123 { 124 OSArray *me = new OSArray; 125 126 if (me && !me->initWithCapacity(capacity)) { 127 me->release(); 128 return 0; 129 } 130 131 return me; 132 } 133 134 OSArray *OSArray::withObjects(const OSObject *objects[], 135 unsigned int count, 136 unsigned int capacity) 137 { 138 OSArray *me = new OSArray; 139 140 if (me && !me->initWithObjects(objects, count, capacity)) { 141 me->release(); 142 return 0; 143 } 144 145 return me; 146 } 147 148 OSArray *OSArray::withArray(const OSArray *array, 149 unsigned int capacity) 150 { 151 OSArray *me = new OSArray; 152 153 if (me && !me->initWithArray(array, capacity)) { 154 me->release(); 155 return 0; 156 } 157 158 return me; 159 } 160 161 void OSArray::free() 162 { 163 // Clear immutability - assumes the container is doing the right thing 164 (void) super::setOptions(0, kImmutable); 165 166 flushCollection(); 167 168 if (array) { 169 kfree(array, sizeof(const OSMetaClassBase *) * capacity); 170 ACCUMSIZE( -(sizeof(const OSMetaClassBase *) * capacity) ); 171 } 172 173 super::free(); 174 } 175 176 177 unsigned int OSArray::getCount() const { return count; } 178 unsigned int OSArray::getCapacity() const { return capacity; } 179 unsigned int OSArray::getCapacityIncrement() const { return capacityIncrement; } 180 unsigned int OSArray::setCapacityIncrement(unsigned int increment) 181 { 182 capacityIncrement = (increment)? increment : 16; 183 184 return capacityIncrement; 185 } 186 187 unsigned int OSArray::ensureCapacity(unsigned int newCapacity) 188 { 189 const OSMetaClassBase **newArray; 190 int oldSize, newSize; 191 192 if (newCapacity <= capacity) 193 return capacity; 194 195 // round up 196 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1) 197 * capacityIncrement; 198 newSize = sizeof(const OSMetaClassBase *) * newCapacity; 199 200 newArray = (const OSMetaClassBase **) kalloc(newSize); 201 if (newArray) { 202 oldSize = sizeof(const OSMetaClassBase *) * capacity; 203 204 ACCUMSIZE(newSize - oldSize); 205 206 bcopy(array, newArray, oldSize); 207 bzero(&newArray[capacity], newSize - oldSize); 208 kfree(array, oldSize); 209 array = newArray; 210 capacity = newCapacity; 211 } 212 213 return capacity; 214 } 215 216 void OSArray::flushCollection() 217 { 218 unsigned int i; 219 220 haveUpdated(); 221 for (i = 0; i < count; i++) 222 array[i]->taggedRelease(OSTypeID(OSCollection)); 223 count = 0; 224 } 225 226 bool OSArray::setObject(const OSMetaClassBase *anObject) 227 { 228 return setObject(count, anObject); 229 } 230 231 bool OSArray::setObject(unsigned int index, const OSMetaClassBase *anObject) 232 { 233 unsigned int i; 234 unsigned int newCount = count + 1; 235 236 if ((index > count) || !anObject) 237 return false; 238 239 // do we need more space? 240 if (newCount > capacity && newCount > ensureCapacity(newCount)) 241 return false; 242 243 haveUpdated(); 244 if (index != count) { 245 for (i = count; i > index; i--) 246 array[i] = array[i-1]; 247 } 248 array[index] = anObject; 249 anObject->taggedRetain(OSTypeID(OSCollection)); 250 count++; 251 252 return true; 253 } 254 255 bool OSArray::merge(const OSArray * otherArray) 256 { 257 unsigned int otherCount = otherArray->getCount(); 258 unsigned int newCount = count + otherCount; 259 260 if (!otherCount) 261 return true; 262 263 // do we need more space? 264 if (newCount > capacity && newCount > ensureCapacity(newCount)) 265 return false; 266 267 haveUpdated(); 268 for (unsigned int i = 0; i < otherCount; i++) { 269 const OSMetaClassBase *newObject = otherArray->getObject(i); 270 271 array[count++] = newObject; 272 newObject->taggedRetain(OSTypeID(OSCollection)); 273 } 274 275 return true; 276 } 277 278 void OSArray:: 279 replaceObject(unsigned int index, const OSMetaClassBase *anObject) 280 { 281 const OSMetaClassBase *oldObject; 282 283 if ((index >= count) || !anObject) 284 return; 285 286 haveUpdated(); 287 oldObject = array[index]; 288 array[index] = anObject; 289 anObject->taggedRetain(OSTypeID(OSCollection)); 290 291 oldObject->taggedRelease(OSTypeID(OSCollection)); 292 } 293 294 void OSArray::removeObject(unsigned int index) 295 { 296 unsigned int i; 297 const OSMetaClassBase *oldObject; 298 299 if (index >= count) 300 return; 301 302 haveUpdated(); 303 oldObject = array[index]; 304 305 count--; 306 for (i = index; i < count; i++) 307 array[i] = array[i+1]; 308 309 oldObject->taggedRelease(OSTypeID(OSCollection)); 310 } 311 312 bool OSArray::isEqualTo(const OSArray *anArray) const 313 { 314 unsigned int i; 315 316 if ( this == anArray ) 317 return true; 318 319 if ( count != anArray->getCount() ) 320 return false; 321 322 for ( i = 0; i < count; i++ ) { 323 if ( !array[i]->isEqualTo(anArray->getObject(i)) ) 324 return false; 325 } 326 327 return true; 328 } 329 330 bool OSArray::isEqualTo(const OSMetaClassBase *anObject) const 331 { 332 OSArray *otherArray; 333 334 otherArray = OSDynamicCast(OSArray, anObject); 335 if ( otherArray ) 336 return isEqualTo(otherArray); 337 else 338 return false; 339 } 340 341 OSObject *OSArray::getObject(unsigned int index) const 342 { 343 if (index >= count) 344 return 0; 345 else 346 return (OSObject *) (const_cast<OSMetaClassBase *>(array[index])); 347 } 348 349 OSObject *OSArray::getLastObject() const 350 { 351 if (count == 0) 352 return 0; 353 else 354 return ( OSObject *) (const_cast<OSMetaClassBase *>(array[count - 1])); 355 } 356 357 unsigned int OSArray::getNextIndexOfObject(const OSMetaClassBase * anObject, 358 unsigned int index) const 359 { 360 while ((index < count) && (array[index] != anObject)) 361 index++; 362 if (index >= count) 363 index = (unsigned int)-1; 364 return index; 365 } 366 367 unsigned int OSArray::iteratorSize() const 368 { 369 return sizeof(unsigned int); 370 } 371 372 bool OSArray::initIterator(void *inIterator) const 373 { 374 unsigned int *iteratorP = (unsigned int *) inIterator; 375 376 *iteratorP = 0; 377 return true; 378 } 379 380 bool OSArray::getNextObjectForIterator(void *inIterator, OSObject **ret) const 381 { 382 unsigned int *iteratorP = (unsigned int *) inIterator; 383 unsigned int index = (*iteratorP)++; 384 385 if (index < count) { 386 *ret = (OSObject *)(const_cast<OSMetaClassBase *> (array[index])); 387 return true; 388 } 389 else { 390 *ret = 0; 391 return false; 392 } 393 } 394 395 bool OSArray::serialize(OSSerialize *s) const 396 { 397 if (s->previouslySerialized(this)) return true; 398 399 if (!s->addXMLStartTag(this, "array")) return false; 400 401 for (unsigned i = 0; i < count; i++) { 402 if (!array[i]->serialize(s)) return false; 403 } 404 405 return s->addXMLEndTag("array"); 406 } 407 408 unsigned OSArray::setOptions(unsigned options, unsigned mask, void *) 409 { 410 unsigned old = super::setOptions(options, mask); 411 if ((old ^ options) & mask) { 412 413 // Value changed need to recurse over all of the child collections 414 for ( unsigned i = 0; i < count; i++ ) { 415 OSCollection *coll = OSDynamicCast(OSCollection, array[i]); 416 if (coll) 417 coll->setOptions(options, mask); 418 } 419 } 420 421 return old; 422 } 423 424 OSCollection * OSArray::copyCollection(OSDictionary *cycleDict) 425 { 426 bool allocDict = !cycleDict; 427 OSCollection *ret = 0; 428 OSArray *newArray = 0; 429 430 if (allocDict) { 431 cycleDict = OSDictionary::withCapacity(16); 432 if (!cycleDict) 433 return 0; 434 } 435 436 do { 437 // Check for a cycle 438 ret = super::copyCollection(cycleDict); 439 if (ret) 440 continue; 441 442 newArray = OSArray::withArray(this); 443 if (!newArray) 444 continue; 445 446 // Insert object into cycle Dictionary 447 cycleDict->setObject((const OSSymbol *) this, newArray); 448 449 for (unsigned int i = 0; i < count; i++) { 450 OSCollection *coll = 451 OSDynamicCast(OSCollection, EXT_CAST(newArray->array[i])); 452 453 if (coll) { 454 OSCollection *newColl = coll->copyCollection(cycleDict); 455 if (!newColl) 456 goto abortCopy; 457 458 newArray->replaceObject(i, newColl); 459 newColl->release(); 460 }; 461 }; 462 463 ret = newArray; 464 newArray = 0; 465 466 } while (false); 467 468 abortCopy: 469 if (newArray) 470 newArray->release(); 471 472 if (allocDict) 473 cycleDict->release(); 474 475 return ret; 476 } 477 478