230 lines
7.6 KiB
C
230 lines
7.6 KiB
C
/*
|
|
* local defines for the table module
|
|
*
|
|
* Copyright 2000 by Gray Watson.
|
|
*
|
|
* This file is part of the table package.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose and without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies,
|
|
* and that the name of Gray Watson not be used in advertising or
|
|
* publicity pertaining to distribution of the document or software
|
|
* without specific, written prior permission.
|
|
*
|
|
* Gray Watson makes no representations about the suitability of the
|
|
* software described herein for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
* The author may be reached via http://256.com/gray/
|
|
*
|
|
* $Id: table_loc.h,v 1.11 2000/03/09 03:30:42 gray Exp $
|
|
*/
|
|
|
|
#ifndef __TABLE_LOC_H__
|
|
#define __TABLE_LOC_H__
|
|
|
|
#ifndef unix
|
|
#define NO_MMAP
|
|
#endif
|
|
|
|
#ifndef BITSPERBYTE
|
|
#define BITSPERBYTE 8
|
|
#endif
|
|
#ifndef BITS
|
|
#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
|
|
#endif
|
|
|
|
#define TABLE_MAGIC 0xBADF00D /* very magic magicness */
|
|
#define LINEAR_MAGIC 0xAD00D00 /* magic value for linear struct */
|
|
#define DEFAULT_SIZE 1024 /* default table size */
|
|
#define MAX_ALIGNMENT 128 /* max alignment value */
|
|
|
|
/*
|
|
* Maximum number of splits. This should mean that these routines can
|
|
* handle at least 2^128 different values (that's _quite_ a few). And
|
|
* then you can always increase the value.
|
|
*/
|
|
#define MAX_QSORT_SPLITS 128
|
|
|
|
/*
|
|
* Maximum number of entries that must be in list for it to be
|
|
* partitioned. If there are fewer elements then just do our
|
|
* insertion sort.
|
|
*/
|
|
#define MAX_QSORT_MANY 8
|
|
|
|
/*
|
|
* Macros.
|
|
*/
|
|
|
|
/* returns 1 when we should grow or shrink the table */
|
|
#define SHOULD_TABLE_GROW(tab) ((tab)->ta_entry_n > (tab)->ta_bucket_n * 2)
|
|
#define SHOULD_TABLE_SHRINK(tab) ((tab)->ta_entry_n < (tab)->ta_bucket_n / 2)
|
|
|
|
/*
|
|
* void HASH_MIX
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* Mix 3 32-bit values reversibly. For every delta with one or two
|
|
* bits set, and the deltas of all three high bits or all three low
|
|
* bits, whether the original value of a,b,c is almost all zero or is
|
|
* uniformly distributed.
|
|
*
|
|
* If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c
|
|
* have at least 1/4 probability of changing. If mix() is run
|
|
* forward, every bit of c will change between 1/3 and 2/3 of the
|
|
* time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
|
|
*
|
|
* HASH_MIX() takes 36 machine instructions, but only 18 cycles on a
|
|
* superscalar machine (like a Pentium or a Sparc). No faster mixer
|
|
* seems to work, that's the result of my brute-force search. There
|
|
* were about 2^68 hashes to choose from. I only tested about a
|
|
* billion of those.
|
|
*/
|
|
#define HASH_MIX(a, b, c) \
|
|
do { \
|
|
a -= b; a -= c; a ^= (c >> 13); \
|
|
b -= c; b -= a; b ^= (a << 8); \
|
|
c -= a; c -= b; c ^= (b >> 13); \
|
|
a -= b; a -= c; a ^= (c >> 12); \
|
|
b -= c; b -= a; b ^= (a << 16); \
|
|
c -= a; c -= b; c ^= (b >> 5); \
|
|
a -= b; a -= c; a ^= (c >> 3); \
|
|
b -= c; b -= a; b ^= (a << 10); \
|
|
c -= a; c -= b; c ^= (b >> 15); \
|
|
} while(0)
|
|
|
|
#define SET_POINTER(pnt, val) \
|
|
do { \
|
|
if ((pnt) != NULL) { \
|
|
(*(pnt)) = (val); \
|
|
} \
|
|
} while(0)
|
|
|
|
/*
|
|
* The following macros take care of the mmap case. When we are
|
|
* mmaping a table from a disk file, all of the pointers in the table
|
|
* structures are replaced with offsets into the file. The following
|
|
* macro, for each pointer, adds the starting address of the mmaped
|
|
* section onto each pointer/offset turning it back into a legitimate
|
|
* pointer.
|
|
*/
|
|
#ifdef NO_MMAP
|
|
|
|
#define TABLE_POINTER(table, type, pnt) (pnt)
|
|
|
|
#else
|
|
|
|
#define TABLE_POINTER(tab_p, type, pnt) \
|
|
((tab_p)->ta_mmap == NULL || (pnt) == NULL ? (pnt) : \
|
|
(type)((char *)((tab_p)->ta_mmap) + (long)(pnt)))
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Macros to get at the key and the data pointers
|
|
*/
|
|
#define ENTRY_KEY_BUF(entry_p) ((entry_p)->te_key_buf)
|
|
#define ENTRY_DATA_BUF(tab_p, entry_p) \
|
|
(ENTRY_KEY_BUF(entry_p) + (entry_p)->te_key_size)
|
|
|
|
/*
|
|
* Table structures...
|
|
*/
|
|
|
|
/*
|
|
* HACK: this should be equiv as the table_entry_t without the key_buf
|
|
* char. We use this with the ENTRY_SIZE() macro above which solves
|
|
* the problem with the lack of the [0] GNU hack. We use the
|
|
* table_entry_t structure to better map the memory and make things
|
|
* faster.
|
|
*/
|
|
typedef struct table_shell_st {
|
|
unsigned int te_key_size; /* size of data */
|
|
unsigned int te_data_size; /* size of data */
|
|
struct table_shell_st *te_next_p; /* pointer to next in the list */
|
|
/* NOTE: this does not have the te_key_buf field here */
|
|
} table_shell_t;
|
|
|
|
/*
|
|
* Elements in the bucket linked-lists. The key[1] is the start of
|
|
* the key with the rest of the key and all of the data information
|
|
* packed in memory directly after the end of this structure.
|
|
*
|
|
* NOTE: if this structure is changed, the table_shell_t must be
|
|
* changed to match.
|
|
*/
|
|
typedef struct table_entry_st {
|
|
unsigned int te_key_size; /* size of data */
|
|
unsigned int te_data_size; /* size of data */
|
|
struct table_entry_st *te_next_p; /* pointer to next in the list */
|
|
unsigned char te_key_buf[1]; /* 1st byte of key buf */
|
|
} table_entry_t;
|
|
|
|
/* external structure for debuggers be able to see void */
|
|
typedef table_entry_t table_entry_ext_t;
|
|
|
|
/* main table structure */
|
|
typedef struct table_st {
|
|
unsigned int ta_magic; /* magic number */
|
|
unsigned int ta_flags; /* table's flags defined in table.h */
|
|
unsigned int ta_bucket_n; /* num of buckets, should be 2^X */
|
|
unsigned int ta_entry_n; /* num of entries in all buckets */
|
|
unsigned int ta_data_align; /* data alignment value */
|
|
table_entry_t **ta_buckets; /* array of linked lists */
|
|
table_linear_t ta_linear; /* linear tracking */
|
|
struct table_st *ta_mmap; /* mmaped table */
|
|
unsigned long ta_file_size; /* size of on-disk space */
|
|
|
|
void *ta_mem_pool; /* pointer to some memory pool */
|
|
table_mem_alloc_t ta_alloc_func; /* memory allocation function */
|
|
table_mem_resize_t ta_resize_func; /* memory resize function */
|
|
table_mem_free_t ta_free_func; /* memory free function */
|
|
} table_t;
|
|
|
|
/* external table structure for debuggers */
|
|
typedef table_t table_ext_t;
|
|
|
|
/* local comparison functions */
|
|
typedef int (*compare_t)(const void *element1_p, const void *element2_p,
|
|
table_compare_t user_compare,
|
|
const table_t *table_p, int *err_bp);
|
|
|
|
/*
|
|
* to map error to string
|
|
*/
|
|
typedef struct {
|
|
int es_error; /* error number */
|
|
char *es_string; /* assocaited string */
|
|
} error_str_t;
|
|
|
|
static error_str_t errors[] = {
|
|
{ TABLE_ERROR_NONE, "no error" },
|
|
{ TABLE_ERROR_PNT, "invalid table pointer" },
|
|
{ TABLE_ERROR_ARG_NULL, "buffer argument is null" },
|
|
{ TABLE_ERROR_SIZE, "incorrect size argument" },
|
|
{ TABLE_ERROR_OVERWRITE, "key exists and no overwrite" },
|
|
{ TABLE_ERROR_NOT_FOUND, "key does not exist" },
|
|
{ TABLE_ERROR_ALLOC, "error allocating memory" },
|
|
{ TABLE_ERROR_LINEAR, "linear access not in progress" },
|
|
{ TABLE_ERROR_OPEN, "could not open file" },
|
|
{ TABLE_ERROR_SEEK, "could not seek to position in file" },
|
|
{ TABLE_ERROR_READ, "could not read from file" },
|
|
{ TABLE_ERROR_WRITE, "could not write to file" },
|
|
{ TABLE_ERROR_MMAP_NONE, "no mmap support compiled in library" },
|
|
{ TABLE_ERROR_MMAP, "could not mmap the file" },
|
|
{ TABLE_ERROR_MMAP_OP, "operation not valid on mmap files" },
|
|
{ TABLE_ERROR_EMPTY, "table is empty" },
|
|
{ TABLE_ERROR_NOT_EMPTY, "table contains data" },
|
|
{ TABLE_ERROR_ALIGNMENT, "invalid alignment value" },
|
|
{ TABLE_ERROR_COMPARE, "problems with internal comparison" },
|
|
{ TABLE_ERROR_FREE, "memory free error" },
|
|
{ 0 }
|
|
};
|
|
|
|
#define INVALID_ERROR "invalid error code"
|
|
|
|
#endif /* ! __TABLE_LOC_H__ */
|