/* Gamelon(tm) File I/O Library Sample Code  C++ Language      */

/* (C)19941996 Menai Corporation(tm)  Released for public use */

 

/* Example 12. How to create and use an Index object       */

/* 12a. Creating and opening an Index object               */

 

/* An Index object is created by a WritePrimaryIndex()     *

 * function, like any other object, except that it cannot  *

 * be assigned OID keys as part of the creation routine.   *

 * A primary index supports only one target file, which is *

 * identified as part of the WritePrimaryIndex() function. *

 * An Index can be opened for use after it has been        *

 * created.  Note that the Cursor which opens an Index     *

 * must have focus on that Index object  this is not     *

 * always the situation after the Cursor has created the   *

 * Index object, because the file alteration may have been *

 * an Insert() or Append(), which ordinarily leaves the    *

 * Cursor with focus on an adjacent object.                */

 

/* Beginning file layout:    *

 *   {                }      *

 *    [#1][#2][#3]{#4}       */

 

/* The programmer wishes to include the objects in this    *

 * file in an Index object which will be placed at the     *

 * beginning of the file.  Here is the sequence of steps:  */

 

#include <stdlib.h>

#include <iostream.h>

#include "gfcursor.hpp"

 

int main(void) {

    int valid;

    CURSOR * c1 = new CURSOR("f1.g");

    c1>eCursorQueryValid(&valid);

    if (!valid)

      exit(1);

    c1>eCursorMoveIn();

/* At this point, Cursor c1 has focus on the first object,

   with OID #1.                                            */

    c1>eAltInsert();

    c1>eObjWritePrimaryIndex("f1.g");

    c1>eCursorMovePrior();

/* Now, Cursor c1 gets moved so that it gains focus on the

   new Index object.  The file structure looks like this:

   {                           }

    [Index(f1)][#1][#2][#3]{#4}

 

   Finally, in preparation for use of the Index object,

   Cursor c1 opens the index:

*/

    c1>eIndexOpen();

 

/* At this point the Index is identified with the same

   file in which it exists, and if queried for the target

   filename Cursor c1 would report that filename.  It is

   time to place some OID keys into the empty Index.

*/

 

/* 12b. Directly placing OIDs into an Index by using

   Include()                                               */

 

/* Starting with the existing file structure, the          *

 * programmer (who knows the OIDs in advance) now places   *

 * the OIDs into the Index through Cursor c1:              */

 

    c1>eIndexInclude(1UL);

    c1>eIndexInclude(2UL);

    c1>eIndexInclude(3UL);

    c1>eIndexInclude(5UL);

/* These actions place the OIDs into the index in the

   following order: 1, 2, 3, 5.  But, wait! The programmer

   made a mistake in typing #4 as #5.  No error will appear,

   because the presence in the supported file of an object

   bearing a particular OID is not checked until the first

   attempt is made to access any object through the Index.

   When that first attempt is made, the invalid OID will be

   purged automatically from the Index.  The programmer can

   check the success of the inclusions as follows:

*/

    unsigned long oid;

    if(!c1>eIndexSeekFirst())

    do {

      c1>eIndexQueryCurrent(&oid);

      cout << oid << endl();

    } while (!eIndexSeekNext())

/* This routine will disclose the OIDs in order, and the

   programmer can see that one was a mistaken entry.  Here

   is an alternative routine, which (if inserted before

   the "do" loop would purge the bad number before

   reporting the inclusions  this requires the creation

   of a second Cursor, which attempts a Move() to an object

   with the arbitrary OID of 1 (which may or may not be

   present) using the Index and thereby forces validation

   of the presence of the objects bearing supported OIDs:

*/

    // CURSOR * c2 = new CURSOR("f1.g");

    // c2>eCursorQueryValid(&valid);

    // if (!valid)

    //exit(1);

    // c2>eCursorMoveTo(1);

    // now use loop shown above

 

/* 12c. Indirectly placing OIDs into an Index by using

   Attach()                                                */

 

/* Just for practice, the programmer decides to add a new  *

 * object to the file and to the Index at the same time.   *

 * To do this, Cursor c2 is moved to the PostLast position *

 * in the file and c1  the Index Cursor  is attached   *

 * to it: from this time until c2 is detached from c1 (or  *

 * one of the Cursors is destroyed, or c1 closes the       *

 * Index) any alterations made by c1 which involve an OID  *

 * will cause that OID to be added to the Index (unless it *

 * is already present).                                    */

 

    CURSOR * c2 = new CURSOR("f1.g");

    c2>eCursorQueryValid(&valid);

    if (!valid)

      exit(1);

    c2>eCursorMoveIn();

    c2>eCursorMovePostLast();

    c1>eIndexAttachTo(c2);

/* unsigned long variable oid was declared earlier */

    oid = 0;

    c2>eAltInsert();

    c2>eObjApplyIdentity(&oid); /* which is OID 10 */

    c2>eObjWrite("Summertime");

/* Result (assuming that the programmer purged the bad OID

   #5):

   {                                     }

    [Index:1,2,3,10][#1][#2][#3]{#4}[#10]

 

   Just to clean up, the programmer now detaches Index

   Cursor c1 from Cursor c2:

*/

    c1>eIndexDetachFrom(c2);

 

/* 12d. Indirectly placing OIDs into an Index by using

   Register()                                              */

 

/* This example shows how all OIDrelated alterations to   *

 * an object can be recorded in an Index, regardless which *

 * Cursor makes the alteration.  In order to keep the      *

 * sample file small, the objects bearing OIDs #1 and #2   *

 * are removed from the file in this sequence: this will   *

 * result in their automatic deletion from the Index, as   *

 * noted below.                                            *

 * Cursor c1 is still open on the Index, and Cursor c2 is  *

 * still in PostLast position.  The programmer begins the  *

 * sequence by Registering object #4 to the Index, by      *

 * moving Cursor c2 to that object and then calling        *

 * Register():                                             */

 

    c2>eCursorMoveTo(4UL);

    c1>eIndexRegister(c2);

/* Now Cursor c2 can do other work.  It begins by getting

   rid of two objects and then moving inside of object #4

   to add new objects:

*/

    c2>eCursorMoveTo(1UL);

    c2>eAltRemove();

    c2>eAltRemove();

/* Remember that when an object is removed from a file,

   the Cursor that takes the action must have focus on

   that object; and after the removal, the Cursor will

   try to move to the next object (failing which it will

   seek a prior object).  In this case, object #2 was next

   to #1, so #2 was automatically in focus; consequently,

   it was only necessary to call Remove() a second time.

   Now the programmer can get on to the main purpose of

   this example: the addition of new objects inside object

   #4, resulting in the automatic addition of those objects

   to the Index.  We assume that the Gamelon File I/O

   Library began assigning new OIDs starting with #10.

*/

    c2>eCursorMoveTo(4UL);

    c2>eCursorMoveIn();

    c2>eCursorMovePostLast();

    c2>eAltInsert();

    c2>eObjApplyIdentity(); /* which is OID 11 */

    c2>eObjWrite('x');

    c2>eAltInsert();

    c2>eObjApplyIdentity(); /* which is OID 12 */

    c2>eObjWrite('y');

    c2>eAltInsert();

    c2>eObjApplyIdentity(); /* which is OID 13 */

    c2>eObjWrite('z');

/* Each of these OIDs has reached the Index directly, without

   the need to force an arbitrary search, because the physical

   location in the file of the newlyadded object was already

   known at the time that its OID was added to the Index.

   Here is the result of the changes:

   {                                                     }

    [Index:1,2,3,10,11,12,13][#3]{#4               }[#10]

                                    [#11][#12][#13]

 

   Note that #2 and #1 are still in the Index, though not in

   the file.  These OIDs will disappear automatically the next

   time that a search is made for an indexed object that was

   removed from the file or that was added to the Index by

   use of Include(OID): the reason is that in both of these

   circumstances the Index has no physical location for the

   objects, and none will be found when the next search

   occurs  in this case because the objects have been removed

   from the file.

*/

 

/* 12e. Moving a Cursor to an object using an OID alone    */

 

/* This capability has been illustrated already, in the    *

 * preceding section.  Note that Cursor c2 was moved       *

 * successively to the objects bearing OIDs #1 and #2.  A  *

 * move such as these, made without assistance of an       *

 * Index, can only be made within the same file.           */

 

/* 12f. Moving a Cursor to an object using an OID and an

   Index                                                   */

 

/* To avoid the limitation of moving only within the same  *

 * file, and to avoid the slowness sometimes encountered   *

 * in moving an Cursor without the help of an Index, the   *

 * Gamelon File I/O Library includes functions which allow *

 * a Cursor to designate one or more indexes to be used to *

 * assist the move.  Since a primary index (the only kind  *

 * supported internally by the Library as of this writing) *

 * supports only one file, it may be necessary to use the  *

 * assistance of more than one Index if the target object  *

 * might be found in any of several files.                 *

 * In this example we assume that file f2 contains (among  *

 * other things) an index of objects within file f1.       *

 * Cursors c1 and c2 are already open on file f1.  Now, to *

 * try out this capability, the programmer opens file f2   *

 * with Cursors c3 and c4, opens the Index with c3 and     *

 * then moves c4 to the last object in file f1.  Note that *

 * this move requires that f1 be open in the same access   *

 * mode as file f2 (and it is  both are opened in Shared *

 * mode by default).  Note also that the move will not     *

 * close file f2, because Cursor c3 is still open on it.   */

 

/* An existing file f2 is assumed, with the following      *

 * structure:                                              *

 * {                         }                             *

 *  [Index(f1):10,11,12,13]{}                              */

 

/* From this file structure, it might be assumed that the  *

 * Index contains only OIDs of objects generated at this   *

 * local computer and added to file f1, because we have    *

 * shown low numbers being applied as OIDs to objects in   *

 * the above examples.                                     *

 * As always, the programmer creates the cursors, checks   *

 * their validity and moves it to the desired location:    */

    CURSOR * c3 = new CURSOR("f2.g");

    c3>eCursorQueryValid(&valid);

    if (!valid)

      exit(1);

    c3>eCursorMoveIn();

    CURSOR * c4 = new CURSOR("f2.g");

    c4>eCursorQueryValid(&valid);

    if (!valid)

      exit(1);

    c4>eCursorMoveIn();

/* Since there are objects within file f2, Cursor c3 gains

   focus on the first object, which is the Index that

   supports file f1.  The programmer now opens the Index

   with c3  and moves c4 to the object bearing OID #10.

*/

    c3>eIndexOpen();

    c4>eCursorMoveTo(4UL, c3);

/* The result is that c4 moves to the last object in file f1,

   which is the object bearing OID #10.

*/

 

/* 12g. Using Indexes and Associate() to help move a

   Cursor                                                  */

 

/* When there is a need to use multiple indexes, or when   *

 * the same index will be used repeatedly, the Library     *

 * provides a way to Associate one or more indexes with a  *

 * particular cursor.  To try out this capability, the     *

 * programmer moves Cursor c4 back to file f2 (which is    *

 * still open with Cursor c3), and then associates Index   *

 * Cursors c1 and c3 (which are in different files!).      *

 * Finally, Cursor c4 moves to the object bearing OID #3,  *

 * which is found in the Index accessed through c1.        */

    c4>eCursorMoveTo(c3);

/* note that the move does not make c4 open the index object */

    c4>eCursorAssociate(c3);

    c4>eCursorAssociate(c1);

    c4>eCursorMoveTo(3UL, NULL);

/* NULL: use Associated indexes */

/* The result is that Cursor c4 moves to the second object

   in file f1, which is the object bearing OID #3.  The Null

   Cursor was specified as a means of invoking use of the

   previouslyAssociated Cursors c1 and c3.

   Our programmer has now finished this lengthy example, so

   all that remains to do is to clean up, which requires the

   deletion of Cursors c1, c2, c3 and c4.  Note that the

   deletion of Cursors c1 and c3 will automatically close

   the Indexes which they held open, and the deletion of

   the final Cursor open on each file will close that file.

*/

    delete c1;

    delete c2;

    delete c3;

    delete c4;

} /* end of main() */

Download this sample source code

Return to Samples List

 Home | Product | Consulting | Programming | Reviews | Company | Site Map | Guest Book

 Menai Corporation, 1010 El Camino Real, Suite 300, Menlo Park, California 94025-4335
 800-GAMELON (800-426-3566) (US only), 650-853-6450 (voice), 650-853-6453 (fax)
 Questions about our products and services:
info@menai.com.
 Comments about this web site:
webmaster@menai.com.

Copyright © 1996-98 Menai Corporation. All Rights Reserved. Menai, Gamelon and gamelon(stylized) are worldwide trademarks of Menai Corporation, registered in the United States of America, and the .[g] logo is a worldwide trademark of Menai Corporation. All other trademarks are owned by their respective owners.