xref: /xnu-11215/libkern/c++/OSArray.cpp (revision e13b1fa5)
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