Example
In this example, key-value pairs of character strings and offsets to RWDateTimes 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>
int main(){
RWCString name;
RWDateTime birthday;
RWFileManager fm("birthday.dat");
RWBTreeOnDisk btree(fm); // 1
while (std::cin >> name) // 2
{
std::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 is 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 exits 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 RWDateTime 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.
After you store the names and birthdates on a file, you can retrieve them like this:
 
#include <rw/disktree.h>
#include <rw/filemgr.h>
#include <rw/cstring.h>
#include <rw/rwdate.h>
#include <rw/rstream.h>
int main(){
RWCString name;
RWDateTime birthday;
RWFileManager fm("birthday.dat");
RWBTreeOnDisk btree(fm);
while(1)
{
std::cout << "Give name: ";
if (!( std::cin >> name)) break; // 1
RWoffset loc = btree.findValue(name); // 2
if (loc==RWNIL) // 3
std::cerr << "Not found.\n";
else
{
fm.SeekTo(loc); // 4
fm >> birthday; // 5
std::cout << "Birthday is " << birthday << std::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>
int 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>
int 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;
}