| /* $Id$ | |
| * | |
| * Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to you under the Apache License, Version | |
| * 2.0 (the "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| /* | |
| * etch_arrayval.c -- etch_arrayvalue implementation. | |
| * | |
| * todo: modify this class to permit using an etch_nativearray as the arrayvalue | |
| * backing store. this could be very useful for large arrays of small values, | |
| * where not all values are accessed individually. the key to this conversion | |
| * is always returning a non-disposable object from get(), and we ensure this | |
| * by always returnings item[i] from the arraylist. when a get(i) is requested, | |
| * we check the arraylist first, lazy-allocating it if necessary. if arraylist[i] | |
| * is null, we populate arraylist[i] from natarray[i]. we then return arraylist[i] | |
| * which is always non-disposable. | |
| */ | |
| #include "etch_arrayval.h" | |
| #include "etch_global.h" | |
| #include "etch_syncobj.h" | |
| #include "etch_tagdata.h" | |
| #include "etchexcp.h" | |
| etch_arrayvalue* new_arrayvalue_init(const int, const int, const int, const int); | |
| etch_arrayvalue* populate_arrayvalue_from(etch_arrayvalue*); | |
| unsigned short etch_itemtype_to_arrayclass(unsigned short item_obj_type); | |
| int array_value_add(etch_arrayvalue* thisp, ETCH_ARRAY_ELEMENT* content); | |
| /** | |
| * new_arrayvalue() | |
| * primary constructor for etch_arrayvalue | |
| * @param type_code wire ID of the array content class. | |
| * @param custom_struct_type non-disposable type of custom struct, | |
| caller retains ownership as with all types. | |
| */ | |
| etch_arrayvalue* new_arrayvalue (const byte type_code, etch_type* custom_struct_type, | |
| const int dim, const int initsize, const int deltsize, | |
| const int is_readonly, const int is_synchronized) | |
| { | |
| etch_arrayvalue* newobj = new_arrayvalue_init | |
| (initsize, deltsize, is_readonly, is_synchronized); | |
| newobj->dim = dim; | |
| newobj->type_code = type_code; | |
| newobj->class_id = etch_arraytype_to_classid (type_code); | |
| newobj->custom_struct_type = custom_struct_type; /* not owned */ | |
| return newobj; | |
| } | |
| /** | |
| * new_arrayvalue_from() | |
| * etch_arrayvalue constructor - builds arryavalue from an etch_nativearray. | |
| * when native array is multi-dimensioned, this constructor is invoked recursively. | |
| * todo: convert this to use the subarray call, which this code duplicates. | |
| * todo: add a parameter to permit the arrayvalue to remain unpopulated; i.e., | |
| * the nativearray is present but the object array is not yet populated. | |
| */ | |
| etch_arrayvalue* new_arrayvalue_from (etch_nativearray* natarray, | |
| const signed char type_code, etch_type* custom_struct_type, | |
| const int initsize, const int deltsize, const int is_readonly) | |
| { | |
| const int SUBARRAY_NUMDIMS = natarray->numdims - 1; | |
| const size_t SUBARRAY_COUNT = natarray->dimension[SUBARRAY_NUMDIMS]; | |
| const size_t SUBARRAY_BYTELEN = natarray->dimsize [SUBARRAY_NUMDIMS]; | |
| int i = 0; | |
| etch_arrayvalue* newav = NULL; /* nativearray currently max 3 dims*/ | |
| if (natarray->is_null) return NULL; | |
| if (SUBARRAY_NUMDIMS < 0 || SUBARRAY_NUMDIMS > 2) return NULL; | |
| newav = new_arrayvalue_init(initsize, deltsize, is_readonly, FALSE); | |
| newav->is_array_owned = !is_readonly; /* does av own nativearray */ | |
| newav->type_code = type_code; /* external array content type */ | |
| newav->class_id = etch_arraytype_to_classid (type_code); | |
| newav->natarray = natarray; | |
| newav->dim = natarray->numdims; | |
| newav->class_id = natarray->class_id; /* validator expects class match */ | |
| newav->custom_struct_type = custom_struct_type; /* not owned */ | |
| if (SUBARRAY_NUMDIMS == 0) /* if single dimension, populate values */ | |
| { | |
| newav = populate_arrayvalue_from(newav); | |
| } | |
| else | |
| { newav->content_obj_type = ETCHTYPEB_ARRAYVAL; | |
| newav->content_item_size = sizeof(void*); | |
| for(; i < (const int) SUBARRAY_COUNT; i++) | |
| { | |
| /* the native array was multi-dimensioned. we therefore add values | |
| * to this arrayvalue, which are arrayalues of one dimension less than | |
| * that of the parent arrayvalue. the sub-arrayvalues are created from | |
| * etch_nativearrays created from offset pointers into the parent | |
| * native array byte vector. sub-arrays therefore do not own content. | |
| */ | |
| const int itemcount = (int) natarray->dimension[SUBARRAY_NUMDIMS-1]; | |
| const size_t vector_offset = i * SUBARRAY_BYTELEN; | |
| byte* subvector = (byte*) natarray->values + vector_offset; | |
| etch_arrayvalue* subav = NULL; | |
| /* create a sub-array. note we pass a possibly unused dimension | |
| * value in order to avoid the extra logic to not do so */ | |
| etch_nativearray* newarray = new_nativearray_from(subvector, natarray->class_id, | |
| natarray->itemsize, SUBARRAY_NUMDIMS, | |
| (int) natarray->dimension[0], (int) natarray->dimension[1], 0); | |
| newarray->content_class_id = natarray->content_class_id; | |
| newarray->content_obj_type = natarray->content_obj_type; | |
| newarray->is_content_owned = FALSE; /* pointer into parent vector */ | |
| newarray->counts[0] = newarray->counts[0]; /* move counts in case */ | |
| newarray->counts[1] = newarray->counts[1]; /* caller is using them */ | |
| newarray->counts[2] = 0; | |
| subav = new_arrayvalue_from /* recursively create a sub-arrayvalue */ | |
| (newarray, type_code, custom_struct_type, itemcount, 0, is_readonly); | |
| arrayvalue_add(newav, (ETCH_ARRAY_ELEMENT*) subav); | |
| } | |
| } | |
| return newav; | |
| } | |
| /** | |
| * new_arrayvalue_default() | |
| * default constructor for etch_arrayvalue | |
| */ | |
| etch_arrayvalue* new_arrayvalue_default () | |
| { | |
| etch_arrayvalue* newobj = new_arrayvalue_init | |
| (ETCH_ARRAYVALUE_DEFAULT_INITSIZE, | |
| ETCH_ARRAYVALUE_DEFAULT_DELTSIZE, | |
| ETCH_ARRAYVALUE_DEFAULT_READONLY, | |
| ETCH_ARRAYVALUE_DEFAULT_SYNCHRONIZED); | |
| return newobj; | |
| } | |
| /** | |
| * new_arrayvalue_init() | |
| * common initialization on etch_arrayvalue construction. | |
| */ | |
| etch_arrayvalue* new_arrayvalue_init (const int initsize, const int deltsize, | |
| const int is_readonly, const int is_synchronized) | |
| { | |
| etch_arrayvalue* newobj = (etch_arrayvalue*) new_object(sizeof(etch_arrayvalue), | |
| ETCHTYPEB_ARRAYVAL, CLASSID_ARRAYVALUE); | |
| newobj->destroy = destroy_arrayvalue; | |
| newobj->clone = clone_null; | |
| /* the underlying arraylist is marked as content type object, meaning we can | |
| * interpret content as etchobject and call methods on the object accordingly, | |
| * most notably destroy(). when is_readonly is true, the underlying list will | |
| * not free memory for its content when the list is destroyed. | |
| */ | |
| newobj->list = new_arrayvalue_arraylist | |
| (initsize, deltsize, is_readonly, is_synchronized); | |
| return newobj; | |
| } | |
| /** | |
| * destroy_array_value() | |
| * destructor for an etch_arrayvalue object | |
| */ | |
| int destroy_arrayvalue (etch_arrayvalue* thisp) | |
| { | |
| if ((thisp->refcount > 0) && (--thisp->refcount > 0)) return -1; | |
| if (!is_etchobj_static_content(thisp)) | |
| { | |
| if (thisp->natarray && thisp->is_array_owned) | |
| thisp->natarray->destroy(thisp->natarray); | |
| if (thisp->list) | |
| thisp->list->destroy(thisp->list); | |
| } | |
| destroy_objectex((objmask*)thisp); | |
| return 0; | |
| } | |
| /** | |
| * populate_arrayvalue_from() | |
| * populate the specified arrayvalue from its attached single-dimensioned native array | |
| */ | |
| etch_arrayvalue* populate_arrayvalue_from (etch_arrayvalue* av) | |
| { | |
| etch_nativearray* nat = av->natarray; | |
| const int numentries = (int) nat->dimension[0]; | |
| objmask* wrapped_value = NULL; | |
| int i = 0, result = 0; | |
| if (nat->numdims != 1) return NULL; | |
| av->content_obj_type = nat->content_obj_type; | |
| av->content_item_size = (short) nat->itemsize; | |
| for(; i < numentries; i++) | |
| { | |
| result = etch_nativearray_get_wrapped_component(nat, i, &wrapped_value); | |
| arrayvalue_add(av, (ETCH_ARRAY_ELEMENT*) wrapped_value); | |
| } | |
| return av; | |
| } | |
| /** | |
| * arrayvalue3_to_nativearray() | |
| * convert an arrayvalue of dimension 3 to a native array. assumes that an | |
| * appropriately sized and configured etch_nativearray object is resident in | |
| * the arrayvalue object. | |
| */ | |
| int arrayvalue3_to_nativearray(etch_arrayvalue* av2) | |
| { | |
| const int item2count = arrayvalue_count(av2); | |
| int item1count = 0, item0count = 0; | |
| etch_nativearray* natv = av2->natarray; | |
| etch_object* wrapper = NULL; | |
| etch_arrayvalue *av1 = NULL, *av0 = NULL; | |
| int i, j, k, items=0; | |
| for(i=0; i < item2count; i++) | |
| { | |
| av1 = arrayvalue_get(av2, i); | |
| if (!is_etch_arrayvalue(av1)) return -1; | |
| item1count = arrayvalue_count(av1); | |
| for(j=0; j < (const int) item1count; j++) | |
| { | |
| av0 = arrayvalue_get(av1, j); | |
| if (!is_etch_arrayvalue(av0)) return -1; | |
| item0count = arrayvalue_count(av0); | |
| for(k=0; k < (const int) item0count; k++) | |
| { /* insert native values into nativearray byte vector. we mask the | |
| * wrapped primitive with an etch_object. we can do so because the | |
| * etch primitive object is guaranteed to offset its value the | |
| * same as that of an etch_object, right after the object header. | |
| */ | |
| if (NULL == (wrapper = arrayvalue_get(av0, k))) return -1; | |
| if (0 == natv->put3(natv, &wrapper->value, i, j, k)) | |
| items++; | |
| else return -1; | |
| } | |
| } | |
| } | |
| return items; | |
| } | |
| /** | |
| * arrayvalue2_to_nativearray() | |
| * convert an arrayvalue of dimension 2 to a native array. assumes that an | |
| * appropriately sized and configured etch_nativearray object is resident in | |
| * the arrayvalue object. | |
| */ | |
| int arrayvalue2_to_nativearray(etch_arrayvalue* av1) | |
| { | |
| const int item1count = arrayvalue_count(av1); | |
| int item0count = 0; | |
| etch_nativearray* natv = av1->natarray; | |
| etch_object* wrapper = NULL; | |
| etch_arrayvalue *av0 = NULL; | |
| int i, j, items=0; | |
| for(i = 0; i < item1count; i++) | |
| { | |
| av0 = arrayvalue_get(av1, i); | |
| if (!is_etch_arrayvalue(av0)) return -1; | |
| item0count = arrayvalue_count(av0); | |
| for(j = 0; j < (const int) item0count; j++) | |
| { /* insert native values into nativearray byte vector. we mask the | |
| * wrapped primitive with an etch_object. we can do so because the | |
| * etch primitive object is guaranteed to offset its value the | |
| * same as that of an etch_object, right after the object header. | |
| */ | |
| if (NULL == (wrapper = arrayvalue_get(av0, j))) return -1; | |
| if (0 == natv->put2(natv, &wrapper->value, i, j)) | |
| items++; | |
| else return -1; | |
| } | |
| } | |
| return items; | |
| } | |
| /** | |
| * arrayvalue1_to_nativearray() | |
| * convert an arrayvalue of dimension 1 to a native array. assumes that an | |
| * appropriately sized and configured etch_nativearray object is resident in | |
| * the arrayvalue object. | |
| */ | |
| int arrayvalue1_to_nativearray(etch_arrayvalue* av) | |
| { | |
| const int itemcount = arrayvalue_count(av); | |
| etch_nativearray* natv = av->natarray; | |
| etch_object* wrapper = NULL; | |
| int i=0, items = 0; | |
| for(; i < itemcount; i++) | |
| { /* insert native values into nativearray byte vector. we mask the | |
| * wrapped primitive with an etch_object. we can do so because the | |
| * etch primitive object is guaranteed to offset its value the | |
| * same as that of an etch_object, right after the object header. | |
| */ | |
| if (NULL == (wrapper = arrayvalue_get(av, i))) return -1; | |
| if (0 == natv->put1(natv, &wrapper->value, i)) | |
| items++; | |
| else return -1; | |
| } | |
| return items; | |
| } | |
| /** | |
| * arrayvalue_to_nativearray() | |
| * convert an arrayvalue to a native array | |
| * if the arrayvalue is created from a native array, the source native array is | |
| * still resident, however this method assumes we want to create the native array | |
| * regardless of whether one is resident. is also assumes that if we have created | |
| * the arrayvalue from scratch, we have done so properly, i.e., a multi-dimensioned | |
| * arrayvalue is and arrayvalue of arrayvalues. It additionally assumes that the | |
| * arrayvalue is populated with at least one value; if this were not the case we | |
| * would need to switch on the byte type_code to determine the item size. | |
| */ | |
| int arrayvalue_to_nativearray (etch_arrayvalue* av) | |
| { | |
| int dim0count=0, dim1count=0, dim2count=0, itemsize=0; | |
| etch_arrayvalue *av2 = NULL, *av1 = NULL, *av0 = NULL; | |
| unsigned short array_class_id = 0; | |
| etch_nativearray* newna = NULL; | |
| const int dimensions = av->dim; | |
| switch(dimensions) /* determine native array size */ | |
| { case 1: | |
| av0 = av; | |
| break; | |
| case 2: | |
| dim1count = arrayvalue_count(av); | |
| av1 = (etch_arrayvalue*) arrayvalue_get(av, 0); | |
| if (is_etch_arrayvalue(av1)) | |
| av0 = av1; | |
| break; | |
| case 3: | |
| dim2count = arrayvalue_count(av); | |
| av2 = (etch_arrayvalue*) arrayvalue_get(av, 0); | |
| if (!is_etch_arrayvalue(av2)) break; | |
| dim1count = arrayvalue_count(av2); | |
| av1 = (etch_arrayvalue*) arrayvalue_get(av2, 0); | |
| if (is_etch_arrayvalue(av1)) | |
| av0 = av1; | |
| } | |
| if (av0) /* if arrayvalue was populated ... */ | |
| { itemsize = av0->content_item_size; | |
| dim0count = arrayvalue_count(av0); | |
| array_class_id = etch_itemtype_to_arrayclass(av0->content_obj_type); | |
| } | |
| if (dim0count == 0 || itemsize == 0) return NULL; /* bad arrayvalue */ | |
| newna = new_nativearray /* allocate appropriately sized native array */ | |
| (array_class_id, itemsize, dimensions, dim0count, dim1count, dim2count); | |
| if (NULL == newna) return NULL; | |
| /* if previous native array was attached to the arrayvalue, free it */ | |
| if (av->natarray) av->natarray->destroy(av->natarray); | |
| av->natarray = newna; /* attach new native array to its arrayvalue */ | |
| switch(dimensions) /* populate new native array from array value */ | |
| { case 1: return arrayvalue1_to_nativearray(av); | |
| case 2: return arrayvalue2_to_nativearray(av); | |
| case 3: return arrayvalue3_to_nativearray(av); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * arrayvalue_add() | |
| * returns 0 or -1 | |
| */ | |
| int arrayvalue_add (etch_arrayvalue* av, ETCH_ARRAY_ELEMENT* content) | |
| { | |
| const int result = arraylist_add(av->list, content); | |
| return result; | |
| } | |
| /** | |
| * array_value_add() | |
| * returns 0 or -1 | |
| */ | |
| int array_value_add (etch_arrayvalue* av, ETCH_ARRAY_ELEMENT* content) | |
| { | |
| const int result = arraylist_add(av->list, content); | |
| return result; | |
| } | |
| /** | |
| * arrayvalue_get() | |
| * return item at specified index | |
| * returns array item, always an address, or NULL. | |
| */ | |
| void* arrayvalue_get (etch_arrayvalue* thisp, const int i) | |
| { | |
| return arraylist_get(thisp->list, i); | |
| } | |
| /** | |
| * arrayvalue_count() | |
| * return item count | |
| */ | |
| int arrayvalue_count (etch_arrayvalue* thisp) | |
| { | |
| return thisp? thisp->list? thisp->list->count: 0: 0; | |
| } | |
| /** | |
| * new_arrayvalue_arraylist() | |
| * allocates and returns an arraylist configured appropriately for use as arrayvalue backing store | |
| */ | |
| etch_arraylist* new_arrayvalue_arraylist (const int initsize, const int deltsize, | |
| const int is_readonly, const int is_synchronized) | |
| { | |
| etch_arraylist* list = is_synchronized? | |
| new_synchronized_arraylist(initsize, deltsize): | |
| new_arraylist(initsize, deltsize); | |
| list->is_readonly = is_readonly != 0; | |
| list->content_type = ETCHARRAYLIST_CONTENT_OBJECT; | |
| return list; | |
| } | |
| /** | |
| * new_array_element() | |
| * as ported from java, used when populating an array with nonspecific objects. | |
| */ | |
| ETCH_ARRAY_ELEMENT* new_array_element (const int objtype) | |
| { | |
| return new_etch_object(CLASSID_ARRAYELEMENT, NULL); | |
| } | |
| static const signed char etch_primitive_typecodes[11] | |
| = {ETCH_XTRNL_TYPECODE_CUSTOM, /* CLASSID_ARRAY_OBJECT */ | |
| ETCH_XTRNL_TYPECODE_BYTE, /* CLASSID_ARRAY_BYTE */ | |
| ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, /* CLASSID_ARRAY_BOOL */ | |
| ETCH_XTRNL_TYPECODE_BYTE, /* CLASSID_ARRAY_BYTE */ | |
| ETCH_XTRNL_TYPECODE_SHORT, /* CLASSID_ARRAY_INT16 */ | |
| ETCH_XTRNL_TYPECODE_INT, /* CLASSID_ARRAY_INT32 */ | |
| ETCH_XTRNL_TYPECODE_LONG, /* CLASSID_ARRAY_INT64 */ | |
| ETCH_XTRNL_TYPECODE_FLOAT, /* CLASSID_ARRAY_FLOAT */ | |
| ETCH_XTRNL_TYPECODE_DOUBLE, /* CLASSID_ARRAY_DOUBLE */ | |
| ETCH_XTRNL_TYPECODE_STRING, /* CLASSID_ARRAY_STRING */ | |
| 0, | |
| }; | |
| static const unsigned short etch_arrayval_classids[11] | |
| = {CLASSID_ARRAY_OBJECT, /* ETCH_XTRNL_TYPECODE_CUSTOM */ | |
| CLASSID_ARRAY_BYTE, /* ETCH_XTRNL_TYPECODE_BYTE */ | |
| CLASSID_ARRAY_BOOL, /* ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE */ | |
| CLASSID_ARRAY_BYTE, /* ETCH_XTRNL_TYPECODE_BYTE */ | |
| CLASSID_ARRAY_INT16, /* ETCH_XTRNL_TYPECODE_SHORT */ | |
| CLASSID_ARRAY_INT32, /* ETCH_XTRNL_TYPECODE_INT */ | |
| CLASSID_ARRAY_INT64, /* ETCH_XTRNL_TYPECODE_LONG */ | |
| CLASSID_ARRAY_FLOAT, /* ETCH_XTRNL_TYPECODE_FLOAT */ | |
| CLASSID_ARRAY_DOUBLE, /* ETCH_XTRNL_TYPECODE_DOUBLE */ | |
| CLASSID_ARRAY_STRING, /* ETCH_XTRNL_TYPECODE_STRING */ | |
| 0, | |
| }; | |
| /** | |
| * etch_arraytype_to_classid() | |
| * returns array class ID corresponding to serialization byte code. | |
| */ | |
| unsigned short etch_arraytype_to_classid (const signed char typecode) | |
| { | |
| int i = 0; | |
| unsigned short idout = 0; | |
| signed char* p = (signed char*) etch_primitive_typecodes; | |
| for(; *p; i++, p++) | |
| if (*p == typecode) | |
| { idout = etch_arrayval_classids[i]; | |
| break; | |
| } | |
| return idout; | |
| } | |
| /** | |
| * etch_classid_to_arraytype() | |
| * returns serialization bytecode corresponding to array class ID | |
| */ | |
| signed char etch_classid_to_arraytype (const unsigned short class_id) | |
| { | |
| int i = 0; | |
| signed char typecodeout = 0; | |
| unsigned short* p = (unsigned short*) etch_arrayval_classids; | |
| for(; *p; i++, p++) | |
| if (*p == class_id) | |
| { typecodeout = etch_primitive_typecodes[i]; | |
| break; | |
| } | |
| return typecodeout; | |
| } | |
| /** | |
| * etch_itemtype_to_arrayclass() | |
| * returns array object type corresponding to item object type | |
| */ | |
| unsigned short etch_itemtype_to_arrayclass(unsigned short item_obj_type) | |
| { | |
| if (item_obj_type > 0 && item_obj_type <= ETCHTYPEB_STRING) | |
| return etch_arrayval_classids[item_obj_type]; | |
| else return CLASSID_ARRAY_OBJECT; | |
| } | |
| /** | |
| * arrayvalue_get_external_typecode() | |
| * returns an array type bytecode for the specified array content type. | |
| */ | |
| signed char arrayvalue_get_external_typecode (unsigned short obj_type, unsigned short class_id) | |
| { | |
| signed char xtype = 0; | |
| #if(0) /* uncompiled arrays are here for documentation purposes */ | |
| unsigned short primitive_class_ids[] = | |
| { CLASSID_ANY, /* 0x0 */ | |
| CLASSID_PRIMITIVE_BYTE, /* 0x1 */ | |
| CLASSID_PRIMITIVE_BOOL, /* 0x2 */ | |
| CLASSID_PRIMITIVE_INT8, /* 0x3 */ | |
| CLASSID_PRIMITIVE_INT16, /* 0x4 */ | |
| CLASSID_PRIMITIVE_INT32, /* 0x5 */ | |
| CLASSID_PRIMITIVE_INT64, /* 0x6 */ | |
| CLASSID_PRIMITIVE_FLOAT, /* 0x7 */ | |
| CLASSID_PRIMITIVE_DOUBLE,/* 0x8 */ | |
| CLASSID_STRING, /* 0x9 */ | |
| }; | |
| unsigned short primitive_obj_types[] = | |
| { ETCHTYPEB_UNDEFINED, /* 0x0 */ | |
| ETCHTYPEB_BYTE, /* 0x1 */ | |
| ETCHTYPEB_BOOL, /* 0x2 */ | |
| ETCHTYPEB_INT8, /* 0x3 */ | |
| ETCHTYPEB_INT16, /* 0x4 */ | |
| ETCHTYPEB_INT32, /* 0x5 */ | |
| ETCHTYPEB_INT64, /* 0x6 */ | |
| ETCHTYPEB_IEEE32, /* 0x7 */ | |
| ETCHTYPEB_IEEE64, /* 0x8 */ | |
| ETCHTYPEB_STRING, /* 0x9 */ | |
| }; | |
| #endif | |
| if (obj_type == ETCHTYPEB_PRIMITIVE) | |
| { if (class_id < 1 || class_id > 9) | |
| class_id = 0; | |
| xtype = etch_primitive_typecodes [class_id]; | |
| } | |
| else /* primitive obj_type? */ | |
| if (obj_type > 0 && obj_type <= 9) | |
| xtype = etch_primitive_typecodes [obj_type]; | |
| else switch(obj_type) | |
| { case ETCHTYPEB_STRUCTVAL: xtype = ETCH_XTRNL_TYPECODE_CUSTOM; break; | |
| case ETCHTYPEB_ARRAYVAL: xtype = ETCH_XTRNL_TYPECODE_ARRAY; break; | |
| case ETCHTYPEB_NATIVEARRAY: xtype = ETCH_XTRNL_TYPECODE_ARRAY; break; | |
| default: xtype = ETCH_XTRNL_TYPECODE_CUSTOM; | |
| } | |
| return xtype; | |
| } | |
| /* | |
| * arrayvalue_set_static_content() | |
| * configure arraylist of object wrappers such that objects are not freed by the arraylist | |
| * destructor. presumably this would be used during recursive access to arrayvalue, where | |
| * lowest level objects are seen and destroyed prior to higher level objects such as the | |
| * array wrappers. | |
| */ | |
| void arrayvalue_set_static_content (etch_arrayvalue* av, const int is_set) | |
| { | |
| etch_arraylist* list = av? av->list: NULL; | |
| if (list) list->is_readonly = is_set? TRUE: FALSE; | |
| } | |
| /* | |
| * arrayvalue_set_iterator() | |
| * set an iterator on the arrayvalue, which becomes an iterator on its list | |
| */ | |
| int arrayvalue_set_iterator (etch_arrayvalue* av, etch_iterator* iterator) | |
| { | |
| return set_iterator (iterator, av->list, &av->list->iterable); | |
| } | |