|
|
/*
* rhizome.h * * author: John R. Douceur * date: 28 April 1997 * * This header file defines structures, function prototypes, and macros for * the rhizome database. The code is object-oriented C, transliterated from * a C++ implementation. * * The rhizome is a database that stores patterns containing wildcards. * Each pattern defines a set of keys that it matches; if a pattern contains * N wildcards, then it matches 2^N keys. Since each pattern can match * multiple keys, it is possible for a given key to match multiple patterns * in the database. The rhizome requires that all patterns stored therein * have a strict hierarchical interrelationship. Two patterns may match no * common keys (in which case the patterns are said to be independent), or * one pattern may match all the keys matched by a second pattern as well as * additonal keys (in which case the second pattern is said to be more general * than the first, and the first more specific than the second). The database * will not accept two patterns which match some keys in common but each of * which also matches additional keys that the other does not. * * The database can be searched for patterns that match a given search key. * When the database is searched for a given key, the most specifically * matching pattern is found. If no patterns in the database match the key, * an appropriate indication is returned. * * Because this code is C, rather than C++, it is not possible to hide as * much of the implementation from the client code as one might wish. * Nonetheless, there is an attempt to isolate the client from some of the * implementation details through the use of macros. Below is described each * of the functions and macros necessary to use the rhizome database. * */
#ifndef _INC_RHIZOME
#define _INC_RHIZOME
#ifdef __cplusplus
extern "C" { #endif
/*
* There are two basic structures employed: the RhizomeNode and the Rhizome. * Ideally, these would be completely hidden from the client, but the macro * GetReferenceFromPatternHandle requires knowledge of the structure's * definition. It is strongly urged that the client not directly refer to any * of the fields of either of these structures. To support the documentation * of the accompanying rhizome.c file, these structures are annotated with * internal comments, but these can be ignored by the reader who wishes only * to understand how to write client code for the rhizome. * * The client refers to a pattern by its PatternHandle. This is typedefed to * a pointer to RhizomeNode, but this fact should be ignored by the client, * since it is an implementation detail. * */
//#include <stdlib.h>
//#include <malloc.h>
struct _RhizomeNode { // This structure is used for both branch nodes and leaf nodes. The two
// are distinguished by the value of the pivot_bit field. For branch
// nodes, pivot_bit < keybits, and for leaf nodes, pivot_bit == keybits.
int pivot_bit; // for branch nodes, bit of key on which to branch
union { struct // data for branch node
{ struct _RhizomeNode *children[2]; // pointers to children in search
} branch; struct // data for leaf node
{ void *reference; // reference value supplied by client
struct _RhizomeNode *godparent; // pointer to more general pattern
} leaf; } udata; char cdata[1]; // space for storing value, mask, and imask fields
};
typedef struct _RhizomeNode RhizomeNode;
struct _Rhizome { int keybits; // number of bits in key
int keybytes; // number of bytes in key, calculated from keybits
RhizomeNode *root; // root of search trie
};
typedef struct _Rhizome Rhizome;
// The client uses PatternHandle to refer to patterns stored in the database.
typedef RhizomeNode *PatternHandle;
/*
* The client interface to the rhizome is provided by five functions and two * macros. It is expected that the client will first instantiate a database, * either on the stack or the heap, and then insert patterns with corresponding * reference information into the database. When the client then performs a * search on a key, the client wishes to know which pattern most specifically * matches the key, and it ultimately wants the reference information * associated with the most specifically matching pattern. * */
// A rhizome may be allocated on the stack simply by declaring a variable of
// type Rhizome. To allocate it on the heap, the following macro returns a
// pointer to a new Rhizome structure. If this macro is used, a corresponding
// call to free() must be made to deallocate the structure from the heap.
//
//#define NEW_Rhizome ((Rhizome *)malloc(sizeof(Rhizome)))
#define AllocateRhizome(_r) GpcAllocMem(&(_r), sizeof(Rhizome), RhizomeTag)
#define FreeRhizome(_r) GpcFreeMem((_r), RhizomeTag)
// Since this is not C++, the Rhizome structure is not self-constructing;
// therefore, the following constructor code must be called on the Rhizome
// structure after it is allocated. The argument keybits specifies the size
// (in bits) of each pattern that will be stored in the database.
//
void constructRhizome( Rhizome *rhizome, int keybits);
// Since this is not C++, the Rhizome structure is not self-destructing;
// therefore, the following destructor code must be called on the Rhizome
// structure before it is deallocated. However, if the client code can be
// sure, based upon its usage of the database, that all patterns have been
// removed before the structure is deallocated, then this function is
// unnecessary.
//
void destructRhizome( Rhizome *rhizome);
// Once the Rhizome structure has been allocated and constructed, patterns can
// be inserted into the database. Each pattern is specified by a value and a
// mask. Each bit of the mask determines whether the bit position is specified
// or is a wildcard: A 1 in a mask bit indicates that the value of that bit is
// specified by the pattern; a 0 indicates that the value of that bit is a
// wildcard. If a mask bit is 1, then the corresponding bit in the value field
// indicates the specified value of that bit. Value and mask fields are passed
// as arrays of bytes.
//
// The client also specifies a reference value, as a void pointer, that it
// wishes to associate with this pattern. When the pattern is installed, the
// insertRhizome function returns a pointer to a PatternHandle. From the
// PatternHandle can be gotten the reference value via the macro
// GetReferenceFromPatternHandle.
//
// If the new pattern conflicts with a pattern already installed in the
// database, meaning that the two patterns match some keys in common but each
// also matches additional keys that the other does not, then the new pattern
// is not inserted, and a value of 0 is returned as the PatternHandle.
//
PatternHandle insertRhizome( Rhizome *rhizome, char *value, char *mask, void *reference, ulong *status);
// This function removes a pattern from the rhizome. The pattern is specified
// by the PatternHandle that was returned by the insertRhizome function. No
// checks are performed to insure that this is a valid handle, so the client
// must discard the handle after it has called removeRhizome.
//
void removeRhizome( Rhizome *rhizome, PatternHandle phandle);
// This function searches the database for the pattern that most specifically
// matches the given key. The key is passed as an array of bytes. When the
// most specific match is found, the PatternHandle of that matching pattern is
// returned. From the PatternHandle can be gotten the reference value via the
// macro GetReferenceFromPatternHandle. If no pattern in the database is found
// to match the key, then a value of 0 is returned as the PatternHandle.
//
PatternHandle searchRhizome( Rhizome *rhizome, char *key);
// To get the client-supplied reference value from a PatternHandle, the
// following macro should be used. The client should not make assumptions
// about the details of the RhizomeNode structure, nor should it even assume
// that the PatternHandle is a pointer to a RhizomeNode.
//
#define GetReferenceFromPatternHandle(phandle) ((PatternHandle)phandle)->udata.leaf.reference
#define GetKeyPtrFromPatternHandle(_r,phandle) (((PatternHandle)phandle)->cdata)
#define GetMaskPtrFromPatternHandle(_r,phandle) (((PatternHandle)phandle)->cdata + (_r)->keybytes)
#define GetKeySizeBytes(_r) ((_r)->keybytes)
#ifdef __cplusplus
} #endif
#endif /* _INC_RHIZOME */
|