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