In this example, key-value pairs of character strings and offsets to RWDates representing birthdays are stored. Given a name, you can retrieve a birthdate from disk.
#include <rw/disktree.h> #include <rw/filemgr.h> #include <rw/cstring.h> #include <rw/rwdate.h> #include <rw/rstream.h> main(){ RWCString name; RWDate birthday; RWFileManager fm("birthday.dat"); RWBTreeOnDisk btree(fm); // 1 while (cin >> name) // 2 { cin >> birthday; // 3 RWoffset loc = fm.allocate(birthday.binaryStoreSize());// 4 fm.SeekTo(loc); // 5 fm << birthday; // 6 btree.insertKeyAndValue(name, loc); // 7 } return 0; }
Here's the line-by-line description:
//1 | Construct a B-tree. The default constructor is used, resulting in a key length of 16 characters. |
//2 | Read the name from standard input. This loop will exit when EOF is reached. |
//3 | Read the corresponding birthday. |
//4 | Allocate enough space from the RWFileManager to store the birthday. Function binaryStoreSize() is a member function in most Rogue Wave classes. It returns the number of bytes necessary to store an object in an RWFile. If you are storing an entire RWCollection, or using one of the methods recursiveSaveOn() or operator<<(RWFile&, RWCollectable), be sure to use recursiveStoreSize() instead. |
//5 | Seek to the location where the RWDate will be stored. |
//6 | Store the date at that location. Most Rogue Wave classes have an overloaded version of the streaming operators << and >>. |
//7 | Insert the key and offset to the object in the B-tree. |
Having stored the names and birthdates on a file, here's how you might retrieve them:
#include <rw/disktree.h> #include <rw/filemgr.h> #include <rw/cstring.h> #include <rw/rwdate.h> #include <rw/rstream.h> main(){ RWCString name; RWDate birthday; RWFileManager fm("birthday.dat"); RWBTreeOnDisk btree(fm); while(1) { cout << "Give name: "; if (!( cin >> name)) break; // 1 RWoffset loc = btree.findValue(name); // 2 if (loc==RWNIL) // 3 cerr << "Not found.\n"; else { fm.SeekTo(loc); // 4 fm >> birthday; // 5 cout << "Birthday is " << birthday << endl; // 6 } } return 0; }
Here is a description of the program:
//1 | The program accepts names until encountering an EOF. |
//2 | The name is used as a key to RWBTreeOnDisk, which returns the associated value, an offset, into the file. |
//3 | Check to see whether the name was found. |
//4 | If the name is valid, use the value to seek to the spot where the associated birthdate is stored. |
//5 | Read the birthdate from the file. |
//6 | Print it out. |
With a little effort, you can easily have more than one B-tree active in the same file. This allows you to maintain indexes on more than one key. Here's how you would create three B-trees in the same file:
#include <rw/disktree.h> #include <rw/filemgr.h> main(){ RWoffset rootArray[3]; RWFileManager fm("index.dat"); RWoffset rootArrayOffset = fm.allocate(sizeof(rootArray)); for (int itree=0; itree<3; itree++) { RWBTreeOnDisk btree(fm, 10, RWBTreeOnDisk::create); rootArray[itree] = btree.baseLocation(); } fm.SeekTo(fm.start()); fm.Write(rootArray, 3); return 0; }
And here is how you could open the three B-trees:
#include <rw/disktree.h> #include <rw/filemgr.h> main(){ RWoffset rootArray[3]; // Location of the tree roots RWBTreeOnDisk* treeArray[3]; // Pointers to the RWBTreeOnDisks RWFileManager fm("index.dat"); fm.SeekTo(fm.start()); // Recover locations of root nodes fm.Read(rootArray, 3); for (int itree=0; itree<3; itree++) { // Initialize the three trees: treeArray[itree] = new RWBTreeOnDisk(fm, 10, // Max. nodes cached RWBTreeOnDisk::autoCreate, // Will read old tree 16, // Key length FALSE, // Do not ignore nulls rootArray[itree] // Location of root ); } . . . for (itree=0; itree<3; itree++) // Free heap memory delete treeArray[itree]; return 0; }