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