#include "mod_perl.h"
#ifdef USE_ITHREADS
#ifdef MP_PERL_5_6_x
# define my_sv_dup(s, p) sv_dup(s)
typedef
struct
{
AV *stashes;
UV flags;
PerlInterpreter *proto_perl;
} CLONE_PARAMS;
#else
# define my_sv_dup(s, p) sv_dup(s, p)
#endif
PTR_TBL_t *modperl_svptr_table_clone(pTHX_ PerlInterpreter *proto_perl,
PTR_TBL_t *source)
{
UV i;
PTR_TBL_t *tbl;
PTR_TBL_ENT_t **src_ary, **dst_ary;
CLONE_PARAMS parms;
Newz(0, tbl, 1, PTR_TBL_t);
tbl->tbl_max = source->tbl_max;
tbl->tbl_items = source->tbl_items;
Newz(0, tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t *);
dst_ary = tbl->tbl_ary;
src_ary = source->tbl_ary;
Zero(&parms, 0, CLONE_PARAMS);
parms.flags = 0;
parms.stashes = newAV();
for
(i=0; i < source->tbl_max; i++, dst_ary++, src_ary++) {
PTR_TBL_ENT_t *src_ent, *dst_ent=NULL;
if
(!*src_ary) {
continue
;
}
for
(src_ent = *src_ary;
src_ent;
src_ent = src_ent->next)
{
if
(dst_ent == NULL) {
Newz(0, dst_ent, 1, PTR_TBL_ENT_t);
*dst_ary = dst_ent;
}
else
{
Newz(0, dst_ent->next, 1, PTR_TBL_ENT_t);
dst_ent = dst_ent->next;
}
dst_ent->oldval = src_ent->oldval;
dst_ent->newval =
SvREFCNT_inc(my_sv_dup((SV*)src_ent->newval, &parms));
}
}
SvREFCNT_dec(parms.stashes);
return
tbl;
}
#endif
void
modperl_svptr_table_destroy(pTHX_ PTR_TBL_t *tbl)
{
UV i;
PTR_TBL_ENT_t **ary = tbl->tbl_ary;
for
(i=0; i < tbl->tbl_max; i++, ary++) {
PTR_TBL_ENT_t *ent;
if
(!*ary) {
continue
;
}
for
(ent = *ary; ent; ent = ent->next) {
if
(!ent->newval) {
continue
;
}
SvREFCNT_dec((SV*)ent->newval);
ent->newval = NULL;
}
}
modperl_svptr_table_free(aTHX_ tbl);
}
void
modperl_svptr_table_delete(pTHX_ PTR_TBL_t *tbl,
void
*key)
{
PTR_TBL_ENT_t *entry, **oentry;
UV hash = PTR2UV(key);
oentry = &tbl->tbl_ary[hash & tbl->tbl_max];
entry = *oentry;
for
(; entry; oentry = &entry->next, entry = *oentry) {
if
(entry->oldval == key) {
*oentry = entry->next;
SvREFCNT_dec((SV*)entry->newval);
Safefree(entry);
tbl->tbl_items--;
return
;
}
}
}
PTR_TBL_t *
modperl_svptr_table_new(pTHX)
{
PTR_TBL_t *tbl;
Newz(0, tbl, 1, PTR_TBL_t);
tbl->tbl_max = 511;
tbl->tbl_items = 0;
Newz(0, tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
return
tbl;
}
void
*
modperl_svptr_table_fetch(pTHX_ PTR_TBL_t *tbl,
void
*sv)
{
PTR_TBL_ENT_t *tblent;
UV hash = PTR2UV(sv);
assert
(tbl);
tblent = tbl->tbl_ary[hash & tbl->tbl_max];
for
(; tblent; tblent = tblent->next) {
if
(tblent->oldval == sv)
return
tblent->newval;
}
return
(
void
*)NULL;
}
void
modperl_svptr_table_store(pTHX_ PTR_TBL_t *tbl,
void
*oldv,
void
*newv)
{
PTR_TBL_ENT_t *tblent, **otblent;
UV hash = PTR2UV(oldv);
bool
i = 1;
assert
(tbl);
otblent = &tbl->tbl_ary[hash & tbl->tbl_max];
for
(tblent = *otblent; tblent; i=0, tblent = tblent->next) {
if
(tblent->oldval == oldv) {
tblent->newval = newv;
return
;
}
}
Newz(0, tblent, 1, PTR_TBL_ENT_t);
tblent->oldval = oldv;
tblent->newval = newv;
tblent->next = *otblent;
*otblent = tblent;
tbl->tbl_items++;
if
(i && tbl->tbl_items > tbl->tbl_max)
modperl_svptr_table_split(aTHX_ tbl);
}
void
modperl_svptr_table_split(pTHX_ PTR_TBL_t *tbl)
{
PTR_TBL_ENT_t **ary = tbl->tbl_ary;
UV oldsize = tbl->tbl_max + 1;
UV newsize = oldsize * 2;
UV i;
Renew(ary, newsize, PTR_TBL_ENT_t*);
Zero(&ary[oldsize], newsize-oldsize, PTR_TBL_ENT_t*);
tbl->tbl_max = --newsize;
tbl->tbl_ary = ary;
for
(i=0; i < oldsize; i++, ary++) {
PTR_TBL_ENT_t **curentp, **entp, *ent;
if
(!*ary)
continue
;
curentp = ary + oldsize;
for
(entp = ary, ent = *ary; ent; ent = *entp) {
if
((newsize & PTR2UV(ent->oldval)) != i) {
*entp = ent->next;
ent->next = *curentp;
*curentp = ent;
continue
;
}
else
entp = &ent->next;
}
}
}
void
modperl_svptr_table_clear(pTHX_ PTR_TBL_t *tbl)
{
register
PTR_TBL_ENT_t **array;
register
PTR_TBL_ENT_t *entry;
register
PTR_TBL_ENT_t *oentry = Null(PTR_TBL_ENT_t*);
UV riter = 0;
UV max;
if
(!tbl || !tbl->tbl_items) {
return
;
}
array = tbl->tbl_ary;
entry = array[0];
max = tbl->tbl_max;
for
(;;) {
if
(entry) {
oentry = entry;
entry = entry->next;
Safefree(oentry);
}
if
(!entry) {
if
(++riter > max) {
break
;
}
entry = array[riter];
}
}
tbl->tbl_items = 0;
}
void
modperl_svptr_table_free(pTHX_ PTR_TBL_t *tbl)
{
if
(!tbl) {
return
;
}
modperl_svptr_table_clear(aTHX_ tbl);
Safefree(tbl->tbl_ary);
Safefree(tbl);
}