#ifndef _BTREE_H_ #define _BTREE_H_ #define KEYSIZE 12 typedef struct simpRec { int value ; /* MUST be stored in little endian order */ char name[KEYSIZE] ; } simpRecT ; #define RECSINBLK 7 #define METAPNTR RECSINBLK /* The first RECSINBLK simpRecT records of the block are * the real nodes. The last record, indexed by METAPNTR, * is really a metadata field for recording information * documented below. It would be better to use unions, * but not enough students have seen them. */ typedef struct blockRec { simpRecT recs[RECSINBLK+1] ; } blockRecT ; /* * These are the invariants used by this implementation * to maintain the btree. */ /* Within the last simpRecT of a node N, the last record * is used as follows: * N.recs[METAPNTR].name[0]: * number of records used within N, * N.recs[METAPNTR].name[1]: * type of the node -- interior and/or leaf */ /* Macros for accessing/setting metadata information */ #define getUsedRecords(NP) ( (int) (NP)->recs[METAPNTR].name[0] ) #define setUsedRecords(NP,X) ( (NP)->recs[METAPNTR].name[0] = (char) (X) ) #define isLeaf(NP) ( (NP)->recs[METAPNTR].name[1] ) #define setLeaf(NP) ( (NP)->recs[METAPNTR].name[1] = 1 ) #define clearLeaf(NP) ( (NP)->recs[METAPNTR].name[1] = 0 ) /* invariant for the node data structure, N * * There are getUsedRecords(&N) elements of N.data that are in use * These getUsedRecords(&N) elements are sorted by the X.rec[*].name field * getUsedRecords(&N) <= RECSINBLK * If ! isLeaf(&N) * the block corresponds to an interior node * for 0<=i<=getUsedRecords(&N) * N.data[i].value points to a subtree that contains all database * names greater than N.data[i-1].name (if i>0) and * less than or equal to N.data[i].name (if i