blob: aebef04970f9de792476b6e52e8503998410bf40 [file]
/* $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);
}