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