pjs/rdf/tests/sht.cpp

220 строки
5.9 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.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.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "rdf.h"
#include "rdfutil.h"
#include "prtypes.h"
#include "prmem.h"
#include "nscore.h"
#include "nsIOutputStream.h"
#include "plhash.h"
#include "plstr.h"
typedef struct _SerializedHashTable {
FILE* file;
PLHashTable* table;
char* buffer;
size_t maxEntrySize;
} SerializedHashTable;
typedef SerializedHashTable* SHT;
typedef struct _SHTEntry {
void* value;
size_t size;
size_t offset;
} SHTEntry;
typedef SHTEntry* SHTE;
void
dumpHashItem (SHT table, char* key, size_t keyLen, void* value, size_t valueSize) {
fprintf(table->file, "A %i\n%s\n%i\n", keyLen, key, valueSize);
fwrite(value, 1, valueSize, table->file);
fprintf(table->file, "\n");
}
PRBool
readNextItem(FILE *file, char** key, char** value, size_t *valueSize, PRBool *ignorep,
int *offset) {
char *xkey, *xvalue;
int keySize;
char ignoreChar;
char tbuff[10];
*offset = ftell(file);
if (!fgets((char*)tbuff, 10, file)) return 0;
if (tbuff[0] == 'X') return 0;
sscanf(tbuff, "%c %i", &ignoreChar, &keySize);
xkey = (char*) PR_Malloc(keySize + 1);
if (!fgets(xkey, keySize+1, file)) return 0;
fread(tbuff, 1, 1, file);
memset(tbuff, '\0', 10);
if (!fgets((char*)tbuff, 10, file)) return 0;
sscanf(tbuff, "%i", valueSize);
xvalue = (char*) PR_Malloc(*valueSize + 1);
xvalue[*valueSize] = '\0';
if (!fread(xvalue, *valueSize, 1, file)) return 0;
fread(tbuff, 1, 1, file);
if (ignoreChar == 'D') {
PR_Free((void*)xvalue);
PR_Free((void*)xkey);
*ignorep = 1;
return 1;
} else {
*ignorep = 0;
*value = xvalue;
*key = xkey;
return 1;
}
}
PRIntn
SHTFlusher(PLHashEntry *he, PRIntn index, void *arg) {
SHT table = (SHT)arg;
SHTE entry = (SHTE)he->value;
char* key = (char*)he->key;
char* v1 = (char*)entry->value;
dumpHashItem(table, key, strlen(key), entry->value, entry->size);
return HT_ENUMERATE_NEXT;
}
void
FlushSHT (SHT table) {
table->buffer = (char*)PR_Malloc(table->maxEntrySize + 256);
fseek(table->file, 0, SEEK_SET);
PL_HashTableEnumerateEntries(table->table, SHTFlusher, table);
fwrite("X", 1, 1, table->file);
fflush(table->file);
PR_Free(table->buffer);
}
PLHashEntry*
SHTAddInt (PLHashTable* table, size_t valueSize, void* value, char* key, int offset) {
SHTE ve = (SHTE) PR_Malloc(sizeof(SHTEntry));
ve->value = value;
ve->size = valueSize;
ve->offset = offset;
return PL_HashTableAdd(table, key, ve);
}
SHT
MakeSerializedHash (FILE* file, PRUint32 numBuckets, PLHashFunction keyHash,
PLHashComparator keyCompare, PLHashComparator valueCompare,
const PLHashAllocOps *allocOps, void *allocPriv) {
SHT table = (SHT)PR_Malloc(sizeof(SerializedHashTable));
char* key;
char* value;
size_t valueSize;
PRBool ignorep = 0;
int offset;
table->table = PL_NewHashTable(numBuckets, keyHash,
keyCompare, valueCompare,
allocOps, allocPriv);
table->file = file;
table->maxEntrySize = 1024;
while (readNextItem(file, &key, &value, &valueSize, &ignorep, &offset)) {
SHTAddInt(table->table, valueSize, value, key, offset);
}
return table;
}
void
SHTAdd(SHT table, char *key, void *value, size_t valueSize) {
fseek(table->file, 0, SEEK_END);
SHTFlusher(SHTAddInt(table->table,valueSize, value, key, ftell(table->file)), 0, table);
fflush(table->file);
}
void
SHTRemove(SHT table, char* key) {
SHTE entry = (SHTE)PL_HashTableLookup(table->table, (void*) key);
if (entry) {
fseek(table->file, entry->offset, SEEK_SET);
fwrite("D", 1, 1, table->file);
fflush(table->file);
PL_HashTableRemove(table->table, key);
PR_Free(entry);
}
}
void*
SHTLookup(SHT ht, const char *key) {
SHTE entry = (SHTE)PL_HashTableLookup(ht->table, (void*) key);
if (entry) {
return entry->value;
} else return 0;
}
FILE*
MakeOrOpenFile (char* name) {
FILE* ans;
ans = fopen(name, "r+");
if (ans) return ans;
ans = fopen(name, "w");
fclose(ans);
return fopen(name, "r+");
}
void SHTtest () {
FILE *f = MakeOrOpenFile("test");
SHT table = MakeSerializedHash(f, 100, PL_HashString, PL_CompareStrings,
PL_CompareValues, NULL, NULL);
char buffer[1024];
printf("\n>");
while (fgets(buffer, 1023, stdin)) {
if (strncmp(buffer, "x", 1) == 0) {
FlushSHT(table);
return;
}
if (strncmp(buffer, "a", 1) ==0) {
char key[100], value[100];
char *xkey, *xvalue;
sscanf(buffer, "a %s %s", key, value);
xkey = (char*)PR_Malloc(strlen(key)+1);
xvalue = (char*)PR_Malloc(strlen(value)+1);
memset(xkey, '\0', strlen(key)+1);
memset(xvalue, '\0', strlen(value)+1);
memcpy(xkey, key, strlen(key));
memcpy(xvalue, value, strlen(value));
SHTAdd(table, xkey, xvalue, strlen(xvalue));
}
if (strncmp(buffer, "q", 1) ==0) {
char key[100];
char* ans;
sscanf(buffer, "q %s", key);
ans = (char*)SHTLookup(table, (char*)key);
printf("-> %s\n", (ans ? ans : "null"));
}
if (strncmp(buffer, "r", 1) == 0) {
char key[100];
sscanf(buffer, "r %s", key);
SHTRemove(table, key);
}
printf("\n>");
}
}