| /* $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_structval.c -- etch_structvalue implementation. | |
| */ | |
| #include "etch_structval.h" | |
| #include "etch_validator.h" | |
| #include "etch_encoding.h" | |
| #include "etch_global.h" | |
| #include "etchexcp.h" | |
| #include "etchmap.h" | |
| #include "etchlog.h" | |
| char* ETCHSVAL = "SVAL"; | |
| etch_structvalue* new_structvalue_init(); | |
| int structvalue_clear_handler (etch_field* key, objmask* value); | |
| /** | |
| * new_structvalue() | |
| * primary constructor for etch_structvalue. | |
| * @param etch_type object, caller retains ownership of the type as usual | |
| */ | |
| etch_structvalue* new_structvalue(etch_type* type, const int initialsize) | |
| { | |
| etch_structvalue* newobj = new_structvalue_init(initialsize); | |
| newobj->struct_type = type; | |
| return newobj; | |
| } | |
| /** | |
| * new_structvalue_init() (private) | |
| * common initialization on etch_structvalue construction. | |
| */ | |
| etch_structvalue* new_structvalue_init(const int initialsize) | |
| { | |
| etch_structvalue* newobj = etch_malloc(sizeof(etch_structvalue), ETCHTYPEB_STRUCTVAL); | |
| memset(newobj, 0, sizeof(etch_structvalue)); | |
| newobj->obj_type = ETCHTYPEB_STRUCTVAL; | |
| newobj->class_id = CLASSID_STRUCTVALUE; /* for now anyway */ | |
| newobj->destroy = destroy_structvalue; | |
| newobj->clone = clone_null; | |
| newobj->items = new_structvalue_hashtable(initialsize); | |
| /* mark map such that it knows its keys and values are etch objects */ | |
| newobj->items->content_type = ETCHHASHTABLE_CONTENT_OBJECT_OBJECT; | |
| return newobj; | |
| } | |
| /** | |
| * destroy_structvalue() | |
| * destructor for an etch_structvalue object | |
| * | |
| * a structvalue owns all its memory *except* its type object, which is global | |
| * to the vf. this means that (a) the etch_type supplied on construction must be | |
| * a reference to a type owned by the service vf (or the unit test); and (b) all | |
| * struct keys must be etch_field* allocated on the heap and not referenced again | |
| * outside of that structvalue scope; and (c) all struct values must be etch object | |
| * references allocated on the heap and not referenced again outside of the | |
| * structvalue scope. | |
| */ | |
| int destroy_structvalue(etch_structvalue* thisp) | |
| { | |
| if (NULL == thisp) return 0; | |
| if (thisp->refcount > 0 && --thisp->refcount > 0) return -1; | |
| if (!is_etchobj_static_content(thisp)) | |
| ETCHOBJ_DESTROY(thisp->items); | |
| /* see comments above as to why we don't destroy type */ | |
| destroy_objectex((objmask*)thisp); | |
| return 0; | |
| } | |
| /* | |
| * structvalue_clear_handler() | |
| * this callback is set to handle freeing of key and value memory during a clear() | |
| * of the structvalue map. structs own all their memory, so if there is a problem | |
| * here, it should be resolved at the source, not by modifying this code. | |
| */ | |
| int structvalue_clear_handler (etch_field* key, objmask* value) | |
| { | |
| destroy_field(key); | |
| value->destroy(value); | |
| return TRUE; | |
| } | |
| /* | |
| * new_structvalue_hashtable | |
| * create the backing store for a struct value | |
| */ | |
| etch_hashtable* new_structvalue_hashtable(const int initialsize) | |
| { | |
| etch_hashtable* ht = new_hashtable(initialsize); | |
| if (ht == NULL) return NULL; | |
| ht->content_type = ETCH_STRUCT_DEFAULT_CONTENT_TYPE; | |
| ht->is_tracked_memory = ETCH_STRUCT_DEFAULT_TRACKED_MEM; | |
| ht->is_readonly_keys = ETCH_STRUCT_DEFAULT_READONLY_KEY; | |
| ht->is_readonly_values = ETCH_STRUCT_DEFAULT_READONLY_VAL; | |
| ht->freehook = structvalue_clear_handler; | |
| return ht; | |
| } | |
| /** | |
| * structvalue_put() | |
| * inserts (or removes) specified key/value pair to/from struct store. | |
| * @param key an etch_field whose destructor will be invoked when the struct is | |
| * destroyed. presumably this etch_field is disposable; if not, the object must | |
| * be marked as immutable using set_etchobj_static_all. | |
| * @param value a *disposable* object which is the value of the key/val pair. | |
| * this object's destructor will be invoked when the struct is destroyed. | |
| * presumably this object and its content are disposable; if not, the object must | |
| * be marked accordingly using set_etchobj_static_all or set_etchobj_static_content. | |
| * returns 0 or -1. | |
| */ | |
| int structvalue_put (etch_structvalue* thisp, etch_field* key, objmask* value) | |
| { | |
| etch_hashtable* map = thisp->items; | |
| if (NULL == key) return -1; | |
| if (NULL == value) /* per contract, no value implies removal desired */ | |
| return map->vtab->removeh (map->realtable, key->hashkey, key, 0); | |
| if (config.is_validate_on_write) | |
| { | |
| etch_type* thistype = thisp->struct_type; | |
| char *errmsg = NULL; | |
| etch_validator* vtor = (etch_validator*) | |
| etchtype_get_validator_by_name (thistype, key->name); | |
| if (NULL == vtor) | |
| errmsg = "validator missing"; | |
| else | |
| if (0 != vtor->validate (vtor, (etch_object*) value)) | |
| errmsg = "validation failed"; | |
| if (errmsg) | |
| { etchlog(ETCHSVAL, ETCHLOG_ERROR, "%s for type '%s' field '%s'\n", | |
| errmsg, thistype->aname, key->aname); | |
| return -1; | |
| } | |
| } | |
| return map->vtab->inserth (map->realtable, key, value, map, 0); | |
| } | |
| /** | |
| * structvalue_get() | |
| * access an element from the struct. | |
| * returns a reference not a copy. | |
| */ | |
| objmask* structvalue_get (etch_structvalue* thisp, etch_field* key) | |
| { | |
| int result = 0; | |
| etch_hashitem hashbucket; | |
| etch_hashitem* thisitem = &hashbucket; | |
| etch_hashtable* map = thisp? thisp->items: NULL; | |
| if (NULL == map) return NULL; | |
| result = map->vtab->findh(map->realtable, key->hashkey, map, &thisitem); | |
| return result == 0? thisitem->value: NULL; | |
| } | |
| /** | |
| * structvalue_remove | |
| * removes an element from the struct, returning the element. | |
| * if the element is found, its key is destroyed, and the object is returned. | |
| * caller owns returned object. | |
| */ | |
| objmask* structvalue_remove(etch_structvalue* thisp, etch_field* key) | |
| { | |
| int result = 0; | |
| etch_hashitem hashbucket; | |
| etch_hashitem* thisitem = &hashbucket; | |
| etch_hashtable* map = thisp? thisp->items: NULL; | |
| memset(thisitem,0,sizeof(etch_hashitem)); | |
| if (NULL == map) return NULL; | |
| /* remove specified item from hashtable without destroying content */ | |
| result = map->vtab->removeh(map->realtable, key->hashkey, map, &thisitem); | |
| if (-1 == result) return NULL; | |
| /* free entry key */ | |
| if (thisitem->key) | |
| if (etchmap_is_object_key(map)) | |
| ((objmask*)thisitem->key)->destroy(thisitem->key); | |
| else etch_free(thisitem->key); | |
| return (objmask*) thisitem->value; | |
| } | |
| /** | |
| * structvalue_is_type() | |
| * indicates if type of this struct is the same as the specified type | |
| */ | |
| int structvalue_is_type(etch_structvalue* thisp, etch_type* type) | |
| { | |
| return is_equal_types(thisp->struct_type, type); | |
| } | |
| /** | |
| * structvalue_count() | |
| * returns number of pairs in the struct | |
| */ | |
| int structvalue_count(etch_structvalue* sv) | |
| { | |
| return etchmap_count(sv->items); | |
| } |