xref: /dflybsd-src/sys/libprop/prop_array.c (revision f3f3eadbf9de7a55ef1ff8cb23a68641403906ea)
19f95f3e0SAlex Hornung /*	$NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $	*/
29f95f3e0SAlex Hornung 
39f95f3e0SAlex Hornung /*-
49f95f3e0SAlex Hornung  * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
59f95f3e0SAlex Hornung  * All rights reserved.
69f95f3e0SAlex Hornung  *
79f95f3e0SAlex Hornung  * This code is derived from software contributed to The NetBSD Foundation
89f95f3e0SAlex Hornung  * by Jason R. Thorpe.
99f95f3e0SAlex Hornung  *
109f95f3e0SAlex Hornung  * Redistribution and use in source and binary forms, with or without
119f95f3e0SAlex Hornung  * modification, are permitted provided that the following conditions
129f95f3e0SAlex Hornung  * are met:
139f95f3e0SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
149f95f3e0SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
159f95f3e0SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
169f95f3e0SAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
179f95f3e0SAlex Hornung  *    documentation and/or other materials provided with the distribution.
189f95f3e0SAlex Hornung  *
199f95f3e0SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209f95f3e0SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219f95f3e0SAlex Hornung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229f95f3e0SAlex Hornung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239f95f3e0SAlex Hornung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249f95f3e0SAlex Hornung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259f95f3e0SAlex Hornung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269f95f3e0SAlex Hornung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279f95f3e0SAlex Hornung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289f95f3e0SAlex Hornung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299f95f3e0SAlex Hornung  * POSSIBILITY OF SUCH DAMAGE.
309f95f3e0SAlex Hornung  */
319f95f3e0SAlex Hornung 
329f95f3e0SAlex Hornung #include <libprop/prop_array.h>
339f95f3e0SAlex Hornung #include "prop_object_impl.h"
349f95f3e0SAlex Hornung 
359f95f3e0SAlex Hornung #if !defined(_KERNEL) && !defined(_STANDALONE)
369f95f3e0SAlex Hornung #include <errno.h>
379f95f3e0SAlex Hornung #endif
389f95f3e0SAlex Hornung 
399f95f3e0SAlex Hornung struct _prop_array {
409f95f3e0SAlex Hornung 	struct _prop_object	pa_obj;
419f95f3e0SAlex Hornung 	_PROP_RWLOCK_DECL(pa_rwlock)
429f95f3e0SAlex Hornung 	prop_object_t *		pa_array;
439f95f3e0SAlex Hornung 	unsigned int		pa_capacity;
449f95f3e0SAlex Hornung 	unsigned int		pa_count;
459f95f3e0SAlex Hornung 	int			pa_flags;
469f95f3e0SAlex Hornung 
479f95f3e0SAlex Hornung 	uint32_t		pa_version;
489f95f3e0SAlex Hornung };
499f95f3e0SAlex Hornung 
509f95f3e0SAlex Hornung #define PA_F_IMMUTABLE		0x01	/* array is immutable */
519f95f3e0SAlex Hornung 
52*f3f3eadbSSascha Wildner _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay");
539f95f3e0SAlex Hornung _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
549f95f3e0SAlex Hornung 		    "property array container object")
559f95f3e0SAlex Hornung 
569f95f3e0SAlex Hornung static _prop_object_free_rv_t
579f95f3e0SAlex Hornung 		_prop_array_free(prop_stack_t, prop_object_t *);
589f95f3e0SAlex Hornung static void	_prop_array_emergency_free(prop_object_t);
599f95f3e0SAlex Hornung static bool	_prop_array_externalize(
609f95f3e0SAlex Hornung 				struct _prop_object_externalize_context *,
619f95f3e0SAlex Hornung 				void *);
629f95f3e0SAlex Hornung static _prop_object_equals_rv_t
639f95f3e0SAlex Hornung 		_prop_array_equals(prop_object_t, prop_object_t,
649f95f3e0SAlex Hornung 				   void **, void **,
659f95f3e0SAlex Hornung 				   prop_object_t *, prop_object_t *);
669f95f3e0SAlex Hornung static void	_prop_array_equals_finish(prop_object_t, prop_object_t);
679f95f3e0SAlex Hornung static prop_object_iterator_t
689f95f3e0SAlex Hornung 		_prop_array_iterator_locked(prop_array_t);
699f95f3e0SAlex Hornung static prop_object_t
709f95f3e0SAlex Hornung 		_prop_array_iterator_next_object_locked(void *);
719f95f3e0SAlex Hornung static void	_prop_array_iterator_reset_locked(void *);
729f95f3e0SAlex Hornung 
739f95f3e0SAlex Hornung static const struct _prop_object_type _prop_object_type_array = {
749f95f3e0SAlex Hornung 	.pot_type		=	PROP_TYPE_ARRAY,
759f95f3e0SAlex Hornung 	.pot_free		=	_prop_array_free,
769f95f3e0SAlex Hornung 	.pot_emergency_free	=	_prop_array_emergency_free,
779f95f3e0SAlex Hornung 	.pot_extern		=	_prop_array_externalize,
789f95f3e0SAlex Hornung 	.pot_equals		=	_prop_array_equals,
799f95f3e0SAlex Hornung 	.pot_equals_finish	=	_prop_array_equals_finish,
809f95f3e0SAlex Hornung };
819f95f3e0SAlex Hornung 
829f95f3e0SAlex Hornung #define prop_object_is_array(x)		\
839f95f3e0SAlex Hornung 	((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
849f95f3e0SAlex Hornung 
859f95f3e0SAlex Hornung #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
869f95f3e0SAlex Hornung 
879f95f3e0SAlex Hornung struct _prop_array_iterator {
889f95f3e0SAlex Hornung 	struct _prop_object_iterator pai_base;
899f95f3e0SAlex Hornung 	unsigned int		pai_index;
909f95f3e0SAlex Hornung };
919f95f3e0SAlex Hornung 
929f95f3e0SAlex Hornung #define EXPAND_STEP		16
939f95f3e0SAlex Hornung 
949f95f3e0SAlex Hornung static _prop_object_free_rv_t
_prop_array_free(prop_stack_t stack,prop_object_t * obj)959f95f3e0SAlex Hornung _prop_array_free(prop_stack_t stack, prop_object_t *obj)
969f95f3e0SAlex Hornung {
979f95f3e0SAlex Hornung 	prop_array_t pa = *obj;
989f95f3e0SAlex Hornung 	prop_object_t po;
999f95f3e0SAlex Hornung 
1009f95f3e0SAlex Hornung 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
1019f95f3e0SAlex Hornung 	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
1029f95f3e0SAlex Hornung 		     (pa->pa_capacity != 0 && pa->pa_array != NULL));
1039f95f3e0SAlex Hornung 
1049f95f3e0SAlex Hornung 	/* The easy case is an empty array, just free and return. */
1059f95f3e0SAlex Hornung 	if (pa->pa_count == 0) {
1069f95f3e0SAlex Hornung 		if (pa->pa_array != NULL)
1079f95f3e0SAlex Hornung 			_PROP_FREE(pa->pa_array, M_PROP_ARRAY);
1089f95f3e0SAlex Hornung 
1099f95f3e0SAlex Hornung 		_PROP_RWLOCK_DESTROY(pa->pa_rwlock);
1109f95f3e0SAlex Hornung 
1119f95f3e0SAlex Hornung 		_PROP_POOL_PUT(_prop_array_pool, pa);
1129f95f3e0SAlex Hornung 
1139f95f3e0SAlex Hornung 		return (_PROP_OBJECT_FREE_DONE);
1149f95f3e0SAlex Hornung 	}
1159f95f3e0SAlex Hornung 
1169f95f3e0SAlex Hornung 	po = pa->pa_array[pa->pa_count - 1];
1179f95f3e0SAlex Hornung 	_PROP_ASSERT(po != NULL);
1189f95f3e0SAlex Hornung 
1199f95f3e0SAlex Hornung 	if (stack == NULL) {
1209f95f3e0SAlex Hornung 		/*
1219f95f3e0SAlex Hornung 		 * If we are in emergency release mode,
1229f95f3e0SAlex Hornung 		 * just let caller recurse down.
1239f95f3e0SAlex Hornung 		 */
1249f95f3e0SAlex Hornung 		*obj = po;
1259f95f3e0SAlex Hornung 		return (_PROP_OBJECT_FREE_FAILED);
1269f95f3e0SAlex Hornung 	}
1279f95f3e0SAlex Hornung 
1289f95f3e0SAlex Hornung 	/* Otherwise, try to push the current object on the stack. */
1299f95f3e0SAlex Hornung 	if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
1309f95f3e0SAlex Hornung 		/* Push failed, entering emergency release mode. */
1319f95f3e0SAlex Hornung 		return (_PROP_OBJECT_FREE_FAILED);
1329f95f3e0SAlex Hornung 	}
1339f95f3e0SAlex Hornung 	/* Object pushed on stack, caller will release it. */
1349f95f3e0SAlex Hornung 	--pa->pa_count;
1359f95f3e0SAlex Hornung 	*obj = po;
1369f95f3e0SAlex Hornung 	return (_PROP_OBJECT_FREE_RECURSE);
1379f95f3e0SAlex Hornung }
1389f95f3e0SAlex Hornung 
1399f95f3e0SAlex Hornung static void
_prop_array_emergency_free(prop_object_t obj)1409f95f3e0SAlex Hornung _prop_array_emergency_free(prop_object_t obj)
1419f95f3e0SAlex Hornung {
1429f95f3e0SAlex Hornung 	prop_array_t pa = obj;
1439f95f3e0SAlex Hornung 
1449f95f3e0SAlex Hornung 	_PROP_ASSERT(pa->pa_count != 0);
1459f95f3e0SAlex Hornung 	--pa->pa_count;
1469f95f3e0SAlex Hornung }
1479f95f3e0SAlex Hornung 
1489f95f3e0SAlex Hornung static bool
_prop_array_externalize(struct _prop_object_externalize_context * ctx,void * v)1499f95f3e0SAlex Hornung _prop_array_externalize(struct _prop_object_externalize_context *ctx,
1509f95f3e0SAlex Hornung 			void *v)
1519f95f3e0SAlex Hornung {
1529f95f3e0SAlex Hornung 	prop_array_t pa = v;
1539f95f3e0SAlex Hornung 	struct _prop_object *po;
1549f95f3e0SAlex Hornung 	prop_object_iterator_t pi;
1559f95f3e0SAlex Hornung 	unsigned int i;
1569f95f3e0SAlex Hornung 	bool rv = false;
1579f95f3e0SAlex Hornung 
1589f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
1599f95f3e0SAlex Hornung 
1609f95f3e0SAlex Hornung 	if (pa->pa_count == 0) {
1619f95f3e0SAlex Hornung 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
1629f95f3e0SAlex Hornung 		return (_prop_object_externalize_empty_tag(ctx, "array"));
1639f95f3e0SAlex Hornung 	}
1649f95f3e0SAlex Hornung 
1659f95f3e0SAlex Hornung 	/* XXXJRT Hint "count" for the internalize step? */
1669f95f3e0SAlex Hornung 	if (_prop_object_externalize_start_tag(ctx, "array") == false ||
1679f95f3e0SAlex Hornung 	    _prop_object_externalize_append_char(ctx, '\n') == false)
1689f95f3e0SAlex Hornung 		goto out;
1699f95f3e0SAlex Hornung 
1709f95f3e0SAlex Hornung 	pi = _prop_array_iterator_locked(pa);
1719f95f3e0SAlex Hornung 	if (pi == NULL)
1729f95f3e0SAlex Hornung 		goto out;
1739f95f3e0SAlex Hornung 
1749f95f3e0SAlex Hornung 	ctx->poec_depth++;
1759f95f3e0SAlex Hornung 	_PROP_ASSERT(ctx->poec_depth != 0);
1769f95f3e0SAlex Hornung 
1779f95f3e0SAlex Hornung 	while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
1789f95f3e0SAlex Hornung 		if ((*po->po_type->pot_extern)(ctx, po) == false) {
1799f95f3e0SAlex Hornung 			prop_object_iterator_release(pi);
1809f95f3e0SAlex Hornung 			goto out;
1819f95f3e0SAlex Hornung 		}
1829f95f3e0SAlex Hornung 	}
1839f95f3e0SAlex Hornung 
1849f95f3e0SAlex Hornung 	prop_object_iterator_release(pi);
1859f95f3e0SAlex Hornung 
1869f95f3e0SAlex Hornung 	ctx->poec_depth--;
1879f95f3e0SAlex Hornung 	for (i = 0; i < ctx->poec_depth; i++) {
1889f95f3e0SAlex Hornung 		if (_prop_object_externalize_append_char(ctx, '\t') == false)
1899f95f3e0SAlex Hornung 			goto out;
1909f95f3e0SAlex Hornung 	}
1919f95f3e0SAlex Hornung 	if (_prop_object_externalize_end_tag(ctx, "array") == false)
1929f95f3e0SAlex Hornung 		goto out;
1939f95f3e0SAlex Hornung 
1949f95f3e0SAlex Hornung 	rv = true;
1959f95f3e0SAlex Hornung 
1969f95f3e0SAlex Hornung  out:
1979f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
1989f95f3e0SAlex Hornung 	return (rv);
1999f95f3e0SAlex Hornung }
2009f95f3e0SAlex Hornung 
2019f95f3e0SAlex Hornung /* ARGSUSED */
2029f95f3e0SAlex Hornung static _prop_object_equals_rv_t
_prop_array_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)2039f95f3e0SAlex Hornung _prop_array_equals(prop_object_t v1, prop_object_t v2,
2049f95f3e0SAlex Hornung     void **stored_pointer1, void **stored_pointer2,
2059f95f3e0SAlex Hornung     prop_object_t *next_obj1, prop_object_t *next_obj2)
2069f95f3e0SAlex Hornung {
2079f95f3e0SAlex Hornung 	prop_array_t array1 = v1;
2089f95f3e0SAlex Hornung 	prop_array_t array2 = v2;
2099f95f3e0SAlex Hornung 	uintptr_t idx;
2109f95f3e0SAlex Hornung 	_prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
2119f95f3e0SAlex Hornung 
2129f95f3e0SAlex Hornung 	if (array1 == array2)
2139f95f3e0SAlex Hornung 		return (_PROP_OBJECT_EQUALS_TRUE);
2149f95f3e0SAlex Hornung 
2159f95f3e0SAlex Hornung 	_PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
2169f95f3e0SAlex Hornung 	idx = (uintptr_t)*stored_pointer1;
2179f95f3e0SAlex Hornung 
2189f95f3e0SAlex Hornung 	/* For the first iteration, lock the objects. */
2199f95f3e0SAlex Hornung 	if (idx == 0) {
2209f95f3e0SAlex Hornung 		if ((uintptr_t)array1 < (uintptr_t)array2) {
2219f95f3e0SAlex Hornung 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
2229f95f3e0SAlex Hornung 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
2239f95f3e0SAlex Hornung 		} else {
2249f95f3e0SAlex Hornung 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
2259f95f3e0SAlex Hornung 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
2269f95f3e0SAlex Hornung 		}
2279f95f3e0SAlex Hornung 	}
2289f95f3e0SAlex Hornung 
2299f95f3e0SAlex Hornung 	if (array1->pa_count != array2->pa_count)
2309f95f3e0SAlex Hornung 		goto out;
2319f95f3e0SAlex Hornung 	if (idx == array1->pa_count) {
2329f95f3e0SAlex Hornung 		rv = _PROP_OBJECT_EQUALS_TRUE;
2339f95f3e0SAlex Hornung 		goto out;
2349f95f3e0SAlex Hornung 	}
2359f95f3e0SAlex Hornung 	_PROP_ASSERT(idx < array1->pa_count);
2369f95f3e0SAlex Hornung 
2379f95f3e0SAlex Hornung 	*stored_pointer1 = (void *)(idx + 1);
2389f95f3e0SAlex Hornung 	*stored_pointer2 = (void *)(idx + 1);
2399f95f3e0SAlex Hornung 
2409f95f3e0SAlex Hornung 	*next_obj1 = array1->pa_array[idx];
2419f95f3e0SAlex Hornung 	*next_obj2 = array2->pa_array[idx];
2429f95f3e0SAlex Hornung 
2439f95f3e0SAlex Hornung 	return (_PROP_OBJECT_EQUALS_RECURSE);
2449f95f3e0SAlex Hornung 
2459f95f3e0SAlex Hornung  out:
2469f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
2479f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
2489f95f3e0SAlex Hornung 	return (rv);
2499f95f3e0SAlex Hornung }
2509f95f3e0SAlex Hornung 
2519f95f3e0SAlex Hornung static void
_prop_array_equals_finish(prop_object_t v1,prop_object_t v2)2529f95f3e0SAlex Hornung _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
2539f95f3e0SAlex Hornung {
2549f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
2559f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
2569f95f3e0SAlex Hornung }
2579f95f3e0SAlex Hornung 
2589f95f3e0SAlex Hornung static prop_array_t
_prop_array_alloc(unsigned int capacity)2599f95f3e0SAlex Hornung _prop_array_alloc(unsigned int capacity)
2609f95f3e0SAlex Hornung {
2619f95f3e0SAlex Hornung 	prop_array_t pa;
2629f95f3e0SAlex Hornung 	prop_object_t *array;
2639f95f3e0SAlex Hornung 
2649f95f3e0SAlex Hornung 	if (capacity != 0) {
2659f95f3e0SAlex Hornung 		array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
2669f95f3e0SAlex Hornung 				     M_PROP_ARRAY);
2679f95f3e0SAlex Hornung 		if (array == NULL)
2689f95f3e0SAlex Hornung 			return (NULL);
2699f95f3e0SAlex Hornung 	} else
2709f95f3e0SAlex Hornung 		array = NULL;
2719f95f3e0SAlex Hornung 
2729f95f3e0SAlex Hornung 	pa = _PROP_POOL_GET(_prop_array_pool);
2739f95f3e0SAlex Hornung 	if (pa != NULL) {
2749f95f3e0SAlex Hornung 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
2759f95f3e0SAlex Hornung 		pa->pa_obj.po_type = &_prop_object_type_array;
2769f95f3e0SAlex Hornung 
2779f95f3e0SAlex Hornung 		_PROP_RWLOCK_INIT(pa->pa_rwlock);
2789f95f3e0SAlex Hornung 		pa->pa_array = array;
2799f95f3e0SAlex Hornung 		pa->pa_capacity = capacity;
2809f95f3e0SAlex Hornung 		pa->pa_count = 0;
2819f95f3e0SAlex Hornung 		pa->pa_flags = 0;
2829f95f3e0SAlex Hornung 
2839f95f3e0SAlex Hornung 		pa->pa_version = 0;
2849f95f3e0SAlex Hornung 	} else if (array != NULL)
2859f95f3e0SAlex Hornung 		_PROP_FREE(array, M_PROP_ARRAY);
2869f95f3e0SAlex Hornung 
2879f95f3e0SAlex Hornung 	return (pa);
2889f95f3e0SAlex Hornung }
2899f95f3e0SAlex Hornung 
2909f95f3e0SAlex Hornung static bool
_prop_array_expand(prop_array_t pa,unsigned int capacity)2919f95f3e0SAlex Hornung _prop_array_expand(prop_array_t pa, unsigned int capacity)
2929f95f3e0SAlex Hornung {
2939f95f3e0SAlex Hornung 	prop_object_t *array, *oarray;
2949f95f3e0SAlex Hornung 
2959f95f3e0SAlex Hornung 	/*
2969f95f3e0SAlex Hornung 	 * Array must be WRITE-LOCKED.
2979f95f3e0SAlex Hornung 	 */
2989f95f3e0SAlex Hornung 
2999f95f3e0SAlex Hornung 	oarray = pa->pa_array;
3009f95f3e0SAlex Hornung 
3019f95f3e0SAlex Hornung 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
3029f95f3e0SAlex Hornung 	if (array == NULL)
3039f95f3e0SAlex Hornung 		return (false);
3049f95f3e0SAlex Hornung 	if (oarray != NULL)
3059f95f3e0SAlex Hornung 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
3069f95f3e0SAlex Hornung 	pa->pa_array = array;
3079f95f3e0SAlex Hornung 	pa->pa_capacity = capacity;
3089f95f3e0SAlex Hornung 
3099f95f3e0SAlex Hornung 	if (oarray != NULL)
3109f95f3e0SAlex Hornung 		_PROP_FREE(oarray, M_PROP_ARRAY);
3119f95f3e0SAlex Hornung 
3129f95f3e0SAlex Hornung 	return (true);
3139f95f3e0SAlex Hornung }
3149f95f3e0SAlex Hornung 
3159f95f3e0SAlex Hornung static prop_object_t
_prop_array_iterator_next_object_locked(void * v)3169f95f3e0SAlex Hornung _prop_array_iterator_next_object_locked(void *v)
3179f95f3e0SAlex Hornung {
3189f95f3e0SAlex Hornung 	struct _prop_array_iterator *pai = v;
3199f95f3e0SAlex Hornung 	prop_array_t pa = pai->pai_base.pi_obj;
3209f95f3e0SAlex Hornung 	prop_object_t po = NULL;
3219f95f3e0SAlex Hornung 
3229f95f3e0SAlex Hornung 	_PROP_ASSERT(prop_object_is_array(pa));
3239f95f3e0SAlex Hornung 
3249f95f3e0SAlex Hornung 	if (pa->pa_version != pai->pai_base.pi_version)
3259f95f3e0SAlex Hornung 		goto out;	/* array changed during iteration */
3269f95f3e0SAlex Hornung 
3279f95f3e0SAlex Hornung 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
3289f95f3e0SAlex Hornung 
3299f95f3e0SAlex Hornung 	if (pai->pai_index == pa->pa_count)
3309f95f3e0SAlex Hornung 		goto out;	/* we've iterated all objects */
3319f95f3e0SAlex Hornung 
3329f95f3e0SAlex Hornung 	po = pa->pa_array[pai->pai_index];
3339f95f3e0SAlex Hornung 	pai->pai_index++;
3349f95f3e0SAlex Hornung 
3359f95f3e0SAlex Hornung  out:
3369f95f3e0SAlex Hornung 	return (po);
3379f95f3e0SAlex Hornung }
3389f95f3e0SAlex Hornung 
3399f95f3e0SAlex Hornung static prop_object_t
_prop_array_iterator_next_object(void * v)3409f95f3e0SAlex Hornung _prop_array_iterator_next_object(void *v)
3419f95f3e0SAlex Hornung {
3429f95f3e0SAlex Hornung 	struct _prop_array_iterator *pai = v;
343b0dfaa52SSascha Wildner 	prop_array_t pa = pai->pai_base.pi_obj;
3449f95f3e0SAlex Hornung 	prop_object_t po;
3459f95f3e0SAlex Hornung 
3469f95f3e0SAlex Hornung 	_PROP_ASSERT(prop_object_is_array(pa));
3479f95f3e0SAlex Hornung 
3489f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
3499f95f3e0SAlex Hornung 	po = _prop_array_iterator_next_object_locked(pai);
3509f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
3519f95f3e0SAlex Hornung 	return (po);
3529f95f3e0SAlex Hornung }
3539f95f3e0SAlex Hornung 
3549f95f3e0SAlex Hornung static void
_prop_array_iterator_reset_locked(void * v)3559f95f3e0SAlex Hornung _prop_array_iterator_reset_locked(void *v)
3569f95f3e0SAlex Hornung {
3579f95f3e0SAlex Hornung 	struct _prop_array_iterator *pai = v;
3589f95f3e0SAlex Hornung 	prop_array_t pa = pai->pai_base.pi_obj;
3599f95f3e0SAlex Hornung 
3609f95f3e0SAlex Hornung 	_PROP_ASSERT(prop_object_is_array(pa));
3619f95f3e0SAlex Hornung 
3629f95f3e0SAlex Hornung 	pai->pai_index = 0;
3639f95f3e0SAlex Hornung 	pai->pai_base.pi_version = pa->pa_version;
3649f95f3e0SAlex Hornung }
3659f95f3e0SAlex Hornung 
3669f95f3e0SAlex Hornung static void
_prop_array_iterator_reset(void * v)3679f95f3e0SAlex Hornung _prop_array_iterator_reset(void *v)
3689f95f3e0SAlex Hornung {
3699f95f3e0SAlex Hornung 	struct _prop_array_iterator *pai = v;
370b0dfaa52SSascha Wildner 	prop_array_t pa = pai->pai_base.pi_obj;
3719f95f3e0SAlex Hornung 
3729f95f3e0SAlex Hornung 	_PROP_ASSERT(prop_object_is_array(pa));
3739f95f3e0SAlex Hornung 
3749f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
3759f95f3e0SAlex Hornung 	_prop_array_iterator_reset_locked(pai);
3769f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
3779f95f3e0SAlex Hornung }
3789f95f3e0SAlex Hornung 
3799f95f3e0SAlex Hornung /*
3809f95f3e0SAlex Hornung  * prop_array_create --
3819f95f3e0SAlex Hornung  *	Create an empty array.
3829f95f3e0SAlex Hornung  */
3839f95f3e0SAlex Hornung prop_array_t
prop_array_create(void)3849f95f3e0SAlex Hornung prop_array_create(void)
3859f95f3e0SAlex Hornung {
3869f95f3e0SAlex Hornung 
3879f95f3e0SAlex Hornung 	return (_prop_array_alloc(0));
3889f95f3e0SAlex Hornung }
3899f95f3e0SAlex Hornung 
3909f95f3e0SAlex Hornung /*
3919f95f3e0SAlex Hornung  * prop_array_create_with_capacity --
3929f95f3e0SAlex Hornung  *	Create an array with the capacity to store N objects.
3939f95f3e0SAlex Hornung  */
3949f95f3e0SAlex Hornung prop_array_t
prop_array_create_with_capacity(unsigned int capacity)3959f95f3e0SAlex Hornung prop_array_create_with_capacity(unsigned int capacity)
3969f95f3e0SAlex Hornung {
3979f95f3e0SAlex Hornung 
3989f95f3e0SAlex Hornung 	return (_prop_array_alloc(capacity));
3999f95f3e0SAlex Hornung }
4009f95f3e0SAlex Hornung 
4019f95f3e0SAlex Hornung /*
4029f95f3e0SAlex Hornung  * prop_array_copy --
4039f95f3e0SAlex Hornung  *	Copy an array.	The new array has an initial capacity equal to
4049f95f3e0SAlex Hornung  *	the number of objects stored in the original array.  The new
4059f95f3e0SAlex Hornung  *	array contains references to the original array's objects, not
4069f95f3e0SAlex Hornung  *	copies of those objects (i.e. a shallow copy).
4079f95f3e0SAlex Hornung  */
4089f95f3e0SAlex Hornung prop_array_t
prop_array_copy(prop_array_t opa)4099f95f3e0SAlex Hornung prop_array_copy(prop_array_t opa)
4109f95f3e0SAlex Hornung {
4119f95f3e0SAlex Hornung 	prop_array_t pa;
4129f95f3e0SAlex Hornung 	prop_object_t po;
4139f95f3e0SAlex Hornung 	unsigned int idx;
4149f95f3e0SAlex Hornung 
4159f95f3e0SAlex Hornung 	if (! prop_object_is_array(opa))
4169f95f3e0SAlex Hornung 		return (NULL);
4179f95f3e0SAlex Hornung 
4189f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
4199f95f3e0SAlex Hornung 
4209f95f3e0SAlex Hornung 	pa = _prop_array_alloc(opa->pa_count);
4219f95f3e0SAlex Hornung 	if (pa != NULL) {
4229f95f3e0SAlex Hornung 		for (idx = 0; idx < opa->pa_count; idx++) {
4239f95f3e0SAlex Hornung 			po = opa->pa_array[idx];
4249f95f3e0SAlex Hornung 			prop_object_retain(po);
4259f95f3e0SAlex Hornung 			pa->pa_array[idx] = po;
4269f95f3e0SAlex Hornung 		}
4279f95f3e0SAlex Hornung 		pa->pa_count = opa->pa_count;
4289f95f3e0SAlex Hornung 		pa->pa_flags = opa->pa_flags;
4299f95f3e0SAlex Hornung 	}
4309f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
4319f95f3e0SAlex Hornung 	return (pa);
4329f95f3e0SAlex Hornung }
4339f95f3e0SAlex Hornung 
4349f95f3e0SAlex Hornung /*
4359f95f3e0SAlex Hornung  * prop_array_copy_mutable --
4369f95f3e0SAlex Hornung  *	Like prop_array_copy(), but the resulting array is mutable.
4379f95f3e0SAlex Hornung  */
4389f95f3e0SAlex Hornung prop_array_t
prop_array_copy_mutable(prop_array_t opa)4399f95f3e0SAlex Hornung prop_array_copy_mutable(prop_array_t opa)
4409f95f3e0SAlex Hornung {
4419f95f3e0SAlex Hornung 	prop_array_t pa;
4429f95f3e0SAlex Hornung 
4439f95f3e0SAlex Hornung 	pa = prop_array_copy(opa);
4449f95f3e0SAlex Hornung 	if (pa != NULL)
4459f95f3e0SAlex Hornung 		pa->pa_flags &= ~PA_F_IMMUTABLE;
4469f95f3e0SAlex Hornung 
4479f95f3e0SAlex Hornung 	return (pa);
4489f95f3e0SAlex Hornung }
4499f95f3e0SAlex Hornung 
4509f95f3e0SAlex Hornung /*
4519f95f3e0SAlex Hornung  * prop_array_capacity --
4529f95f3e0SAlex Hornung  *	Return the capacity of the array.
4539f95f3e0SAlex Hornung  */
4549f95f3e0SAlex Hornung unsigned int
prop_array_capacity(prop_array_t pa)4559f95f3e0SAlex Hornung prop_array_capacity(prop_array_t pa)
4569f95f3e0SAlex Hornung {
4579f95f3e0SAlex Hornung 	unsigned int rv;
4589f95f3e0SAlex Hornung 
4599f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
4609f95f3e0SAlex Hornung 		return (0);
4619f95f3e0SAlex Hornung 
4629f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
4639f95f3e0SAlex Hornung 	rv = pa->pa_capacity;
4649f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
4659f95f3e0SAlex Hornung 
4669f95f3e0SAlex Hornung 	return (rv);
4679f95f3e0SAlex Hornung }
4689f95f3e0SAlex Hornung 
4699f95f3e0SAlex Hornung /*
4709f95f3e0SAlex Hornung  * prop_array_count --
4719f95f3e0SAlex Hornung  *	Return the number of objects stored in the array.
4729f95f3e0SAlex Hornung  */
4739f95f3e0SAlex Hornung unsigned int
prop_array_count(prop_array_t pa)4749f95f3e0SAlex Hornung prop_array_count(prop_array_t pa)
4759f95f3e0SAlex Hornung {
4769f95f3e0SAlex Hornung 	unsigned int rv;
4779f95f3e0SAlex Hornung 
4789f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
4799f95f3e0SAlex Hornung 		return (0);
4809f95f3e0SAlex Hornung 
4819f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
4829f95f3e0SAlex Hornung 	rv = pa->pa_count;
4839f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
4849f95f3e0SAlex Hornung 
4859f95f3e0SAlex Hornung 	return (rv);
4869f95f3e0SAlex Hornung }
4879f95f3e0SAlex Hornung 
4889f95f3e0SAlex Hornung /*
4899f95f3e0SAlex Hornung  * prop_array_ensure_capacity --
4909f95f3e0SAlex Hornung  *	Ensure that the array has the capacity to store the specified
4919f95f3e0SAlex Hornung  *	total number of objects (inluding the objects already stored
4929f95f3e0SAlex Hornung  *	in the array).
4939f95f3e0SAlex Hornung  */
4949f95f3e0SAlex Hornung bool
prop_array_ensure_capacity(prop_array_t pa,unsigned int capacity)4959f95f3e0SAlex Hornung prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
4969f95f3e0SAlex Hornung {
4979f95f3e0SAlex Hornung 	bool rv;
4989f95f3e0SAlex Hornung 
4999f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
5009f95f3e0SAlex Hornung 		return (false);
5019f95f3e0SAlex Hornung 
5029f95f3e0SAlex Hornung 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
5039f95f3e0SAlex Hornung 	if (capacity > pa->pa_capacity)
5049f95f3e0SAlex Hornung 		rv = _prop_array_expand(pa, capacity);
5059f95f3e0SAlex Hornung 	else
5069f95f3e0SAlex Hornung 		rv = true;
5079f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5089f95f3e0SAlex Hornung 
5099f95f3e0SAlex Hornung 	return (rv);
5109f95f3e0SAlex Hornung }
5119f95f3e0SAlex Hornung 
5129f95f3e0SAlex Hornung static prop_object_iterator_t
_prop_array_iterator_locked(prop_array_t pa)5139f95f3e0SAlex Hornung _prop_array_iterator_locked(prop_array_t pa)
5149f95f3e0SAlex Hornung {
5159f95f3e0SAlex Hornung 	struct _prop_array_iterator *pai;
5169f95f3e0SAlex Hornung 
5179f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
5189f95f3e0SAlex Hornung 		return (NULL);
5199f95f3e0SAlex Hornung 
5209f95f3e0SAlex Hornung 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
5219f95f3e0SAlex Hornung 	if (pai == NULL)
5229f95f3e0SAlex Hornung 		return (NULL);
5239f95f3e0SAlex Hornung 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
5249f95f3e0SAlex Hornung 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
5259f95f3e0SAlex Hornung 	prop_object_retain(pa);
5269f95f3e0SAlex Hornung 	pai->pai_base.pi_obj = pa;
5279f95f3e0SAlex Hornung 	_prop_array_iterator_reset_locked(pai);
5289f95f3e0SAlex Hornung 
5299f95f3e0SAlex Hornung 	return (&pai->pai_base);
5309f95f3e0SAlex Hornung }
5319f95f3e0SAlex Hornung 
5329f95f3e0SAlex Hornung /*
5339f95f3e0SAlex Hornung  * prop_array_iterator --
5349f95f3e0SAlex Hornung  *	Return an iterator for the array.  The array is retained by
5359f95f3e0SAlex Hornung  *	the iterator.
5369f95f3e0SAlex Hornung  */
5379f95f3e0SAlex Hornung prop_object_iterator_t
prop_array_iterator(prop_array_t pa)5389f95f3e0SAlex Hornung prop_array_iterator(prop_array_t pa)
5399f95f3e0SAlex Hornung {
5409f95f3e0SAlex Hornung 	prop_object_iterator_t pi;
5419f95f3e0SAlex Hornung 
5429f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5439f95f3e0SAlex Hornung 	pi = _prop_array_iterator_locked(pa);
5449f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5459f95f3e0SAlex Hornung 	return (pi);
5469f95f3e0SAlex Hornung }
5479f95f3e0SAlex Hornung 
5489f95f3e0SAlex Hornung /*
5499f95f3e0SAlex Hornung  * prop_array_make_immutable --
5509f95f3e0SAlex Hornung  *	Make the array immutable.
5519f95f3e0SAlex Hornung  */
5529f95f3e0SAlex Hornung void
prop_array_make_immutable(prop_array_t pa)5539f95f3e0SAlex Hornung prop_array_make_immutable(prop_array_t pa)
5549f95f3e0SAlex Hornung {
5559f95f3e0SAlex Hornung 
5569f95f3e0SAlex Hornung 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
5579f95f3e0SAlex Hornung 	if (prop_array_is_immutable(pa) == false)
5589f95f3e0SAlex Hornung 		pa->pa_flags |= PA_F_IMMUTABLE;
5599f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5609f95f3e0SAlex Hornung }
5619f95f3e0SAlex Hornung 
5629f95f3e0SAlex Hornung /*
5639f95f3e0SAlex Hornung  * prop_array_mutable --
5649f95f3e0SAlex Hornung  *	Returns true if the array is mutable.
5659f95f3e0SAlex Hornung  */
5669f95f3e0SAlex Hornung bool
prop_array_mutable(prop_array_t pa)5679f95f3e0SAlex Hornung prop_array_mutable(prop_array_t pa)
5689f95f3e0SAlex Hornung {
5699f95f3e0SAlex Hornung 	bool rv;
5709f95f3e0SAlex Hornung 
5719f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5729f95f3e0SAlex Hornung 	rv = prop_array_is_immutable(pa) == false;
5739f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5749f95f3e0SAlex Hornung 
5759f95f3e0SAlex Hornung 	return (rv);
5769f95f3e0SAlex Hornung }
5779f95f3e0SAlex Hornung 
5789f95f3e0SAlex Hornung /*
5799f95f3e0SAlex Hornung  * prop_array_get --
5809f95f3e0SAlex Hornung  *	Return the object stored at the specified array index.
5819f95f3e0SAlex Hornung  */
5829f95f3e0SAlex Hornung prop_object_t
prop_array_get(prop_array_t pa,unsigned int idx)5839f95f3e0SAlex Hornung prop_array_get(prop_array_t pa, unsigned int idx)
5849f95f3e0SAlex Hornung {
5859f95f3e0SAlex Hornung 	prop_object_t po = NULL;
5869f95f3e0SAlex Hornung 
5879f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
5889f95f3e0SAlex Hornung 		return (NULL);
5899f95f3e0SAlex Hornung 
5909f95f3e0SAlex Hornung 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5919f95f3e0SAlex Hornung 	if (idx >= pa->pa_count)
5929f95f3e0SAlex Hornung 		goto out;
5939f95f3e0SAlex Hornung 	po = pa->pa_array[idx];
5949f95f3e0SAlex Hornung 	_PROP_ASSERT(po != NULL);
5959f95f3e0SAlex Hornung  out:
5969f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5979f95f3e0SAlex Hornung 	return (po);
5989f95f3e0SAlex Hornung }
5999f95f3e0SAlex Hornung 
6009f95f3e0SAlex Hornung static bool
_prop_array_add(prop_array_t pa,prop_object_t po)6019f95f3e0SAlex Hornung _prop_array_add(prop_array_t pa, prop_object_t po)
6029f95f3e0SAlex Hornung {
6039f95f3e0SAlex Hornung 
6049f95f3e0SAlex Hornung 	/*
6059f95f3e0SAlex Hornung 	 * Array must be WRITE-LOCKED.
6069f95f3e0SAlex Hornung 	 */
6079f95f3e0SAlex Hornung 
6089f95f3e0SAlex Hornung 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
6099f95f3e0SAlex Hornung 
6109f95f3e0SAlex Hornung 	if (prop_array_is_immutable(pa) ||
6119f95f3e0SAlex Hornung 	    (pa->pa_count == pa->pa_capacity &&
6129f95f3e0SAlex Hornung 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
6139f95f3e0SAlex Hornung 		return (false);
6149f95f3e0SAlex Hornung 
6159f95f3e0SAlex Hornung 	prop_object_retain(po);
6169f95f3e0SAlex Hornung 	pa->pa_array[pa->pa_count++] = po;
6179f95f3e0SAlex Hornung 	pa->pa_version++;
6189f95f3e0SAlex Hornung 
6199f95f3e0SAlex Hornung 	return (true);
6209f95f3e0SAlex Hornung }
6219f95f3e0SAlex Hornung 
6229f95f3e0SAlex Hornung /*
6239f95f3e0SAlex Hornung  * prop_array_set --
6249f95f3e0SAlex Hornung  *	Store a reference to an object at the specified array index.
6259f95f3e0SAlex Hornung  *	This method is not allowed to create holes in the array; the
6269f95f3e0SAlex Hornung  *	caller must either be setting the object just beyond the existing
6279f95f3e0SAlex Hornung  *	count or replacing an already existing object reference.
6289f95f3e0SAlex Hornung  */
6299f95f3e0SAlex Hornung bool
prop_array_set(prop_array_t pa,unsigned int idx,prop_object_t po)6309f95f3e0SAlex Hornung prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
6319f95f3e0SAlex Hornung {
6329f95f3e0SAlex Hornung 	prop_object_t opo;
6339f95f3e0SAlex Hornung 	bool rv = false;
6349f95f3e0SAlex Hornung 
6359f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
6369f95f3e0SAlex Hornung 		return (false);
6379f95f3e0SAlex Hornung 
6389f95f3e0SAlex Hornung 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
6399f95f3e0SAlex Hornung 
6409f95f3e0SAlex Hornung 	if (prop_array_is_immutable(pa))
6419f95f3e0SAlex Hornung 		goto out;
6429f95f3e0SAlex Hornung 
6439f95f3e0SAlex Hornung 	if (idx == pa->pa_count) {
6449f95f3e0SAlex Hornung 		rv = _prop_array_add(pa, po);
6459f95f3e0SAlex Hornung 		goto out;
6469f95f3e0SAlex Hornung 	}
6479f95f3e0SAlex Hornung 
6489f95f3e0SAlex Hornung 	_PROP_ASSERT(idx < pa->pa_count);
6499f95f3e0SAlex Hornung 
6509f95f3e0SAlex Hornung 	opo = pa->pa_array[idx];
6519f95f3e0SAlex Hornung 	_PROP_ASSERT(opo != NULL);
6529f95f3e0SAlex Hornung 
6539f95f3e0SAlex Hornung 	prop_object_retain(po);
6549f95f3e0SAlex Hornung 	pa->pa_array[idx] = po;
6559f95f3e0SAlex Hornung 	pa->pa_version++;
6569f95f3e0SAlex Hornung 
6579f95f3e0SAlex Hornung 	prop_object_release(opo);
6589f95f3e0SAlex Hornung 
6599f95f3e0SAlex Hornung 	rv = true;
6609f95f3e0SAlex Hornung 
6619f95f3e0SAlex Hornung  out:
6629f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
6639f95f3e0SAlex Hornung 	return (rv);
6649f95f3e0SAlex Hornung }
6659f95f3e0SAlex Hornung 
6669f95f3e0SAlex Hornung /*
6679f95f3e0SAlex Hornung  * prop_array_add --
6689f95f3e0SAlex Hornung  *	Add a reference to an object to the specified array, appending
6699f95f3e0SAlex Hornung  *	to the end and growing the array's capacity, if necessary.
6709f95f3e0SAlex Hornung  */
6719f95f3e0SAlex Hornung bool
prop_array_add(prop_array_t pa,prop_object_t po)6729f95f3e0SAlex Hornung prop_array_add(prop_array_t pa, prop_object_t po)
6739f95f3e0SAlex Hornung {
6749f95f3e0SAlex Hornung 	bool rv;
6759f95f3e0SAlex Hornung 
6769f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
6779f95f3e0SAlex Hornung 		return (false);
6789f95f3e0SAlex Hornung 
6799f95f3e0SAlex Hornung 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
6809f95f3e0SAlex Hornung 	rv = _prop_array_add(pa, po);
6819f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
6829f95f3e0SAlex Hornung 
6839f95f3e0SAlex Hornung 	return (rv);
6849f95f3e0SAlex Hornung }
6859f95f3e0SAlex Hornung 
6869f95f3e0SAlex Hornung /*
6879f95f3e0SAlex Hornung  * prop_array_remove --
6889f95f3e0SAlex Hornung  *	Remove the reference to an object from an array at the specified
6899f95f3e0SAlex Hornung  *	index.	The array will be compacted following the removal.
6909f95f3e0SAlex Hornung  */
6919f95f3e0SAlex Hornung void
prop_array_remove(prop_array_t pa,unsigned int idx)6929f95f3e0SAlex Hornung prop_array_remove(prop_array_t pa, unsigned int idx)
6939f95f3e0SAlex Hornung {
6949f95f3e0SAlex Hornung 	prop_object_t po;
6959f95f3e0SAlex Hornung 
6969f95f3e0SAlex Hornung 	if (! prop_object_is_array(pa))
6979f95f3e0SAlex Hornung 		return;
6989f95f3e0SAlex Hornung 
6999f95f3e0SAlex Hornung 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
7009f95f3e0SAlex Hornung 
7019f95f3e0SAlex Hornung 	_PROP_ASSERT(idx < pa->pa_count);
7029f95f3e0SAlex Hornung 
7039f95f3e0SAlex Hornung 	/* XXX Should this be a _PROP_ASSERT()? */
7049f95f3e0SAlex Hornung 	if (prop_array_is_immutable(pa)) {
7059f95f3e0SAlex Hornung 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
7069f95f3e0SAlex Hornung 		return;
7079f95f3e0SAlex Hornung 	}
7089f95f3e0SAlex Hornung 
7099f95f3e0SAlex Hornung 	po = pa->pa_array[idx];
7109f95f3e0SAlex Hornung 	_PROP_ASSERT(po != NULL);
7119f95f3e0SAlex Hornung 
7129f95f3e0SAlex Hornung 	for (++idx; idx < pa->pa_count; idx++)
7139f95f3e0SAlex Hornung 		pa->pa_array[idx - 1] = pa->pa_array[idx];
7149f95f3e0SAlex Hornung 	pa->pa_count--;
7159f95f3e0SAlex Hornung 	pa->pa_version++;
7169f95f3e0SAlex Hornung 
7179f95f3e0SAlex Hornung 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
7189f95f3e0SAlex Hornung 
7199f95f3e0SAlex Hornung 	prop_object_release(po);
7209f95f3e0SAlex Hornung }
7219f95f3e0SAlex Hornung 
7229f95f3e0SAlex Hornung /*
7239f95f3e0SAlex Hornung  * prop_array_equals --
7249f95f3e0SAlex Hornung  *	Return true if the two arrays are equivalent.  Note we do a
7259f95f3e0SAlex Hornung  *	by-value comparison of the objects in the array.
7269f95f3e0SAlex Hornung  */
7279f95f3e0SAlex Hornung bool
prop_array_equals(prop_array_t array1,prop_array_t array2)7289f95f3e0SAlex Hornung prop_array_equals(prop_array_t array1, prop_array_t array2)
7299f95f3e0SAlex Hornung {
7309f95f3e0SAlex Hornung 	if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
7319f95f3e0SAlex Hornung 		return (false);
7329f95f3e0SAlex Hornung 
7339f95f3e0SAlex Hornung 	return (prop_object_equals(array1, array2));
7349f95f3e0SAlex Hornung }
7359f95f3e0SAlex Hornung 
7369f95f3e0SAlex Hornung /*
7379f95f3e0SAlex Hornung  * prop_array_externalize --
7389f95f3e0SAlex Hornung  *	Externalize an array, return a NUL-terminated buffer
7399f95f3e0SAlex Hornung  *	containing the XML-style representation.  The buffer is allocated
7409f95f3e0SAlex Hornung  *	with the M_TEMP memory type.
7419f95f3e0SAlex Hornung  */
7429f95f3e0SAlex Hornung char *
prop_array_externalize(prop_array_t pa)7439f95f3e0SAlex Hornung prop_array_externalize(prop_array_t pa)
7449f95f3e0SAlex Hornung {
7459f95f3e0SAlex Hornung 	struct _prop_object_externalize_context *ctx;
7469f95f3e0SAlex Hornung 	char *cp;
7479f95f3e0SAlex Hornung 
7489f95f3e0SAlex Hornung 	ctx = _prop_object_externalize_context_alloc();
7499f95f3e0SAlex Hornung 	if (ctx == NULL)
7509f95f3e0SAlex Hornung 		return (NULL);
7519f95f3e0SAlex Hornung 
7529f95f3e0SAlex Hornung 	if (_prop_object_externalize_header(ctx) == false ||
7539f95f3e0SAlex Hornung 	    (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
7549f95f3e0SAlex Hornung 	    _prop_object_externalize_footer(ctx) == false) {
7559f95f3e0SAlex Hornung 		/* We are responsible for releasing the buffer. */
7569f95f3e0SAlex Hornung 		_PROP_FREE(ctx->poec_buf, M_TEMP);
7579f95f3e0SAlex Hornung 		_prop_object_externalize_context_free(ctx);
7589f95f3e0SAlex Hornung 		return (NULL);
7599f95f3e0SAlex Hornung 	}
7609f95f3e0SAlex Hornung 
7619f95f3e0SAlex Hornung 	cp = ctx->poec_buf;
7629f95f3e0SAlex Hornung 	_prop_object_externalize_context_free(ctx);
7639f95f3e0SAlex Hornung 
7649f95f3e0SAlex Hornung 	return (cp);
7659f95f3e0SAlex Hornung }
7669f95f3e0SAlex Hornung 
7679f95f3e0SAlex Hornung /*
7689f95f3e0SAlex Hornung  * _prop_array_internalize --
7699f95f3e0SAlex Hornung  *	Parse an <array>...</array> and return the object created from the
7709f95f3e0SAlex Hornung  *	external representation.
7719f95f3e0SAlex Hornung  */
7729f95f3e0SAlex Hornung static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
7739f95f3e0SAlex Hornung     struct _prop_object_internalize_context *);
7749f95f3e0SAlex Hornung 
7759f95f3e0SAlex Hornung bool
_prop_array_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)7769f95f3e0SAlex Hornung _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
7779f95f3e0SAlex Hornung     struct _prop_object_internalize_context *ctx)
7789f95f3e0SAlex Hornung {
7799f95f3e0SAlex Hornung 	/* We don't currently understand any attributes. */
7809f95f3e0SAlex Hornung 	if (ctx->poic_tagattr != NULL)
7819f95f3e0SAlex Hornung 		return (true);
7829f95f3e0SAlex Hornung 
7839f95f3e0SAlex Hornung 	*obj = prop_array_create();
7849f95f3e0SAlex Hornung 	/*
7859f95f3e0SAlex Hornung 	 * We are done if the create failed or no child elements exist.
7869f95f3e0SAlex Hornung 	 */
7879f95f3e0SAlex Hornung 	if (*obj == NULL || ctx->poic_is_empty_element)
7889f95f3e0SAlex Hornung 		return (true);
7899f95f3e0SAlex Hornung 
7909f95f3e0SAlex Hornung 	/*
7919f95f3e0SAlex Hornung 	 * Opening tag is found, now continue to the first element.
7929f95f3e0SAlex Hornung 	 */
7939f95f3e0SAlex Hornung 	return (_prop_array_internalize_body(stack, obj, ctx));
7949f95f3e0SAlex Hornung }
7959f95f3e0SAlex Hornung 
7969f95f3e0SAlex Hornung static bool
_prop_array_internalize_continue(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx,void * data,prop_object_t child)7979f95f3e0SAlex Hornung _prop_array_internalize_continue(prop_stack_t stack,
7989f95f3e0SAlex Hornung     prop_object_t *obj,
7999f95f3e0SAlex Hornung     struct _prop_object_internalize_context *ctx,
8009f95f3e0SAlex Hornung     void *data, prop_object_t child)
8019f95f3e0SAlex Hornung {
8029f95f3e0SAlex Hornung 	prop_array_t array;
8039f95f3e0SAlex Hornung 
8049f95f3e0SAlex Hornung 	_PROP_ASSERT(data == NULL);
8059f95f3e0SAlex Hornung 
8069f95f3e0SAlex Hornung 	if (child == NULL)
8079f95f3e0SAlex Hornung 		goto bad; /* Element could not be parsed. */
8089f95f3e0SAlex Hornung 
8099f95f3e0SAlex Hornung 	array = *obj;
8109f95f3e0SAlex Hornung 
8119f95f3e0SAlex Hornung 	if (prop_array_add(array, child) == false) {
8129f95f3e0SAlex Hornung 		prop_object_release(child);
8139f95f3e0SAlex Hornung 		goto bad;
8149f95f3e0SAlex Hornung 	}
8159f95f3e0SAlex Hornung 	prop_object_release(child);
8169f95f3e0SAlex Hornung 
8179f95f3e0SAlex Hornung 	/*
8189f95f3e0SAlex Hornung 	 * Current element is processed and added, look for next.
8199f95f3e0SAlex Hornung 	 */
8209f95f3e0SAlex Hornung 	return (_prop_array_internalize_body(stack, obj, ctx));
8219f95f3e0SAlex Hornung 
8229f95f3e0SAlex Hornung  bad:
8239f95f3e0SAlex Hornung 	prop_object_release(*obj);
8249f95f3e0SAlex Hornung 	*obj = NULL;
8259f95f3e0SAlex Hornung 	return (true);
8269f95f3e0SAlex Hornung }
8279f95f3e0SAlex Hornung 
8289f95f3e0SAlex Hornung static bool
_prop_array_internalize_body(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)8299f95f3e0SAlex Hornung _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
8309f95f3e0SAlex Hornung     struct _prop_object_internalize_context *ctx)
8319f95f3e0SAlex Hornung {
8329f95f3e0SAlex Hornung 	prop_array_t array = *obj;
8339f95f3e0SAlex Hornung 
8349f95f3e0SAlex Hornung 	_PROP_ASSERT(array != NULL);
8359f95f3e0SAlex Hornung 
8369f95f3e0SAlex Hornung 	/* Fetch the next tag. */
8379f95f3e0SAlex Hornung 	if (_prop_object_internalize_find_tag(ctx, NULL,
8389f95f3e0SAlex Hornung 				_PROP_TAG_TYPE_EITHER) == false)
8399f95f3e0SAlex Hornung 		goto bad;
8409f95f3e0SAlex Hornung 
8419f95f3e0SAlex Hornung 	/* Check to see if this is the end of the array. */
8429f95f3e0SAlex Hornung 	if (_PROP_TAG_MATCH(ctx, "array") &&
8439f95f3e0SAlex Hornung 	    ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
8449f95f3e0SAlex Hornung 		/* It is, so don't iterate any further. */
8459f95f3e0SAlex Hornung 		return (true);
8469f95f3e0SAlex Hornung 	}
8479f95f3e0SAlex Hornung 
8489f95f3e0SAlex Hornung 	if (_prop_stack_push(stack, array,
8499f95f3e0SAlex Hornung 			     _prop_array_internalize_continue, NULL, NULL))
8509f95f3e0SAlex Hornung 		return (false);
8519f95f3e0SAlex Hornung 
8529f95f3e0SAlex Hornung  bad:
8539f95f3e0SAlex Hornung 	prop_object_release(array);
8549f95f3e0SAlex Hornung 	*obj = NULL;
8559f95f3e0SAlex Hornung 	return (true);
8569f95f3e0SAlex Hornung }
8579f95f3e0SAlex Hornung 
8589f95f3e0SAlex Hornung /*
8599f95f3e0SAlex Hornung  * prop_array_internalize --
8609f95f3e0SAlex Hornung  *	Create an array by parsing the XML-style representation.
8619f95f3e0SAlex Hornung  */
8629f95f3e0SAlex Hornung prop_array_t
prop_array_internalize(const char * xml)8639f95f3e0SAlex Hornung prop_array_internalize(const char *xml)
8649f95f3e0SAlex Hornung {
8659f95f3e0SAlex Hornung 	return _prop_generic_internalize(xml, "array");
8669f95f3e0SAlex Hornung }
8679f95f3e0SAlex Hornung 
8689f95f3e0SAlex Hornung #if !defined(_KERNEL) && !defined(_STANDALONE)
8699f95f3e0SAlex Hornung /*
8709f95f3e0SAlex Hornung  * prop_array_externalize_to_file --
8719f95f3e0SAlex Hornung  *	Externalize an array to the specified file.
8729f95f3e0SAlex Hornung  */
8739f95f3e0SAlex Hornung bool
prop_array_externalize_to_file(prop_array_t array,const char * fname)8749f95f3e0SAlex Hornung prop_array_externalize_to_file(prop_array_t array, const char *fname)
8759f95f3e0SAlex Hornung {
8769f95f3e0SAlex Hornung 	char *xml;
8779f95f3e0SAlex Hornung 	bool rv;
8789f95f3e0SAlex Hornung 	int save_errno = 0;	/* XXXGCC -Wuninitialized [mips, ...] */
8799f95f3e0SAlex Hornung 
8809f95f3e0SAlex Hornung 	xml = prop_array_externalize(array);
8819f95f3e0SAlex Hornung 	if (xml == NULL)
8829f95f3e0SAlex Hornung 		return (false);
8839f95f3e0SAlex Hornung 	rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
8849f95f3e0SAlex Hornung 	if (rv == false)
8859f95f3e0SAlex Hornung 		save_errno = errno;
8869f95f3e0SAlex Hornung 	_PROP_FREE(xml, M_TEMP);
8879f95f3e0SAlex Hornung 	if (rv == false)
8889f95f3e0SAlex Hornung 		errno = save_errno;
8899f95f3e0SAlex Hornung 
8909f95f3e0SAlex Hornung 	return (rv);
8919f95f3e0SAlex Hornung }
8929f95f3e0SAlex Hornung 
8939f95f3e0SAlex Hornung /*
8949f95f3e0SAlex Hornung  * prop_array_internalize_from_file --
8959f95f3e0SAlex Hornung  *	Internalize an array from a file.
8969f95f3e0SAlex Hornung  */
8979f95f3e0SAlex Hornung prop_array_t
prop_array_internalize_from_file(const char * fname)8989f95f3e0SAlex Hornung prop_array_internalize_from_file(const char *fname)
8999f95f3e0SAlex Hornung {
9009f95f3e0SAlex Hornung 	struct _prop_object_internalize_mapped_file *mf;
9019f95f3e0SAlex Hornung 	prop_array_t array;
9029f95f3e0SAlex Hornung 
9039f95f3e0SAlex Hornung 	mf = _prop_object_internalize_map_file(fname);
9049f95f3e0SAlex Hornung 	if (mf == NULL)
9059f95f3e0SAlex Hornung 		return (NULL);
9069f95f3e0SAlex Hornung 	array = prop_array_internalize(mf->poimf_xml);
9079f95f3e0SAlex Hornung 	_prop_object_internalize_unmap_file(mf);
9089f95f3e0SAlex Hornung 
9099f95f3e0SAlex Hornung 	return (array);
9109f95f3e0SAlex Hornung }
9119f95f3e0SAlex Hornung #endif /* _KERNEL && !_STANDALONE */
912