mirror of
git://projects.qi-hardware.com/gmenu2x.git
synced 2025-04-21 12:27:27 +03:00
initial commit - needs clean-up
Signed-off-by: Mirko Lindner <mirko@sharism.cc>
This commit is contained in:
9
src/sparsehash-1.6/experimental/Makefile
Normal file
9
src/sparsehash-1.6/experimental/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
example: example.o libchash.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
.SUFFIXES: .c .o .h
|
||||
.c.o:
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
|
||||
|
||||
example.o: example.c libchash.h
|
||||
libchash.o: libchash.c libchash.h
|
||||
14
src/sparsehash-1.6/experimental/README
Normal file
14
src/sparsehash-1.6/experimental/README
Normal file
@@ -0,0 +1,14 @@
|
||||
This is a C version of sparsehash (and also, maybe, densehash) that I
|
||||
wrote way back when, and served as the inspiration for the C++
|
||||
version. The API for the C version is much uglier than the C++,
|
||||
because of the lack of template support. I believe the class works,
|
||||
but I'm not convinced it's really flexible or easy enough to use.
|
||||
|
||||
It would be nice to rework this C class to follow the C++ API as
|
||||
closely as possible (eg have a set_deleted_key() instead of using a
|
||||
#define like this code does now). I believe the code compiles and
|
||||
runs, if anybody is interested in using it now, but it's subject to
|
||||
major change in the future, as people work on it.
|
||||
|
||||
Craig Silverstein
|
||||
20 March 2005
|
||||
54
src/sparsehash-1.6/experimental/example.c
Normal file
54
src/sparsehash-1.6/experimental/example.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "libchash.h"
|
||||
|
||||
static void TestInsert() {
|
||||
struct HashTable* ht;
|
||||
HTItem* bck;
|
||||
|
||||
ht = AllocateHashTable(1, 0); /* value is 1 byte, 0: don't copy keys */
|
||||
|
||||
HashInsert(ht, PTR_KEY(ht, "January"), 31); /* 0: don't overwrite old val */
|
||||
bck = HashInsert(ht, PTR_KEY(ht, "February"), 28);
|
||||
bck = HashInsert(ht, PTR_KEY(ht, "March"), 31);
|
||||
|
||||
bck = HashFind(ht, PTR_KEY(ht, "February"));
|
||||
assert(bck);
|
||||
assert(bck->data == 28);
|
||||
|
||||
FreeHashTable(ht);
|
||||
}
|
||||
|
||||
static void TestFindOrInsert() {
|
||||
struct HashTable* ht;
|
||||
int i;
|
||||
int iterations = 1000000;
|
||||
int range = 30; /* random number between 1 and 30 */
|
||||
|
||||
ht = AllocateHashTable(4, 0); /* value is 4 bytes, 0: don't copy keys */
|
||||
|
||||
/* We'll test how good rand() is as a random number generator */
|
||||
for (i = 0; i < iterations; ++i) {
|
||||
int key = rand() % range;
|
||||
HTItem* bck = HashFindOrInsert(ht, key, 0); /* initialize to 0 */
|
||||
bck->data++; /* found one more of them */
|
||||
}
|
||||
|
||||
for (i = 0; i < range; ++i) {
|
||||
HTItem* bck = HashFind(ht, i);
|
||||
if (bck) {
|
||||
printf("%3d: %d\n", bck->key, bck->data);
|
||||
} else {
|
||||
printf("%3d: 0\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
FreeHashTable(ht);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestInsert();
|
||||
TestFindOrInsert();
|
||||
return 0;
|
||||
}
|
||||
1537
src/sparsehash-1.6/experimental/libchash.c
Normal file
1537
src/sparsehash-1.6/experimental/libchash.c
Normal file
File diff suppressed because it is too large
Load Diff
252
src/sparsehash-1.6/experimental/libchash.h
Normal file
252
src/sparsehash-1.6/experimental/libchash.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/* Copyright (c) 1998 - 2005, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Craig Silverstein
|
||||
*
|
||||
* This library is intended to be used for in-memory hash tables,
|
||||
* though it provides rudimentary permanent-storage capabilities.
|
||||
* It attempts to be fast, portable, and small. The best algorithm
|
||||
* to fulfill these goals is an internal probing hashing algorithm,
|
||||
* as in Knuth, _Art of Computer Programming_, vol III. Unlike
|
||||
* chained (open) hashing, it doesn't require a pointer for every
|
||||
* item, yet it is still constant time lookup in practice.
|
||||
*
|
||||
* Also to save space, we let the contents (both data and key) that
|
||||
* you insert be a union: if the key/data is small, we store it
|
||||
* directly in the hashtable, otherwise we store a pointer to it.
|
||||
* To keep you from having to figure out which, use KEY_PTR and
|
||||
* PTR_KEY to convert between the arguments to these functions and
|
||||
* a pointer to the real data. For instance:
|
||||
* char key[] = "ab", *key2;
|
||||
* HTItem *bck; HashTable *ht;
|
||||
* HashInsert(ht, PTR_KEY(ht, key), 0);
|
||||
* bck = HashFind(ht, PTR_KEY(ht, "ab"));
|
||||
* key2 = KEY_PTR(ht, bck->key);
|
||||
*
|
||||
* There are a rich set of operations supported:
|
||||
* AllocateHashTable() -- Allocates a hashtable structure and
|
||||
* returns it.
|
||||
* cchKey: if it's a positive number, then each key is a
|
||||
* fixed-length record of that length. If it's 0,
|
||||
* the key is assumed to be a \0-terminated string.
|
||||
* fSaveKey: normally, you are responsible for allocating
|
||||
* space for the key. If this is 1, we make a
|
||||
* copy of the key for you.
|
||||
* ClearHashTable() -- Removes everything from a hashtable
|
||||
* FreeHashTable() -- Frees memory used by a hashtable
|
||||
*
|
||||
* HashFind() -- takes a key (use PTR_KEY) and returns the
|
||||
* HTItem containing that key, or NULL if the
|
||||
* key is not in the hashtable.
|
||||
* HashFindLast() -- returns the item found by last HashFind()
|
||||
* HashFindOrInsert() -- inserts the key/data pair if the key
|
||||
* is not already in the hashtable, or
|
||||
* returns the appropraite HTItem if it is.
|
||||
* HashFindOrInsertItem() -- takes key/data as an HTItem.
|
||||
* HashInsert() -- adds a key/data pair to the hashtable. What
|
||||
* it does if the key is already in the table
|
||||
* depends on the value of SAMEKEY_OVERWRITE.
|
||||
* HashInsertItem() -- takes key/data as an HTItem.
|
||||
* HashDelete() -- removes a key/data pair from the hashtable,
|
||||
* if it's there. RETURNS 1 if it was there,
|
||||
* 0 else.
|
||||
* If you use sparse tables and never delete, the full data
|
||||
* space is available. Otherwise we steal -2 (maybe -3),
|
||||
* so you can't have data fields with those values.
|
||||
* HashDeleteLast() -- deletes the item returned by the last Find().
|
||||
*
|
||||
* HashFirstBucket() -- used to iterate over the buckets in a
|
||||
* hashtable. DON'T INSERT OR DELETE WHILE
|
||||
* ITERATING! You can't nest iterations.
|
||||
* HashNextBucket() -- RETURNS NULL at the end of iterating.
|
||||
*
|
||||
* HashSetDeltaGoalSize() -- if you're going to insert 1000 items
|
||||
* at once, call this fn with arg 1000.
|
||||
* It grows the table more intelligently.
|
||||
*
|
||||
* HashSave() -- saves the hashtable to a file. It saves keys ok,
|
||||
* but it doesn't know how to interpret the data field,
|
||||
* so if the data field is a pointer to some complex
|
||||
* structure, you must send a function that takes a
|
||||
* file pointer and a pointer to the structure, and
|
||||
* write whatever you want to write. It should return
|
||||
* the number of bytes written. If the file is NULL,
|
||||
* it should just return the number of bytes it would
|
||||
* write, without writing anything.
|
||||
* If your data field is just an integer, not a
|
||||
* pointer, just send NULL for the function.
|
||||
* HashLoad() -- loads a hashtable. It needs a function that takes
|
||||
* a file and the size of the structure, and expects
|
||||
* you to read in the structure and return a pointer
|
||||
* to it. You must do memory allocation, etc. If
|
||||
* the data is just a number, send NULL.
|
||||
* HashLoadKeys() -- unlike HashLoad(), doesn't load the data off disk
|
||||
* until needed. This saves memory, but if you look
|
||||
* up the same key a lot, it does a disk access each
|
||||
* time.
|
||||
* You can't do Insert() or Delete() on hashtables that were loaded
|
||||
* from disk.
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* includes definition of "ulong", we hope */
|
||||
#define ulong u_long
|
||||
|
||||
#define MAGIC_KEY "CHsh" /* when we save the file */
|
||||
|
||||
#ifndef LOG_WORD_SIZE /* 5 for 32 bit words, 6 for 64 */
|
||||
#if defined (__LP64__) || defined (_LP64)
|
||||
#define LOG_WORD_SIZE 6 /* log_2(sizeof(ulong)) [in bits] */
|
||||
#else
|
||||
#define LOG_WORD_SIZE 5 /* log_2(sizeof(ulong)) [in bits] */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The following gives a speed/time tradeoff: how many buckets are *
|
||||
* in each bin. 0 gives 32 buckets/bin, which is a good number. */
|
||||
#ifndef LOG_BM_WORDS
|
||||
#define LOG_BM_WORDS 0 /* each group has 2^L_B_W * 32 buckets */
|
||||
#endif
|
||||
|
||||
/* The following are all parameters that affect performance. */
|
||||
#ifndef JUMP
|
||||
#define JUMP(key, offset) ( ++(offset) ) /* ( 1 ) for linear hashing */
|
||||
#endif
|
||||
#ifndef Table
|
||||
#define Table(x) Sparse##x /* Dense##x for dense tables */
|
||||
#endif
|
||||
#ifndef FAST_DELETE
|
||||
#define FAST_DELETE 0 /* if it's 1, we never shrink the ht */
|
||||
#endif
|
||||
#ifndef SAMEKEY_OVERWRITE
|
||||
#define SAMEKEY_OVERWRITE 1 /* overwrite item with our key on insert? */
|
||||
#endif
|
||||
#ifndef OCCUPANCY_PCT
|
||||
#define OCCUPANCY_PCT 0.5 /* large PCT means smaller and slower */
|
||||
#endif
|
||||
#ifndef MIN_HASH_SIZE
|
||||
#define MIN_HASH_SIZE 512 /* ht size when first created */
|
||||
#endif
|
||||
/* When deleting a bucket, we can't just empty it (future hashes *
|
||||
* may fail); instead we set the data field to DELETED. Thus you *
|
||||
* should set DELETED to a data value you never use. Better yet, *
|
||||
* if you don't need to delete, define INSERT_ONLY. */
|
||||
#ifndef INSERT_ONLY
|
||||
#define DELETED -2UL
|
||||
#define IS_BCK_DELETED(bck) ( (bck) && (bck)->data == DELETED )
|
||||
#define SET_BCK_DELETED(ht, bck) do { (bck)->data = DELETED; \
|
||||
FREE_KEY(ht, (bck)->key); } while ( 0 )
|
||||
#else
|
||||
#define IS_BCK_DELETED(bck) 0
|
||||
#define SET_BCK_DELETED(ht, bck) \
|
||||
do { fprintf(stderr, "Deletion not supported for insert-only hashtable\n");\
|
||||
exit(2); } while ( 0 )
|
||||
#endif
|
||||
|
||||
/* We need the following only for dense buckets (Dense##x above). *
|
||||
* If you need to, set this to a value you'll never use for data. */
|
||||
#define EMPTY -3UL /* steal more of the bck->data space */
|
||||
|
||||
|
||||
/* This is what an item is. Either can be cast to a pointer. */
|
||||
typedef struct {
|
||||
ulong data; /* 4 bytes for data: either a pointer or an integer */
|
||||
ulong key; /* 4 bytes for the key: either a pointer or an int */
|
||||
} HTItem;
|
||||
|
||||
struct Table(Bin); /* defined in chash.c, I hope */
|
||||
struct Table(Iterator);
|
||||
typedef struct Table(Bin) Table; /* Expands to SparseBin, etc */
|
||||
typedef struct Table(Iterator) TableIterator;
|
||||
|
||||
/* for STORES_PTR to work ok, cchKey MUST BE DEFINED 1st, cItems 2nd! */
|
||||
typedef struct HashTable {
|
||||
ulong cchKey; /* the length of the key, or if it's \0 terminated */
|
||||
ulong cItems; /* number of items currently in the hashtable */
|
||||
ulong cDeletedItems; /* # of buckets holding DELETE in the hashtable */
|
||||
ulong cBuckets; /* size of the table */
|
||||
Table *table; /* The actual contents of the hashtable */
|
||||
int fSaveKeys; /* 1 if we copy keys locally; 2 if keys in one block */
|
||||
int cDeltaGoalSize; /* # of coming inserts (or deletes, if <0) we expect */
|
||||
HTItem *posLastFind; /* position of last Find() command */
|
||||
TableIterator *iter; /* used in First/NextBucket */
|
||||
|
||||
FILE *fpData; /* if non-NULL, what item->data points into */
|
||||
char * (*dataRead)(FILE *, int); /* how to load data from disk */
|
||||
HTItem bckData; /* holds data after being loaded from disk */
|
||||
} HashTable;
|
||||
|
||||
/* Small keys are stored and passed directly, but large keys are
|
||||
* stored and passed as pointers. To make it easier to remember
|
||||
* what to pass, we provide two functions:
|
||||
* PTR_KEY: give it a pointer to your data, and it returns
|
||||
* something appropriate to send to Hash() functions or
|
||||
* be stored in a data field.
|
||||
* KEY_PTR: give it something returned by a Hash() routine, and
|
||||
* it returns a (char *) pointer to the actual data.
|
||||
*/
|
||||
#define HashKeySize(ht) ( ((ulong *)(ht))[0] ) /* this is how we inline */
|
||||
#define HashSize(ht) ( ((ulong *)(ht))[1] ) /* ...a la C++ :-) */
|
||||
|
||||
#define STORES_PTR(ht) ( HashKeySize(ht) == 0 || \
|
||||
HashKeySize(ht) > sizeof(ulong) )
|
||||
#define KEY_PTR(ht, key) ( STORES_PTR(ht) ? (char *)(key) : (char *)&(key) )
|
||||
#ifdef DONT_HAVE_TO_WORRY_ABOUT_BUS_ERRORS
|
||||
#define PTR_KEY(ht, ptr) ( STORES_PTR(ht) ? (ulong)(ptr) : *(ulong *)(ptr) )
|
||||
#else
|
||||
#define PTR_KEY(ht, ptr) ( STORES_PTR(ht) ? (ulong)(ptr) : HTcopy((char *)ptr))
|
||||
#endif
|
||||
|
||||
|
||||
/* Function prototypes */
|
||||
unsigned long HTcopy(char *pul); /* for PTR_KEY, not for users */
|
||||
|
||||
struct HashTable *AllocateHashTable(int cchKey, int fSaveKeys);
|
||||
void ClearHashTable(struct HashTable *ht);
|
||||
void FreeHashTable(struct HashTable *ht);
|
||||
|
||||
HTItem *HashFind(struct HashTable *ht, ulong key);
|
||||
HTItem *HashFindLast(struct HashTable *ht);
|
||||
HTItem *HashFindOrInsert(struct HashTable *ht, ulong key, ulong dataInsert);
|
||||
HTItem *HashFindOrInsertItem(struct HashTable *ht, HTItem *pItem);
|
||||
|
||||
HTItem *HashInsert(struct HashTable *ht, ulong key, ulong data);
|
||||
HTItem *HashInsertItem(struct HashTable *ht, HTItem *pItem);
|
||||
|
||||
int HashDelete(struct HashTable *ht, ulong key);
|
||||
int HashDeleteLast(struct HashTable *ht);
|
||||
|
||||
HTItem *HashFirstBucket(struct HashTable *ht);
|
||||
HTItem *HashNextBucket(struct HashTable *ht);
|
||||
|
||||
int HashSetDeltaGoalSize(struct HashTable *ht, int delta);
|
||||
|
||||
void HashSave(FILE *fp, struct HashTable *ht, int (*write)(FILE *, char *));
|
||||
struct HashTable *HashLoad(FILE *fp, char * (*read)(FILE *, int));
|
||||
struct HashTable *HashLoadKeys(FILE *fp, char * (*read)(FILE *, int));
|
||||
Reference in New Issue
Block a user