#include "refString.h"
#include "nedit_malloc.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define RCS_SIZE 0x10000
struct rcs;
struct rcs_stats
{
int talloc, tshar, tgiveup, tbytes, tbyteshared;
};
struct rcs
{
struct rcs *next;
char *string;
int usage;
};
static struct rcs *Rcs[
RCS_SIZE];
static struct rcs_stats RcsStats;
static unsigned const DJB2_SEED = 5381u;
static unsigned djb2s(
char const* key,
unsigned hash)
{
char c;
while (!!(c = *key++))
hash = ((hash <<
5) + hash) ^ c;
return hash;
}
unsigned StringHashAddr(
const char *key)
{
return djb2s(key,
DJB2_SEED);
}
unsigned StringsHashAddr(
const char** keys)
{
unsigned hash =
DJB2_SEED;
char const* key;
while (!!(key = *keys++))
hash = djb2s(key, hash);
return hash;
}
const char *RefStringDup(
const char *str)
{
unsigned bucket;
size_t len;
struct rcs *rp;
char *newstr;
if (str ==
NULL)
return NULL;
len = strlen(str);
RcsStats.talloc++;
bucket = StringHashAddr(str) %
RCS_SIZE;
rp = Rcs[bucket];
for (; rp; rp = rp->next)
if (!strcmp(str, rp->string))
break;
newstr =
NULL;
if (rp)
{
rp->usage++;
newstr = rp->string;
RcsStats.tshar++;
RcsStats.tbyteshared += len;
}
else
{
rp = NEditNew(
struct rcs);
rp->usage =
1;
rp->next = Rcs[bucket];
Rcs[bucket] = rp;
rp->string = (
char*) NEditMalloc(len +
1);
memcpy(rp->string, str, len +
1);
newstr = rp->string;
}
RcsStats.tbytes += len;
return newstr;
}
void RefStringFree(
const char *rcs_str)
{
int bucket;
struct rcs *rp;
struct rcs *prev =
NULL;
if (rcs_str ==
NULL)
return;
bucket = StringHashAddr(rcs_str) %
RCS_SIZE;
for (rp = Rcs[bucket]; rp; rp = rp->next)
{
if (rcs_str == rp->string)
break;
prev = rp;
}
if (rp)
{
rp->usage--;
if (rp->usage <
0)
{
fprintf(stderr,
"XNEdit: internal error deallocating shared string.");
return;
}
if (rp->usage ==
0)
{
NEditFree(rp->string);
if (prev)
prev->next = rp->next;
else
Rcs[bucket] = rp->next;
NEditFree(rp);
}
}
else
{
fprintf(stderr,
"XNEdit: attempt to free a non-shared string.");
return;
}
}