blob: ee0de34825a4f23a26f59b0517e7881fe020a950 [file] [log] [blame]
/* $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.
*/
/*
* etchmap.c -- generic int or string to object map.
* note that this code does not implement an etch_map type, that type was added
* to etch after we had already defined this particular API.
* todo: convert global cache to use this code.
*/
#include "etch_map.h"
#include "etch_mem.h"
#include <wchar.h>
#ifdef WIN32
#pragma warning (disable:4996)
#endif
/*
* make_etchmap_key()
* given 32-bit key constructs alpha key for the map returning key byte length
*/
int make_etchmap_key(const unsigned int key, char* buf, const int buflen)
{
//_itoa_s(key, buf, buflen, 10);
sprintf(buf, "%d", key);
return (int)strlen(buf);
}
/*
* etchmap_populate_out()
* populate caller's out struct
*/
void etchmap_populate_out(etch_hashitem* useritem, etch_hashitem* curritem)
{
useritem->key = curritem->key;
useritem->value = curritem->value;
useritem->hash = curritem->hash;
}
/*
* etchmap_findxl()
* @return a reference to map content, not owned by caller.
* if the etch_hashitem out parameter is specified, it is populated on success.
*/
void* etchmap_findxl(etch_hashtable* map, char* key, unsigned keylen, void** out)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_find(map->realtable, key, keylen, 0, (void**)&founditem);
#if ETCHMAP_DEBUG
#pragma warning(disable:4313)
if (result == 0)
printf("etchmap_found key %s len %d addr %08x\n",
key, keylen, founditem->value);
else printf("etchmap_notfound key %s len %d\n", key, keylen);
#endif
if (result == -1) return NULL;
if (out)
etchmap_populate_out(*out, founditem);
return founditem->value;
}
/*
* etchmap_find()
* locate object with specified key, returning it or NULL.
* @return a reference to map content, not owned by caller.
* if the etch_hashitem out parameter is specified, it is populated on success.
*/
void* etchmap_find(etch_hashtable* map, const unsigned int objkey, void** out)
{
char ckey[ETCHMAP_MAX_IKEYSIZE+1];
unsigned keylen = make_etchmap_key(objkey, ckey, ETCHMAP_MAX_IKEYSIZE);
return etchmap_findxl(map, ckey, keylen, out);
}
/*
* etchmap_findx()
* locate object with specified ansi char key, returning it or NULL
*/
void* etchmap_findx(etch_hashtable* map, char* key, void** out)
{
unsigned keylen = (unsigned)strlen(key);
return etchmap_findxl(map, key, keylen, out);
}
/*
* etchmap_findxw()
* locate object with specified unicode key, returning it or NULL
* @return a reference to map content, not owned by caller.
* if the etch_hashitem out parameter is specified, it is populated on success.
*/
void* etchmap_findxw(etch_hashtable* map, wchar_t* key, void** out)
{
unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
return etchmap_findxl(map, (char*) key, keylen, out);
}
/*
* etchmap_find_by_hash()
* locate object with specified hashkey, returning it or NULL.
* @return a reference to map content, not owned by caller.
* if the etch_hashitem out parameter is specified, it is populated on success.
*/
void* etchmap_find_by_hash(etch_hashtable* map, const unsigned hash, void** out)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_findh(map->realtable, hash, map, (void**)&founditem);
if (result == -1) return NULL;
if (out)
etchmap_populate_out(*out, founditem);
return founditem->value;
}
/*
* etchmap_current()
* return object at current position
*/
etch_hashitem* etchmap_current(etch_hashtable* map)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_current(map->realtable, 0, (void**)&founditem);
return (result == -1)? NULL: founditem;
}
/*
* etchmap_delxl()
* remove specified object from map given ansi char key and length.
* return pointer to object, which is not freed here, it is owned by caller.
*/
void* etchmap_delxl (etch_hashtable* map, char* ckey, const unsigned keylen)
{
etch_hashitem hashbucket;
etch_hashitem* founditem = &hashbucket;
int result = jenkins_remove(map->realtable, ckey, keylen, 0, (void**)&founditem);
if (result == -1) return NULL;
free(founditem->key); /* free 4-byte key allocated in etchmap_add() */
return founditem->value;
}
/*
* etchmap_del()
* remove specified object from map given integer key.
* return pointer to object, which is not freed here, it is owned by caller.
*/
void* etchmap_del (etch_hashtable* map, const unsigned int objkey)
{
char ckey[ETCHMAP_MAX_IKEYSIZE+1];
unsigned keylen = make_etchmap_key(objkey, ckey, ETCHMAP_MAX_IKEYSIZE);
return etchmap_delxl(map, ckey, keylen);
}
/*
* etchmap_delx()
* remove specified object from map given ansi char key.
* return pointer to object, which is not freed here, it is owned by caller.
*/
void* etchmap_delx (etch_hashtable* map, char* key)
{
const unsigned keylen = (unsigned)strlen(key);
return etchmap_delxl(map, key, keylen);
}
/*
* etchmap_delxw()
* remove specified object from map given unicode key.
* return pointer to object, which is not freed here, it is owned by caller.
*/
void* etchmap_delxw (etch_hashtable* map, wchar_t* key)
{
const unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
return etchmap_delxl(map, (char*) key, keylen);
}
/*
* etchmap_insertxl()
* add specified object to map given ansi char key and char length,
* with preexistence test optional.
* @param key a string for which caller retains ownership, map makes a copy.
* @param data an object owned by map or not depending on map attributes.
* @return hash of supplied key, or zero if insertion error.
*/
int etchmap_insertxl (etch_hashtable* map,
char* key, const unsigned keylen, void* data, const int is_check)
{
int result = 0, keylent = 0;
char* pkey = NULL;
void* pval = NULL;
etch_hashitem hashbucket;
etch_hashitem* inserteditem = &hashbucket;
memset(&hashbucket, 0, sizeof(etch_hashitem));
if (is_check)
{ pval = etchmap_findxl(map, key, keylen, (void**)&inserteditem);
if (pval) return inserteditem->hash; /* entry exists */
}
keylent = keylen + 1;/* add new entry */
pkey = etch_malloc(keylent, 0);
//strcpy_s(pkey, keylent, key);
strcpy(pkey, key);
#if ETCHMAP_DEBUG
#pragma warning(disable:4313)
printf("etchmap_insertxl key %s len %d addr %08x\n", pkey, keylen, data);
#endif
result = jenkins_insert
(map->realtable, pkey, keylen, data, 0, 0, (void**)&inserteditem);
/* etchmap_dump(); */
return inserteditem->hash;
}
/*
* etchmap_insertxlw()
* add specified object to map given unicode key and char length,
* with preexistence test optional.
* @param key a string for which caller retains ownership, map makes a copy.
* @param data an object owned by map or not depending on map attributes.
* @return hash of supplied key, or zero if insertion error.
*/
int etchmap_insertxlw (etch_hashtable* map,
wchar_t* key, const unsigned keylen, void* data, const int is_check)
{
int result = 0, keylent = 0;
wchar_t* pkey = NULL;
void* pval = NULL;
etch_hashitem hashbucket;
etch_hashitem* inserteditem = &hashbucket;
memset(&hashbucket, 0, sizeof(etch_hashitem));
if (is_check)
{ pval = etchmap_findxl(map, (char*) key, keylen, (void**)&inserteditem);
if (pval) return inserteditem->hash; /* entry exists */
}
keylent = keylen + sizeof(wchar_t); /* add new entry */
/* watch this spot. issue observed here where etch_malloc reports that it
* "could not add x to heap tracking store". my guess is that a heap item
* at address x had been etch_freed, but key x was for some reason not
* removed from the tracking table. memory address x was subsequently
* re-issued by malloc, and when etch_malloc attempts to add it to the
* tracking table, the address already exists there (or there is a hash
* collision?). regardless, this is a tracking error, is probably not a
* leak (because etch_free frees the memory regardless of this error),
* however the error messages are a problem so we need to address this.
*/
pkey = etch_malloc(keylent, 0);
wcscpy(pkey, key);
result = jenkins_insert
(map->realtable, pkey, keylen, data, 0, 0, (void**)&inserteditem);
return inserteditem->hash;
}
/*
* etchmap_insert()
* add specified object to map with preexistence test optional.
* return inserted item hash, or zero if insertion error.
*/
int etchmap_insert (etch_hashtable* map,
const unsigned int key, void* data, const int is_check)
{
char ckey[ETCHMAP_MAX_IKEYSIZE+1];
unsigned keylen = make_etchmap_key(key, ckey, ETCHMAP_MAX_IKEYSIZE);
return etchmap_insertxl(map, ckey, keylen, data, is_check);
}
/*
* etchmap_insertx()
* add specified object to map with preexistence test optional.
* param key a string for which caller retains ownership, map makes a copy.
* @param data the value of the key/value pair, owned by map or not depending
* on map attributes.
* return inserted item hash, or zero if insertion error.
*/
int etchmap_insertx (etch_hashtable* map, char* key, void* data, const int is_check)
{
unsigned keylen = (unsigned)strlen(key);
return etchmap_insertxl(map, key, keylen, data, is_check);
}
/*
* etchmap_insertxw()
* add specified object to map with preexistence test optional.
* param key a string for which caller retains ownership, map makes a copy.
* @param data the value of the key/value pair, owned by map or not depending
* on map attributes.
* return inserted item hash, or zero if insertion error.
*/
int etchmap_insertxw (etch_hashtable* map, wchar_t* key, void* data, const int is_check)
{
unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
return etchmap_insertxlw(map, key, keylen, data, is_check);
}
/*
* etchmap_add()
* add specified object to map given integer key.
* return 0 or -1.
*/
int etchmap_add (etch_hashtable* map, const unsigned int objkey, void* data)
{
/* zero back from etchmap_insert() indicates insert error */
return etchmap_insert (map, objkey, data, TRUE)? 0: -1;
}
/*
* etchmap_addx()
* add specified object to map.
* return 0 or -1.
*/
int etchmap_addx(etch_hashtable* map, char* key, void* data)
{
/* zero back from etchmap_insert() indicates insert error */
return etchmap_insertx (map, key, data, TRUE)? 0: -1;
}
/*
* etchmap_addxw()
* add specified object to map.
* return 0 or -1.
*/
int etchmap_addxw(etch_hashtable* map, wchar_t* key, void* data)
{
/* zero back from etchmap_insert() indicates insert error */
return etchmap_insertxw (map, key, data, TRUE)? 0: -1;
}
/*
* etchmap_count()
* return count of items in map.
*/
int etchmap_count(etch_hashtable* map)
{
return map? ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable, 0, 0): 0;
}
/*
* string_to_etchobject_clear_handler()
* callback set to handle freeing of key memory during a clear() of
* a string to object type map, where the objects are etch_objects.
* handlers return FALSE to indicate memory free NOT handled.
*/
int string_to_etchobject_clear_handler (char* key, etch_object* value)
{
etch_free(key);
etch_object_destroy(value);
return TRUE;
}
/*
* string_to_genericobject_clear_handler()
* callback set to handle freeing of key memory during a clear() of
* a string to object type map, where the objects are not etch_objects.
* handlers return FALSE to indicate memory free NOT handled.
*/
int string_to_genericobject_clear_handler (char* key, void* value)
{
etch_free(key);
etch_free(value);
return TRUE;
}
/* - - - - - - - - - - - - - - - -
* etch_map (object to object map)
* - - - - - - - - - - - - - - - -
*/
/**
* etchmap_is_object_key
* @return boolean value indicating whether hashtable key is an etch object
*/
int etchmap_is_object_key(etch_hashtable* map)
{
int result = FALSE;
if (map) switch(map->content_type)
{ case ETCHHASHTABLE_CONTENT_OBJECT_OBJECT:
case ETCHHASHTABLE_CONTENT_OBJECT_NONE:
result = TRUE;
}
return result;
}
/**
* etchmap_map_add
* inserts item to object/object hashtable
* it is assumed that hashkey has been pre-computed on the key object.
*/
int etchmap_map_add (etch_hashtable* map, etch_object* key, etch_object* value)
{
int result = 0;
key->get_hashkey(key);
result = ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, key, value, map, 0);
return result;
}
/**
* etchmap_map_find()
* finds object with specified object key .
* it is assumed that hashkey has been pre-computed on the key object.
* @return 0 or -1
* found item is returned via out parameter, if supplied.
*/
int etchmap_map_find(etch_hashtable* map, etch_object* key, etch_hashitem** out)
{
const int result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, key->get_hashkey(key), map, out);
return result;
}
/**
* etchmap_set_add
* inserts item to object/null hashtable
* it is assumed that hashkey has been pre-computed on the key object.
*/
int etchmap_set_add (etch_hashtable* set, etch_object* key)
{
int result = 0;
key->get_hashkey(key);
result = ((struct i_hashtable*)((etch_object*)set)->vtab)->inserth(set->realtable, key, NULL, set, 0);
return result;
}