xref: /netbsd-src/common/lib/libprop/prop_array.c (revision 42e8dee34631e017f072502ee6e754ef6778a79f)
1*42e8dee3Sthorpej /*	$NetBSD: prop_array.c,v 1.3 2006/05/28 03:53:51 thorpej Exp $	*/
2774eb1a3Sthorpej 
3774eb1a3Sthorpej /*-
4774eb1a3Sthorpej  * Copyright (c) 2006 The NetBSD Foundation, Inc.
5774eb1a3Sthorpej  * All rights reserved.
6774eb1a3Sthorpej  *
7774eb1a3Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
8774eb1a3Sthorpej  * by Jason R. Thorpe.
9774eb1a3Sthorpej  *
10774eb1a3Sthorpej  * Redistribution and use in source and binary forms, with or without
11774eb1a3Sthorpej  * modification, are permitted provided that the following conditions
12774eb1a3Sthorpej  * are met:
13774eb1a3Sthorpej  * 1. Redistributions of source code must retain the above copyright
14774eb1a3Sthorpej  *    notice, this list of conditions and the following disclaimer.
15774eb1a3Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
16774eb1a3Sthorpej  *    notice, this list of conditions and the following disclaimer in the
17774eb1a3Sthorpej  *    documentation and/or other materials provided with the distribution.
18774eb1a3Sthorpej  * 3. All advertising materials mentioning features or use of this software
19774eb1a3Sthorpej  *    must display the following acknowledgement:
20774eb1a3Sthorpej  *      This product includes software developed by the NetBSD
21774eb1a3Sthorpej  *      Foundation, Inc. and its contributors.
22774eb1a3Sthorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
23774eb1a3Sthorpej  *    contributors may be used to endorse or promote products derived
24774eb1a3Sthorpej  *    from this software without specific prior written permission.
25774eb1a3Sthorpej  *
26774eb1a3Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27774eb1a3Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28774eb1a3Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29774eb1a3Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30774eb1a3Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31774eb1a3Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32774eb1a3Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33774eb1a3Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34774eb1a3Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35774eb1a3Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36774eb1a3Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
37774eb1a3Sthorpej  */
38774eb1a3Sthorpej 
39774eb1a3Sthorpej #include <prop/prop_array.h>
40774eb1a3Sthorpej #include "prop_object_impl.h"
41774eb1a3Sthorpej 
42774eb1a3Sthorpej struct _prop_array {
43774eb1a3Sthorpej 	struct _prop_object	pa_obj;
44774eb1a3Sthorpej 	prop_object_t *		pa_array;
45774eb1a3Sthorpej 	unsigned int		pa_capacity;
46774eb1a3Sthorpej 	unsigned int		pa_count;
47774eb1a3Sthorpej 	int			pa_flags;
48774eb1a3Sthorpej 
49774eb1a3Sthorpej 	uint32_t		pa_version;
50774eb1a3Sthorpej };
51774eb1a3Sthorpej 
52774eb1a3Sthorpej #define	PA_F_IMMUTABLE		0x01	/* array is immutable */
53774eb1a3Sthorpej 
54774eb1a3Sthorpej _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
55774eb1a3Sthorpej _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
56774eb1a3Sthorpej 		    "property array container object")
57774eb1a3Sthorpej 
583e69f1b2Sthorpej static void		_prop_array_free(void *);
593e69f1b2Sthorpej static boolean_t	_prop_array_externalize(
603e69f1b2Sthorpej 				struct _prop_object_externalize_context *,
613e69f1b2Sthorpej 				void *);
623e69f1b2Sthorpej static boolean_t	_prop_array_equals(void *, void *);
633e69f1b2Sthorpej 
643e69f1b2Sthorpej static const struct _prop_object_type _prop_object_type_array = {
653e69f1b2Sthorpej 	.pot_type	=	PROP_TYPE_ARRAY,
663e69f1b2Sthorpej 	.pot_free	=	_prop_array_free,
673e69f1b2Sthorpej 	.pot_extern	=	_prop_array_externalize,
683e69f1b2Sthorpej 	.pot_equals	=	_prop_array_equals,
693e69f1b2Sthorpej };
703e69f1b2Sthorpej 
713e69f1b2Sthorpej #define	prop_object_is_array(x) 	\
723e69f1b2Sthorpej 	((x)->pa_obj.po_type == &_prop_object_type_array)
73774eb1a3Sthorpej 
74774eb1a3Sthorpej #define	prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
75774eb1a3Sthorpej 
76774eb1a3Sthorpej struct _prop_array_iterator {
77774eb1a3Sthorpej 	struct _prop_object_iterator pai_base;
78774eb1a3Sthorpej 	unsigned int		pai_index;
79774eb1a3Sthorpej };
80774eb1a3Sthorpej 
81774eb1a3Sthorpej #define	EXPAND_STEP		16
82774eb1a3Sthorpej 
83774eb1a3Sthorpej static void
84774eb1a3Sthorpej _prop_array_free(void *v)
85774eb1a3Sthorpej {
86774eb1a3Sthorpej 	prop_array_t pa = v;
87774eb1a3Sthorpej 	prop_object_t po;
88774eb1a3Sthorpej 	unsigned int idx;
89774eb1a3Sthorpej 
90774eb1a3Sthorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
91774eb1a3Sthorpej 	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
92774eb1a3Sthorpej 		     (pa->pa_capacity != 0 && pa->pa_array != NULL));
93774eb1a3Sthorpej 
94774eb1a3Sthorpej 	for (idx = 0; idx < pa->pa_count; idx++) {
95774eb1a3Sthorpej 		po = pa->pa_array[idx];
96774eb1a3Sthorpej 		_PROP_ASSERT(po != NULL);
97774eb1a3Sthorpej 		prop_object_release(po);
98774eb1a3Sthorpej 	}
99774eb1a3Sthorpej 
100774eb1a3Sthorpej 	if (pa->pa_array != NULL)
101774eb1a3Sthorpej 		_PROP_FREE(pa->pa_array, M_PROP_ARRAY);
102774eb1a3Sthorpej 
103774eb1a3Sthorpej 	_PROP_POOL_PUT(_prop_array_pool, pa);
104774eb1a3Sthorpej }
105774eb1a3Sthorpej 
106774eb1a3Sthorpej static boolean_t
107774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx,
108774eb1a3Sthorpej 			void *v)
109774eb1a3Sthorpej {
110774eb1a3Sthorpej 	prop_array_t pa = v;
111774eb1a3Sthorpej 	struct _prop_object *po;
112774eb1a3Sthorpej 	prop_object_iterator_t pi;
113774eb1a3Sthorpej 	unsigned int i;
114774eb1a3Sthorpej 
115774eb1a3Sthorpej 	if (pa->pa_count == 0)
116774eb1a3Sthorpej 		return (_prop_object_externalize_empty_tag(ctx, "array"));
117774eb1a3Sthorpej 
118774eb1a3Sthorpej 	/* XXXJRT Hint "count" for the internalize step? */
119774eb1a3Sthorpej 	if (_prop_object_externalize_start_tag(ctx, "array") == FALSE ||
120774eb1a3Sthorpej 	    _prop_object_externalize_append_char(ctx, '\n') == FALSE)
121774eb1a3Sthorpej 		return (FALSE);
122774eb1a3Sthorpej 
123774eb1a3Sthorpej 	pi = prop_array_iterator(pa);
124774eb1a3Sthorpej 	if (pi == NULL)
125774eb1a3Sthorpej 		return (FALSE);
126774eb1a3Sthorpej 
127774eb1a3Sthorpej 	ctx->poec_depth++;
128774eb1a3Sthorpej 	_PROP_ASSERT(ctx->poec_depth != 0);
129774eb1a3Sthorpej 
130774eb1a3Sthorpej 	while ((po = prop_object_iterator_next(pi)) != NULL) {
1313e69f1b2Sthorpej 		if ((*po->po_type->pot_extern)(ctx, po) == FALSE) {
132774eb1a3Sthorpej 			prop_object_iterator_release(pi);
133774eb1a3Sthorpej 			return (FALSE);
134774eb1a3Sthorpej 		}
135774eb1a3Sthorpej 	}
136774eb1a3Sthorpej 
137774eb1a3Sthorpej 	prop_object_iterator_release(pi);
138774eb1a3Sthorpej 
139774eb1a3Sthorpej 	ctx->poec_depth--;
140774eb1a3Sthorpej 	for (i = 0; i < ctx->poec_depth; i++) {
141774eb1a3Sthorpej 		if (_prop_object_externalize_append_char(ctx, '\t') == FALSE)
142774eb1a3Sthorpej 			return (FALSE);
143774eb1a3Sthorpej 	}
144774eb1a3Sthorpej 	if (_prop_object_externalize_end_tag(ctx, "array") == FALSE)
145774eb1a3Sthorpej 		return (FALSE);
146774eb1a3Sthorpej 
147774eb1a3Sthorpej 	return (TRUE);
148774eb1a3Sthorpej }
149774eb1a3Sthorpej 
1503e69f1b2Sthorpej static boolean_t
1513e69f1b2Sthorpej _prop_array_equals(void *v1, void *v2)
1523e69f1b2Sthorpej {
1533e69f1b2Sthorpej 	prop_array_t array1 = v1;
1543e69f1b2Sthorpej 	prop_array_t array2 = v2;
1553e69f1b2Sthorpej 	unsigned int idx;
1563e69f1b2Sthorpej 
1573e69f1b2Sthorpej 	_PROP_ASSERT(prop_object_is_array(array1));
1583e69f1b2Sthorpej 	_PROP_ASSERT(prop_object_is_array(array2));
1593e69f1b2Sthorpej 
1603e69f1b2Sthorpej 	if (array1 == array2)
1613e69f1b2Sthorpej 		return (TRUE);
1623e69f1b2Sthorpej 	if (array1->pa_count != array2->pa_count)
1633e69f1b2Sthorpej 		return (FALSE);
1643e69f1b2Sthorpej 
1653e69f1b2Sthorpej 	for (idx = 0; idx < array1->pa_count; idx++) {
1663e69f1b2Sthorpej 		if (prop_object_equals(array1->pa_array[idx],
1673e69f1b2Sthorpej 				       array2->pa_array[idx]) == FALSE)
1683e69f1b2Sthorpej 			return (FALSE);
1693e69f1b2Sthorpej 	}
1703e69f1b2Sthorpej 
1713e69f1b2Sthorpej 	return (TRUE);
1723e69f1b2Sthorpej }
1733e69f1b2Sthorpej 
174774eb1a3Sthorpej static prop_array_t
175774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity)
176774eb1a3Sthorpej {
177774eb1a3Sthorpej 	prop_array_t pa;
178774eb1a3Sthorpej 	prop_object_t *array;
179774eb1a3Sthorpej 
180774eb1a3Sthorpej 	if (capacity != 0) {
181774eb1a3Sthorpej 		array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
182774eb1a3Sthorpej 				     M_PROP_ARRAY);
183774eb1a3Sthorpej 		if (array == NULL)
184774eb1a3Sthorpej 			return (NULL);
185774eb1a3Sthorpej 	} else
186774eb1a3Sthorpej 		array = NULL;
187774eb1a3Sthorpej 
188774eb1a3Sthorpej 
189774eb1a3Sthorpej 	pa = _PROP_POOL_GET(_prop_array_pool);
190774eb1a3Sthorpej 	if (pa != NULL) {
1913e69f1b2Sthorpej 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
1923e69f1b2Sthorpej 		pa->pa_obj.po_type = &_prop_object_type_array;
193774eb1a3Sthorpej 
194774eb1a3Sthorpej 		pa->pa_array = array;
195774eb1a3Sthorpej 		pa->pa_capacity = capacity;
196774eb1a3Sthorpej 		pa->pa_count = 0;
197774eb1a3Sthorpej 		pa->pa_flags = 0;
198774eb1a3Sthorpej 
199774eb1a3Sthorpej 		pa->pa_version = 0;
200774eb1a3Sthorpej 	} else if (array != NULL)
201774eb1a3Sthorpej 		_PROP_FREE(array, M_PROP_ARRAY);
202774eb1a3Sthorpej 
203774eb1a3Sthorpej 	return (pa);
204774eb1a3Sthorpej }
205774eb1a3Sthorpej 
206774eb1a3Sthorpej static boolean_t
207774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity)
208774eb1a3Sthorpej {
209774eb1a3Sthorpej 	prop_object_t *array, *oarray;
210774eb1a3Sthorpej 
211774eb1a3Sthorpej 	oarray = pa->pa_array;
212774eb1a3Sthorpej 
213*42e8dee3Sthorpej 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
214774eb1a3Sthorpej 	if (array == NULL)
215774eb1a3Sthorpej 		return (FALSE);
216774eb1a3Sthorpej 	if (oarray != NULL)
217*42e8dee3Sthorpej 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
218774eb1a3Sthorpej 	pa->pa_array = array;
219774eb1a3Sthorpej 	pa->pa_capacity = capacity;
220774eb1a3Sthorpej 
221774eb1a3Sthorpej 	if (oarray != NULL)
222774eb1a3Sthorpej 		_PROP_FREE(oarray, M_PROP_ARRAY);
223774eb1a3Sthorpej 
224774eb1a3Sthorpej 	return (TRUE);
225774eb1a3Sthorpej }
226774eb1a3Sthorpej 
227774eb1a3Sthorpej static prop_object_t
228774eb1a3Sthorpej _prop_array_iterator_next_object(void *v)
229774eb1a3Sthorpej {
230774eb1a3Sthorpej 	struct _prop_array_iterator *pai = v;
231774eb1a3Sthorpej 	prop_array_t pa = pai->pai_base.pi_obj;
232774eb1a3Sthorpej 	prop_object_t po;
233774eb1a3Sthorpej 
234774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
235774eb1a3Sthorpej 
236774eb1a3Sthorpej 	if (pa->pa_version != pai->pai_base.pi_version)
237774eb1a3Sthorpej 		return (NULL);	/* array changed during iteration */
238774eb1a3Sthorpej 
239774eb1a3Sthorpej 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
240774eb1a3Sthorpej 
241774eb1a3Sthorpej 	if (pai->pai_index == pa->pa_count)
242774eb1a3Sthorpej 		return (NULL);	/* we've iterated all objects */
243774eb1a3Sthorpej 
244774eb1a3Sthorpej 	po = pa->pa_array[pai->pai_index];
245774eb1a3Sthorpej 	pai->pai_index++;
246774eb1a3Sthorpej 
247774eb1a3Sthorpej 	return (po);
248774eb1a3Sthorpej }
249774eb1a3Sthorpej 
250774eb1a3Sthorpej static void
251774eb1a3Sthorpej _prop_array_iterator_reset(void *v)
252774eb1a3Sthorpej {
253774eb1a3Sthorpej 	struct _prop_array_iterator *pai = v;
254774eb1a3Sthorpej 	prop_array_t pa = pai->pai_base.pi_obj;
255774eb1a3Sthorpej 
256774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
257774eb1a3Sthorpej 
258774eb1a3Sthorpej 	pai->pai_index = 0;
259774eb1a3Sthorpej 	pai->pai_base.pi_version = pa->pa_version;
260774eb1a3Sthorpej }
261774eb1a3Sthorpej 
262774eb1a3Sthorpej /*
263774eb1a3Sthorpej  * prop_array_create --
264774eb1a3Sthorpej  *	Create an empty array.
265774eb1a3Sthorpej  */
266774eb1a3Sthorpej prop_array_t
267774eb1a3Sthorpej prop_array_create(void)
268774eb1a3Sthorpej {
269774eb1a3Sthorpej 
270774eb1a3Sthorpej 	return (_prop_array_alloc(0));
271774eb1a3Sthorpej }
272774eb1a3Sthorpej 
273774eb1a3Sthorpej /*
274774eb1a3Sthorpej  * prop_array_create_with_capacity --
275774eb1a3Sthorpej  *	Create an array with the capacity to store N objects.
276774eb1a3Sthorpej  */
277774eb1a3Sthorpej prop_array_t
278774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity)
279774eb1a3Sthorpej {
280774eb1a3Sthorpej 
281774eb1a3Sthorpej 	return (_prop_array_alloc(capacity));
282774eb1a3Sthorpej }
283774eb1a3Sthorpej 
284774eb1a3Sthorpej /*
285774eb1a3Sthorpej  * prop_array_copy --
286774eb1a3Sthorpej  *	Copy an array.  The new array has an initial capacity equal to
287774eb1a3Sthorpej  *	the number of objects stored in the original array.  The new
288774eb1a3Sthorpej  *	array contains references to the original array's objects, not
289774eb1a3Sthorpej  *	copies of those objects (i.e. a shallow copy).
290774eb1a3Sthorpej  */
291774eb1a3Sthorpej prop_array_t
292774eb1a3Sthorpej prop_array_copy(prop_array_t opa)
293774eb1a3Sthorpej {
294774eb1a3Sthorpej 	prop_array_t pa;
295774eb1a3Sthorpej 	prop_object_t po;
296774eb1a3Sthorpej 	unsigned int idx;
297774eb1a3Sthorpej 
298774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(opa));
299774eb1a3Sthorpej 
300774eb1a3Sthorpej 	pa = _prop_array_alloc(opa->pa_count);
301774eb1a3Sthorpej 	if (pa != NULL) {
302774eb1a3Sthorpej 		for (idx = 0; idx < opa->pa_count; idx++) {
303774eb1a3Sthorpej 			po = opa->pa_array[idx];
304774eb1a3Sthorpej 			prop_object_retain(po);
305774eb1a3Sthorpej 			pa->pa_array[idx] = po;
306774eb1a3Sthorpej 		}
307774eb1a3Sthorpej 		pa->pa_count = opa->pa_count;
308774eb1a3Sthorpej 		pa->pa_flags = opa->pa_flags;
309774eb1a3Sthorpej 	}
310774eb1a3Sthorpej 	return (pa);
311774eb1a3Sthorpej }
312774eb1a3Sthorpej 
313774eb1a3Sthorpej /*
314774eb1a3Sthorpej  * prop_array_copy_mutable --
315774eb1a3Sthorpej  *	Like prop_array_copy(), but the resulting array is mutable.
316774eb1a3Sthorpej  */
317774eb1a3Sthorpej prop_array_t
318774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa)
319774eb1a3Sthorpej {
320774eb1a3Sthorpej 	prop_array_t pa;
321774eb1a3Sthorpej 
322774eb1a3Sthorpej 	pa = prop_array_copy(opa);
323774eb1a3Sthorpej 	if (pa != NULL)
324774eb1a3Sthorpej 		pa->pa_flags &= ~PA_F_IMMUTABLE;
325774eb1a3Sthorpej 
326774eb1a3Sthorpej 	return (pa);
327774eb1a3Sthorpej }
328774eb1a3Sthorpej 
329774eb1a3Sthorpej /*
330774eb1a3Sthorpej  * prop_array_capacity --
331774eb1a3Sthorpej  *	Return the capacity of the array.
332774eb1a3Sthorpej  */
333774eb1a3Sthorpej unsigned int
334774eb1a3Sthorpej prop_array_capacity(prop_array_t pa)
335774eb1a3Sthorpej {
336774eb1a3Sthorpej 
337774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
338774eb1a3Sthorpej 	return (pa->pa_capacity);
339774eb1a3Sthorpej }
340774eb1a3Sthorpej 
341774eb1a3Sthorpej /*
342774eb1a3Sthorpej  * prop_array_count --
343774eb1a3Sthorpej  *	Return the number of objects stored in the array.
344774eb1a3Sthorpej  */
345774eb1a3Sthorpej unsigned int
346774eb1a3Sthorpej prop_array_count(prop_array_t pa)
347774eb1a3Sthorpej {
348774eb1a3Sthorpej 
349774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
350774eb1a3Sthorpej 	return (pa->pa_count);
351774eb1a3Sthorpej }
352774eb1a3Sthorpej 
353774eb1a3Sthorpej /*
354774eb1a3Sthorpej  * prop_array_ensure_capacity --
355774eb1a3Sthorpej  *	Ensure that the array has the capacity to store the specified
356774eb1a3Sthorpej  *	total number of objects (inluding the objects already stored
357774eb1a3Sthorpej  *	in the array).
358774eb1a3Sthorpej  */
359774eb1a3Sthorpej boolean_t
360774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
361774eb1a3Sthorpej {
362774eb1a3Sthorpej 
363774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
364774eb1a3Sthorpej 	if (capacity > pa->pa_capacity)
365*42e8dee3Sthorpej 		return (_prop_array_expand(pa, capacity));
366774eb1a3Sthorpej 	return (TRUE);
367774eb1a3Sthorpej }
368774eb1a3Sthorpej 
369774eb1a3Sthorpej /*
370774eb1a3Sthorpej  * prop_array_iterator --
371774eb1a3Sthorpej  *	Return an iterator for the array.  The array is retained by
372774eb1a3Sthorpej  *	the iterator.
373774eb1a3Sthorpej  */
374774eb1a3Sthorpej prop_object_iterator_t
375774eb1a3Sthorpej prop_array_iterator(prop_array_t pa)
376774eb1a3Sthorpej {
377774eb1a3Sthorpej 	struct _prop_array_iterator *pai;
378774eb1a3Sthorpej 
379774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
380774eb1a3Sthorpej 
381774eb1a3Sthorpej 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
382774eb1a3Sthorpej 	if (pai == NULL)
383774eb1a3Sthorpej 		return (NULL);
384774eb1a3Sthorpej 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
385774eb1a3Sthorpej 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
386774eb1a3Sthorpej 	prop_object_retain(pa);
387774eb1a3Sthorpej 	pai->pai_base.pi_obj = pa;
388774eb1a3Sthorpej 	pai->pai_base.pi_version = pa->pa_version;
389774eb1a3Sthorpej 
390774eb1a3Sthorpej 	_prop_array_iterator_reset(pai);
391774eb1a3Sthorpej 
392774eb1a3Sthorpej 	return (&pai->pai_base);
393774eb1a3Sthorpej }
394774eb1a3Sthorpej 
395774eb1a3Sthorpej /*
396774eb1a3Sthorpej  * prop_array_make_immutable --
397774eb1a3Sthorpej  *	Make the array immutable.
398774eb1a3Sthorpej  */
399774eb1a3Sthorpej void
400774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa)
401774eb1a3Sthorpej {
402774eb1a3Sthorpej 
403774eb1a3Sthorpej 	if (prop_array_is_immutable(pa) == FALSE)
404774eb1a3Sthorpej 		pa->pa_flags |= PA_F_IMMUTABLE;
405774eb1a3Sthorpej }
406774eb1a3Sthorpej 
407774eb1a3Sthorpej /*
408774eb1a3Sthorpej  * prop_array_mutable --
409774eb1a3Sthorpej  *	Returns TRUE if the array is mutable.
410774eb1a3Sthorpej  */
411774eb1a3Sthorpej boolean_t
412774eb1a3Sthorpej prop_array_mutable(prop_array_t pa)
413774eb1a3Sthorpej {
414774eb1a3Sthorpej 
415774eb1a3Sthorpej 	return (prop_array_is_immutable(pa) == FALSE);
416774eb1a3Sthorpej }
417774eb1a3Sthorpej 
418774eb1a3Sthorpej /*
419774eb1a3Sthorpej  * prop_array_get --
420774eb1a3Sthorpej  *	Return the object stored at the specified array index.
421774eb1a3Sthorpej  */
422774eb1a3Sthorpej prop_object_t
423774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx)
424774eb1a3Sthorpej {
425774eb1a3Sthorpej 	prop_object_t po;
426774eb1a3Sthorpej 
427774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
428774eb1a3Sthorpej 	if (idx >= pa->pa_count)
429774eb1a3Sthorpej 		return (NULL);
430774eb1a3Sthorpej 	po = pa->pa_array[idx];
431774eb1a3Sthorpej 	_PROP_ASSERT(po != NULL);
432774eb1a3Sthorpej 	return (po);
433774eb1a3Sthorpej }
434774eb1a3Sthorpej 
435774eb1a3Sthorpej /*
436774eb1a3Sthorpej  * prop_array_set --
437774eb1a3Sthorpej  *	Store a reference to an object at the specified array index.
438774eb1a3Sthorpej  *	This method is not allowed to create holes in the array; the
439774eb1a3Sthorpej  *	caller must either be setting the object just beyond the existing
440774eb1a3Sthorpej  *	count or replacing an already existing object reference.
441774eb1a3Sthorpej  */
442774eb1a3Sthorpej boolean_t
443774eb1a3Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
444774eb1a3Sthorpej {
445774eb1a3Sthorpej 	prop_object_t opo;
446774eb1a3Sthorpej 
447774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
448774eb1a3Sthorpej 
449774eb1a3Sthorpej 	if (prop_array_is_immutable(pa))
450774eb1a3Sthorpej 		return (FALSE);
451774eb1a3Sthorpej 
452774eb1a3Sthorpej 	if (idx == pa->pa_count)
453774eb1a3Sthorpej 		return (prop_array_add(pa, po));
454774eb1a3Sthorpej 
455774eb1a3Sthorpej 	_PROP_ASSERT(idx < pa->pa_count);
456774eb1a3Sthorpej 
457774eb1a3Sthorpej 	opo = pa->pa_array[idx];
458774eb1a3Sthorpej 	_PROP_ASSERT(opo != NULL);
459774eb1a3Sthorpej 
460774eb1a3Sthorpej 	prop_object_retain(po);
461774eb1a3Sthorpej 	pa->pa_array[idx] = po;
462774eb1a3Sthorpej 	pa->pa_version++;
463774eb1a3Sthorpej 
464774eb1a3Sthorpej 	prop_object_release(opo);
465774eb1a3Sthorpej 
466774eb1a3Sthorpej 	return (TRUE);
467774eb1a3Sthorpej }
468774eb1a3Sthorpej 
469774eb1a3Sthorpej /*
470774eb1a3Sthorpej  * prop_array_add --
471774eb1a3Sthorpej  *	Add a refrerence to an object to the specified array, appending
472774eb1a3Sthorpej  *	to the end and growing the array's capacity, if necessary.
473774eb1a3Sthorpej  */
474774eb1a3Sthorpej boolean_t
475774eb1a3Sthorpej prop_array_add(prop_array_t pa, prop_object_t po)
476774eb1a3Sthorpej {
477774eb1a3Sthorpej 
478774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
479774eb1a3Sthorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
480774eb1a3Sthorpej 
481774eb1a3Sthorpej 	if (prop_array_is_immutable(pa) ||
482774eb1a3Sthorpej 	    (pa->pa_count == pa->pa_capacity &&
483774eb1a3Sthorpej 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == FALSE))
484774eb1a3Sthorpej 		return (FALSE);
485774eb1a3Sthorpej 
486774eb1a3Sthorpej 	prop_object_retain(po);
487774eb1a3Sthorpej 	pa->pa_array[pa->pa_count++] = po;
488774eb1a3Sthorpej 	pa->pa_version++;
489774eb1a3Sthorpej 
490774eb1a3Sthorpej 	return (TRUE);
491774eb1a3Sthorpej }
492774eb1a3Sthorpej 
493774eb1a3Sthorpej /*
494774eb1a3Sthorpej  * prop_array_remove --
495774eb1a3Sthorpej  *	Remove the reference to an object from an array at the specified
496774eb1a3Sthorpej  *	index.  The array will be compacted following the removal.
497774eb1a3Sthorpej  */
498774eb1a3Sthorpej void
499774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx)
500774eb1a3Sthorpej {
501774eb1a3Sthorpej 	prop_object_t po;
502774eb1a3Sthorpej 
503774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
504774eb1a3Sthorpej 	_PROP_ASSERT(idx < pa->pa_count);
505774eb1a3Sthorpej 
506774eb1a3Sthorpej 	/* XXX Should this be a _PROP_ASSERT()? */
507774eb1a3Sthorpej 	if (prop_array_is_immutable(pa))
508774eb1a3Sthorpej 		return;
509774eb1a3Sthorpej 
510774eb1a3Sthorpej 	po = pa->pa_array[idx];
511774eb1a3Sthorpej 	_PROP_ASSERT(po != NULL);
512774eb1a3Sthorpej 
513774eb1a3Sthorpej 	for (++idx; idx < pa->pa_count; idx++)
514774eb1a3Sthorpej 		pa->pa_array[idx - 1] = pa->pa_array[idx];
515774eb1a3Sthorpej 	pa->pa_count--;
516774eb1a3Sthorpej 	pa->pa_version++;
517774eb1a3Sthorpej 
518774eb1a3Sthorpej 	prop_object_release(po);
519774eb1a3Sthorpej }
520774eb1a3Sthorpej 
521774eb1a3Sthorpej /*
5223e69f1b2Sthorpej  * prop_array_equals --
5233e69f1b2Sthorpej  *	Return TRUE if the two arrays are equivalent.  Note we do a
5243e69f1b2Sthorpej  *	by-value comparison of the objects in the array.
5253e69f1b2Sthorpej  */
5263e69f1b2Sthorpej boolean_t
5273e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2)
5283e69f1b2Sthorpej {
5293e69f1b2Sthorpej 
5303e69f1b2Sthorpej 	return (_prop_array_equals(array1, array2));
5313e69f1b2Sthorpej }
5323e69f1b2Sthorpej 
5333e69f1b2Sthorpej /*
534774eb1a3Sthorpej  * _prop_array_internalize --
535774eb1a3Sthorpej  *	Parse an <array>...</array> and return the object created from the
536774eb1a3Sthorpej  *	external representation.
537774eb1a3Sthorpej  */
538774eb1a3Sthorpej prop_object_t
539774eb1a3Sthorpej _prop_array_internalize(struct _prop_object_internalize_context *ctx)
540774eb1a3Sthorpej {
541774eb1a3Sthorpej 	prop_array_t array;
542774eb1a3Sthorpej 	prop_object_t obj;
543774eb1a3Sthorpej 
544774eb1a3Sthorpej 	/* We don't currently understand any attributes. */
545774eb1a3Sthorpej 	if (ctx->poic_tagattr != NULL)
546774eb1a3Sthorpej 		return (NULL);
547774eb1a3Sthorpej 
548774eb1a3Sthorpej 	array = prop_array_create();
549774eb1a3Sthorpej 	if (array == NULL)
550774eb1a3Sthorpej 		return (NULL);
551774eb1a3Sthorpej 
552774eb1a3Sthorpej 	if (ctx->poic_is_empty_element)
553774eb1a3Sthorpej 		return (array);
554774eb1a3Sthorpej 
555774eb1a3Sthorpej 	for (;;) {
556774eb1a3Sthorpej 		/* Fetch the next tag. */
557774eb1a3Sthorpej 		if (_prop_object_internalize_find_tag(ctx, NULL,
558774eb1a3Sthorpej 					_PROP_TAG_TYPE_EITHER) == FALSE)
559774eb1a3Sthorpej 			goto bad;
560774eb1a3Sthorpej 
561774eb1a3Sthorpej 		/* Check to see if this is the end of the array. */
562774eb1a3Sthorpej 		if (_PROP_TAG_MATCH(ctx, "array") &&
563774eb1a3Sthorpej 		    ctx->poic_tag_type == _PROP_TAG_TYPE_END)
564774eb1a3Sthorpej 		    	break;
565774eb1a3Sthorpej 
566774eb1a3Sthorpej 		/* Fetch the object. */
567774eb1a3Sthorpej 		obj = _prop_object_internalize_by_tag(ctx);
568774eb1a3Sthorpej 		if (obj == NULL)
569774eb1a3Sthorpej 			goto bad;
570774eb1a3Sthorpej 
571774eb1a3Sthorpej 		if (prop_array_add(array, obj) == FALSE) {
572774eb1a3Sthorpej 			prop_object_release(obj);
573774eb1a3Sthorpej 			goto bad;
574774eb1a3Sthorpej 		}
575774eb1a3Sthorpej 		prop_object_release(obj);
576774eb1a3Sthorpej 	}
577774eb1a3Sthorpej 
578774eb1a3Sthorpej 	return (array);
579774eb1a3Sthorpej 
580774eb1a3Sthorpej  bad:
581774eb1a3Sthorpej 	prop_object_release(array);
582774eb1a3Sthorpej 	return (NULL);
583774eb1a3Sthorpej }
584