#include "cxsa_main.h"
#include "cxsa_locking.h"
/*************************
* initialization section
************************/
autoxs_hashkey * CXSAccessor_last_hashkey = NULL;
autoxs_hashkey * CXSAccessor_hashkeys = NULL;
HashTable* CXSAccessor_reverse_hashkeys = NULL;
/* TODO the array index storage is still thought to not be 100%
* thread-safe during re-allocation and concurrent access by an
* implementation XSUB. Requires the same linked-list dance as the
* hash case. */
U32 CXSAccessor_no_arrayindices = 0;
U32 CXSAccessor_free_arrayindices_no = 0;
I32* CXSAccessor_arrayindices = NULL;
U32 CXSAccessor_reverse_arrayindices_length = 0;
I32* CXSAccessor_reverse_arrayindices = NULL;
/*************************
* implementation section
*************************/
/* implement hash containers */
STATIC
autoxs_hashkey *
_new_hashkey() {
autoxs_hashkey * retval;
retval = (autoxs_hashkey *) cxa_malloc( sizeof(autoxs_hashkey) );
retval->next = NULL;
if (CXSAccessor_last_hashkey != NULL) { /* apend to list */
CXSAccessor_last_hashkey->next = retval;
}
else { /* init */
CXSAccessor_hashkeys = retval;
}
CXSAccessor_last_hashkey = retval;
return retval;
}
autoxs_hashkey *
get_hashkey(pTHX_ const char* key, const I32 len) {
autoxs_hashkey * hashkey;
CXSA_ACQUIRE_GLOBAL_LOCK(CXSAccessor_lock);
/* init */
if (CXSAccessor_reverse_hashkeys == NULL)
CXSAccessor_reverse_hashkeys = CXSA_HashTable_new(16, 0.9);
hashkey = (autoxs_hashkey *) CXSA_HashTable_fetch(CXSAccessor_reverse_hashkeys, key, (STRLEN)len);
if (hashkey == NULL) { /* does not exist */
hashkey = _new_hashkey();
/* store the new hash key in the reverse lookup table */
CXSA_HashTable_store(CXSAccessor_reverse_hashkeys, key, len, hashkey);
}
CXSA_RELEASE_GLOBAL_LOCK(CXSAccessor_lock);
return hashkey;
}
/* implement array containers */
STATIC
void
_resize_array(I32** array, U32* len, U32 newlen) {
*array = (I32*)cxa_realloc((void*)(*array), newlen*sizeof(I32));
*len = newlen;
}
STATIC
void
_resize_array_init(I32** array, U32* len, U32 newlen, I32 init) {
U32 i;
*array = (I32*)cxa_realloc((void*)(*array), newlen*sizeof(I32));
for (i = *len; i < newlen; ++i)
(*array)[i] = init;
*len = newlen;
}
/* this is private, call get_internal_array_index instead */
I32
_new_internal_arrayindex() {
if (CXSAccessor_no_arrayindices == CXSAccessor_free_arrayindices_no) {
U32 extend = 2 + CXSAccessor_no_arrayindices * 2;
/*printf("extending array index storage by %u\n", extend);*/
_resize_array(&CXSAccessor_arrayindices, &CXSAccessor_no_arrayindices, extend);
}
return CXSAccessor_free_arrayindices_no++;
}
I32 get_internal_array_index(I32 object_ary_idx) {
I32 new_index;
CXSA_ACQUIRE_GLOBAL_LOCK(CXSAccessor_lock);
if (CXSAccessor_reverse_arrayindices_length <= (U32)object_ary_idx)
_resize_array_init( &CXSAccessor_reverse_arrayindices,
&CXSAccessor_reverse_arrayindices_length,
object_ary_idx+1, -1 );
/* -1 == "undef" */
if (CXSAccessor_reverse_arrayindices[object_ary_idx] > -1) {
CXSA_RELEASE_GLOBAL_LOCK(CXSAccessor_lock);
return CXSAccessor_reverse_arrayindices[object_ary_idx];
}
new_index = _new_internal_arrayindex();
CXSAccessor_reverse_arrayindices[object_ary_idx] = new_index;
CXSA_RELEASE_GLOBAL_LOCK(CXSAccessor_lock);
return new_index;
}