1
0
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:
Mirko Lindner
2010-02-04 12:33:47 +01:00
commit cddcd72e33
311 changed files with 59414 additions and 0 deletions

View 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

View 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

View 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;
}

File diff suppressed because it is too large Load Diff

View 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));