/* * e4graphimpl.h -- * * This file contains the definition of the implementation part of the * e4Graph library. It defines the following classes: * * e4_RefCounter -- A base class used to manage lifecycle. * e4_StorageImpl -- Storage independent implementation of tree * data storage. * e4_NodeImpl -- An implementation of a node. * e4_VertexImpl -- An implementation of a vertex. * * Copyright (c) 2000-2003, JYL Software Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __E4_GRAPHIMPL_H__ #define __E4_GRAPHIMPL_H__ #if (defined(__GNUC__)) || (!defined(_WIN32)) #include #endif #if defined (_MSC_VER_) #include #else #include #endif /* * Include public side of e4Graph API. */ #include "e4graph.h" /* * This flag is for internal use and should not overlap with E4_OPENGC, * E4_GCBEFORECOMMIT and E4_AUTOGC. * * It is used by callers to indicate that * an explicit GC was requested by the user program, and this request is * always respected, whether or not a GC is needed. */ #define E4_REQUESTEDGC (1<<0) /* * This defines the size of the hash key for callback records. The hash * key is composed of an int + 2 void *, so on 32-bit and 64-bit machines * this has different sizes, which is why it must be parameterized. */ #define E4_CALLBACKKEYSIZE \ ((sizeof(int) + (sizeof(void *) * 2)) / sizeof(int)) /* * The value of E4_NEXTNONE is used to indicate the end of a chain * of records. */ #define E4_NEXTNONE -1 /* * This flag is used to indicate that a detach callback was already * delivered for this node or vertex. It is reset when the vertex or * node becomes attached again, so that subsequent detach callbacks * can also be delivered. * * This flag is stored into the flags private instance variable in * e4_NodeImpl and e4_VertexImpl instances. */ #define E4_CBDETACHDELIVERED (1<<0) /*********************************************************************** * * Stack of integers API: * *********************************************************************** */ /* * This class stores a stack of ints. */ class e4_DLL e4_IntStack { private: int next; int size; int *stack; public: /* * Constructor: */ e4_IntStack(); /* * Destructor: */ virtual ~e4_IntStack(); /* * Push and pop operations. */ void Push(int id); bool Pop(int *idp); void Reset(); }; /*********************************************************************** * * e4Graph internal API proper: * *********************************************************************** */ /* * The e4_RefCounter class: * * This class is the base class for all of the e4 classes, and implements * simple refcount controlled lifecycle mgmt for objects. Objects start out * with a zero refcount, and when the refcount goes back to zero, a virtual * method NotReferenced is called. This allows the derived class to decide * what to do. */ class e4_DLL e4_RefCounter { private: /* * This field contains the current number of outstanding references * to this object. */ int refCount; /* * User level data attached to this instance. */ void *userData; protected: /* * Constructor: */ e4_RefCounter() : refCount(0), userData(NULL) {} /* * This method, which must be supplied by derived classes, is called * each time the reference count goes back to zero. */ virtual void NotReferenced() = 0; public: /* * Reference count management: */ inline void IncrRefCount() { refCount++; #ifdef DEBUG_REFCOUNT fprintf(stderr, "Incr 0x%x: refcount %d\n", this, refCount); #endif } inline void DecrRefCount() { refCount--; #ifdef DEBUG_REFCOUNT fprintf(stderr, "Decr 0x%x: refcount %d\n", this, refCount); #endif if (refCount <= 0) { NotReferenced(); } } /* * Returns the current reference count. */ inline int RefCount() const { return refCount; } /* * These operations manipulate user-level data attached to each * instance. */ inline void SetTransientUserData(void *d) { userData = d; } inline void *GetTransientUserData() { return userData; } /* * Is this instance valid? This method *must* be overridden * by sub-classes. */ virtual bool IsValid() const = 0; /* * What's the "kind" of this class? Must be implemented by * subclasses. */ virtual e4_RefKind Kind() const = 0; }; /* * These constants are used to denote GC states for nodes and vertices: */ #define E4_GCNKR (1<<0) /* Node known reachable. */ #define E4_GCNRU (1<<1) /* Node reachability unknown. */ #define E4_GCNKU (1<<2) /* Node known unreachable. */ #define E4_GCNSN (1<<3) /* Node examined by current GC. */ #define E4_GCVKR (1<<4) /* Vertex known reachable. */ #define E4_GCVRU (1<<5) /* Vertex reachability unknown. */ #define E4_GCVKU (1<<6) /* Vertex known unreachable. */ #define E4_GCVSN (1<<7) /* Veetex examined by current GC. */ /* * The e4_StorageImpl class: * * NOTE: Because most of the operations in this class use c4_Property * instances which are declared extern but not exported, this class cannot * have any inline operations (or at least it cannot have any inline * operations that use these instances...) */ class e4_DLL e4_StorageImpl : public e4_RefCounter { private: bool commit; /* Should the storage be committed * when the e4_StorageImpl instance is * destroyed? */ bool stable; /* If the storage contains any changes * that haven't been committed yet, * this is false. */ bool gcAtCommit; /* Does every commit do a GC? */ e4_HashTable *activeNodes; /* Hash table for nodes that * have been loaded in-memory * to allow returning the same * pointer on multiple requests * for a specific node. */ e4_HashTable *activeVertices; /* Hash table for vertices that * habe been loaded in-memory * to allow returning the same * pointer on multiple requests * for a specific vertex. */ e4_HashTable *nameHash; /* Hash table to map from * vertex names to indices in * the "names" view. Used to * allow use of integer indices * for vertex names instead of * the more inefficient string * values. */ e4_HashTable *callbacks; /* Hash table for callbacks defined * for this storage. */ int callbacksPresent; /* Bitmap for notating that a certain * kind of callback is present. This * is used to efficiently decide if * we need to invoke the callback * mechanism for a given kind of * event. */ int statemask; /* All states that are turned on * have corresponding bits in this * variable turned on. */ int perms; /* What storage permissions are * in effect for this storage? */ bool destroyed; /* Has this storage been destroyed * already? */ char *GCState; /* Vector of bytes for recording * the state of the garbage collector * and memory management. Bits in this * vector are defined above. */ int GCStateLength; /* How long is the GCState vector? */ int timestamp; /* Timestamp of last event. */ int eventTimeStamps[E4_LASTUSERDEFINEDEVENTCODE+1]; /* Records time stamps for * when significant events occur. */ protected: char *drivername; /* The name of the storage driver * being used by this storage. */ char *name; /* Unique name for storage. */ private: e4_StorageImpl(); /* The default constructor is private * to prevent it from being called. */ e4_StorageImpl(const e4_StorageImpl &); /* Copy constructor cannot be * called either. */ void operator= (const e4_StorageImpl *); /* Nor assignment. */ /* * These operations are for use by e4_StorageImpl only: */ void InitializeNameHash(); void InitializeNodeHash(); void InitializeVertexHash(); void InitializeCallbackHash(); public: /* * Use this static function to get an e4_StorageImpl: */ static e4_StorageImpl *GetStorage(const char *name, const char *drivernm, int statemask, int perms); /* * Use this static function to get version information out of * an existing storage to identify the version of e4Graph that * wrote that storage. */ static bool GetStorageVersionInfo(const char *fname, const char *drivername, int &maj, int &min, e4_ReleaseStatus &rs, int &ri); /* * Set and get the state bits. */ inline int SetState(int newstate) { int oldstate = statemask; statemask = newstate; return oldstate; } inline int GetState() const { return statemask; } /* * Get the storage permissions: */ inline int GetPermissions() const {return perms;} /* * Is this storage stable? Mark the storage as stable or unstable. */ inline bool IsStable() {return stable;}; inline bool IsUnstable() {return stable ? false : true;}; inline void MarkUnstable() { bool changed = (stable == true) ? true : false; stable = false; if (changed) { RecordTimeStamp(E4_ECCHANGESTG); if (HasCallbacks(E4_ECCHANGESTG)) { CauseEventInternal(E4_ECCHANGESTG, this, (void *) stable); } } }; inline void MarkStable() { bool changed = (stable == false) ? true : false; stable = true; if (changed) { RecordTimeStamp(E4_ECCHANGESTG); if (HasCallbacks(E4_ECCHANGESTG)) { CauseEventInternal(E4_ECCHANGESTG, this, (void *) stable); } } }; /* * APIs associated with new GC mechanism: */ bool NewPartialGC(bool fullclean); void NewFullGC(); void SpanReachable(); bool SpanUnreachable(); void SweepUnreachable(); bool NewlyUnreachableEntities(); /* * Commit the storage: */ inline bool Commit() { if ((perms & E4_SPCOMMIT) == 0) { return false; } if (DRV_Commit()) { MarkStable(); RecordTimeStamp(E4_ECCOMMITSTG); return true; } return false; } /* * Copy this storage to another: */ inline bool CopyTo(e4_StorageImpl *osp) { if ((osp == NULL) || ((osp->perms & (E4_SPMODIFY | E4_SPCOPYTO)) != (E4_SPMODIFY | E4_SPCOPYTO)) || ((perms & E4_SPCOPYFROM) == 0)) { return false; } if (DRV_CopyTo(osp)) { osp->MarkUnstable(); osp->RecordTimeStamp(E4_ECCOPYTOSTG); RecordTimeStamp(E4_ECCOPYFRMSTG); return true; } return false; } /* * Destroy this storage: */ inline void Destroy() { if (destroyed) { return; } destroyed = true; if ((perms & E4_SPMODIFY) == 0) { return; } DRV_Destroy(); } /* * Time stamp mechanism: */ inline int GetTimeStamp() const {return timestamp;} int GetTimeStampFor(int em) const; bool HasOccurredSince(int ts, int em) const; void RecordTimeStamp(int em); /* * IMPL wrappers for driver functions called from the INTF layer: */ inline e4_VertexImpl *FindNextVertex(int vertexID, e4_VisitMethod vm, int vv, int nameID, int nodeID, int parentID, e4_VertexType typeID, e4_DetachChoice dc) const { return DRV_FindNextVertex(vertexID, vm, vv, nameID, nodeID, parentID, typeID, dc); } inline e4_NodeImpl *FindNextNode(int nodeID) const { return DRV_FindNextNode(nodeID); } inline bool GetStatistic(e4_Space sp, e4_SpaceStat st, int &dv) { return DRV_GetStatistic(sp, st, dv); } inline int HashCode() const {return DRV_HashCode();} inline void DoGC() { if ((perms & E4_SPMODIFY) == 0) { return; } DRV_DoGC(E4_REQUESTEDGC); MarkUnstable(); } inline void DoPartialGC() { if ((perms & E4_SPMODIFY) == 0) { return; } DRV_DoGC(E4_AUTOGC); MarkUnstable(); } inline bool NeedsGC() const {return DRV_NeedsGC();} inline void SetNeedsGC(bool needs) { if ((perms & E4_SPMODIFY) == 0) { return; } DRV_SetNeedsGC(needs); } inline int GetRootNodeID() {return DRV_GetRootNodeID();} inline bool SetRootNodeID(int id) { if ((perms & E4_SPMODIFY) == 0) { return false; } if (DRV_SetRootNodeID(id)) { MarkUnstable(); RecordTimeStamp(E4_ECSETSTGROOT); return true; } return false; } inline bool IsRootNodeID(int id) {return DRV_IsRootNodeID(id);} /* * Get the name and storage driver ID for this storage. */ inline const char *GetName() const {return name;} inline const char *GetDriver() const {return drivername;} /* * Get and set the root node. */ e4_NodeImpl *GetRootNode(); bool SetRootNode(e4_NodeImpl *nrp); /* * Enter a name into the persistent storage and also into storage-wide * hash table, or retrieve its index from the hash table if it is * already interned. If create is false then the name is not added to * the table if it is new. */ int InternName(const char *nm, bool create) const; /* * Add a callback function. */ bool AddCallback(int eventCode, void *fn, void *clientData); /* * Remove a callback function. */ bool DelCallback(int eventCode, void *fn, void *clientData); /* * Cause callbacks to be called for a user defined event on the * given e4Graph object. */ bool CauseEvent(int eventCode, const e4_RefCount &r, void *data); /* * Cause events for event codes that are predefined by e4Graph: */ void CauseEventInternal(int eventCode, e4_RefCounter *r, void *data); /* * Does this storage have a callback of the given kind? */ inline bool HasCallbacks(int eventCode) { return ((callbacksPresent & (1 << eventCode)) == (1 << eventCode)) ? true : false; } /* * Create detached entities within this storage. */ e4_NodeImpl *CreateDetachedNode(); e4_VertexImpl *CreateDetachedVertex(const char *nm, e4_NodeImpl *nip); e4_VertexImpl *CreateDetachedVertex(const char *nm, int i); e4_VertexImpl *CreateDetachedVertex(const char *nm, double d); e4_VertexImpl *CreateDetachedVertex(const char *nm, const char *s); e4_VertexImpl *CreateDetachedVertex(const char *nm, const void *bytes, int nbytes); /* * Helper method to move a vertex to a node at a position computed * from 'order' and 'rank'. */ bool MoveVertex(int nodeID, int vertexID, e4_InsertOrder order, int rank); /* * This is a storage: */ inline virtual e4_RefKind Kind() const {return E4_RKSTORAGE;} /* * Is vertex ID caching allowed? */ inline bool CachingVertexIDs() { return ((statemask & E4_NOVERTEXCACHE) == E4_NOVERTEXCACHE) ? false : true; } /* * Is this instance valid? */ virtual bool IsValid() const { if (!destroyed) { return DRV_IsValid(); } return false; } protected: /* * These operations are for use by e4_Storage, e4_StorageVisitor, * e4_NodeImpl, and e4_VertexImpl: */ friend class e4_Storage; friend class e4_StorageVisitor; friend class e4_NodeImpl; friend class e4_VertexImpl; /* * Get the ID of a given node. */ int GetNodeID(e4_Node n) const; /* * Retrieve the first e4_StorageImpl: */ static e4_StorageImpl *GetFirstStorageImpl(); /* * Retrieve the next e4_StorageImpl after the given one. */ static e4_StorageImpl *GetNextStorageImpl(e4_StorageImpl *si); /* * This method is called when the reference count goes to (or below) * zero. */ virtual void NotReferenced(); /* * This method is called to clean up any references from this * e4_StorageImpl to other instances. */ void CleanUp(); /* * This method is called to clean up the associated state after a * storage is made empty with MakeEmpty(). */ void HashCleanup(); /* * The destructor is declared and is virtual so that derived classes can * clean up their own state. */ virtual ~e4_StorageImpl(); /* * This constructor is used by derived classes. */ e4_StorageImpl(const char *name, const char *dnm, int pps); /* * Retrieve e4_NodeImpl and e4_VertexImpl instances from the cache * given their IDs. */ e4_VertexImpl *FindReferencedVertex(int vertexID) const; e4_NodeImpl *FindReferencedNode(int nodeID) const; /* * Find a node given its node ID; create the e4_NodeImpl instance if it is * not yet in-memory. */ e4_NodeImpl *FindNode(int nodeID) const; e4_NodeImpl *FindOrCreateNode(int nodeID) const; e4_NodeImpl *FindOrCreateNode(int nodeID, bool *isNew) const; /* * Store a node in the activeNodes hash table. */ void StoreNode(int nodeID, e4_NodeImpl *n) const; /* * Forget a node by removing it from the activeNodes table. */ void ForgetNode(int nodeID); /* * Retrieve an instance of e4_VertexImpl for a given vertex in a node. * Creates and caches the instance if necessary. */ e4_VertexImpl *GetVertex(int id) const; /* * Store a vertex in the activeVertices hash table. */ void StoreVertex(int vertexID, e4_VertexImpl *f) const; /* * Forget a vertex by removing it from the activeVertices table. */ void ForgetVertex(int vertexID); /* * Is this vertex or node referenced by the user of e4Graph? */ bool IsReferencedNode(int nodeID) const; bool IsReferencedVertex(int vertexID) const; /* * Methods to iterate over all entities referenced by the user program. */ int FirstReferencedNodeID(e4_HashSearch *searchP); int NextReferencedNodeID(e4_HashSearch *searchP); int FirstReferencedVertexID(e4_HashSearch *searchP); int NextReferencedVertexID(e4_HashSearch *searchP); /* * Enter the name only into the storage-wide hash table. It is already * in the persistent storage. */ void AddNameToNameHash(const char *nm, int idx) const; /* * Given a nameID, get the actual name. */ const char *NameFromNameID(int nameID) const; /* * APIs to manage the GC state: * * The GC state vector contains bits denoting the GC state of each * node and vertex in this storage. */ void RegisterGCState(int id, int mask); void UnregisterGCState(int id, int mask); bool IsGCState(int id, int mask); void RegisterUnreachableVertexID(int vertexID); void UnregisterUnreachableVertexID(int vertexID); void RegisterMaybeUnreachableVertexID(int vertexID); void UnregisterMaybeUnreachableVertexID(int vertexID); void RegisterReachableVertexID(int vertexID); void UnregisterReachableVertexID(int vertexID); void SetScannedVertexID(int vertexID); void ClearScannedVertexID(int vertexID); void RegisterUnreachableNodeID(int nodeID); void UnregisterUnreachableNodeID(int nodeID); void RegisterMaybeUnreachableNodeID(int nodeID); void UnregisterMaybeUnreachableNodeID(int nodeID); void RegisterReachableNodeID(int nodeID); void UnregisterReachableNodeID(int nodeID); void SetScannedNodeID(int nodeID); void ClearScannedNodeID(int nodeID); bool IsMaybeUnreachableNodeID(int nodeID); bool IsReachableNodeID(int nodeID); bool IsUnreachableNodeID(int nodeID); bool IsScannedNodeID(int nodeID); bool IsMaybeUnreachableVertexID(int vertexID); bool IsReachableVertexID(int vertexID); bool IsUnreachableVertexID(int vertexID); bool IsScannedVertexID(int vertexID); int FirstGCEntity(int mask); int NextGCEntity(int i, int mask); int FirstUnreachableNodeID(); int NextUnreachableNodeID(int cur); int FirstMaybeUnreachableNodeID(); int NextMaybeUnreachableNodeID(int cur); int FirstReachableNodeID(); int NextReachableNodeID(int cur); int FirstUnreachableVertexID(); int NextUnreachableVertexID(int cur); int FirstMaybeUnreachableVertexID(); int NextMaybeUnreachableVertexID(int cur); int FirstReachableVertexID(); int NextReachableVertexID(int cur); /* *========================================================================= * * DRIVER API SECTION: * * The APIs defined below this header are all pure virtual. They must * all be supplied by a class derived from e4_StorageImpl. All of these * APIs have names starting with DRV_ to denote that they form the driver * interface. * *========================================================================= */ public: /* * Cause a commit *now*. */ virtual bool DRV_Commit() = 0; /* * Is this storage valid? */ virtual bool DRV_IsValid() const = 0; /* * Set the ID of the root node: */ virtual bool DRV_SetRootNodeID(int ID) = 0; virtual int DRV_GetRootNodeID() = 0; virtual bool DRV_IsRootNodeID(int ID) = 0; /* * Given a vertex ID, get the e4_VertexImpl instance representing the * next vertex in the containing node. */ virtual e4_VertexImpl *DRV_FindNextVertex(int vertexID, e4_VisitMethod vm, int vv, int nameID, int nodeID, int parentID, e4_VertexType typeID, e4_DetachChoice dc) const = 0; /* * Given a node ID, get the e4_NodeImpl instance representing the * next node in the storage. */ virtual e4_NodeImpl *DRV_FindNextNode(int nodeID) const = 0; /* * Get a value for a statistic being collected for this storage. */ virtual bool DRV_GetStatistic(e4_Space sp, e4_SpaceStat st, int &v) = 0; /* * Return the hash code associated with this storage. */ virtual int DRV_HashCode() const = 0; /* * Do a GC. */ virtual void DRV_DoGC(int reqstate) = 0; /* * Is a GC needed? */ virtual bool DRV_NeedsGC() const = 0; /* * Note that a GC is needed. */ virtual void DRV_SetNeedsGC(bool needs) = 0; protected: /* * APIs for supporting GC (new GC): */ virtual void DRV_FreeNode(int id) = 0; virtual void DRV_FreeVertex(int id) = 0; /* * Mark a node or vertex as having had the detach notify callback * delivered. */ virtual void DRV_MarkDetachNotifiedNodeID(int id) = 0; virtual void DRV_MarkDetachNotifiedVertexID(int id) = 0; /* * Has a detach callback not yet been delivered for this node or vertex? */ virtual bool DRV_IsNewlyDetachedNodeID(int id) = 0; virtual bool DRV_IsNewlyDetachedVertexID(int id) = 0; /* * Determine whether the node or vertex identified by * the given ID is detached. */ virtual bool DRV_IsDetachedNodeID(int id) const = 0; virtual bool DRV_IsDetachedVertexID(int id) const = 0; /* * Detach a vertex or node. */ virtual bool DRV_DetachNodeByID(int id) = 0; virtual bool DRV_DetachVertexByID(int id) = 0; /* * Get the vertex ID of the first detached vertex whose value is * the given node ID. Similarly, get the vertex ID of the next * detached vertex whose value is the given node. */ virtual int DRV_GetFirstDetachedVertexIDWithNodeID(int id) const = 0; virtual int DRV_GetNextDetachedVertexIDAfter(int id) const = 0; #ifdef NOTDEF /* * Add an element to a free-list. */ virtual void DRV_UnusedNode(int id) = 0; virtual void DRV_UnusedInt(int id) = 0; virtual void DRV_UnusedDouble(int id) = 0; virtual void DRV_UnusedString(int id) = 0; virtual void DRV_UnusedName(int id) = 0; virtual void DRV_UnusedBinary(int id) = 0; #endif /* * Count how many vertices there are in a node, given the nodeID. */ virtual int DRV_VertexCountFromNodeID(int nodeID) const = 0; /* * Count how many vertices in a node identified by its nodeID have * a given name, type or value. */ virtual int DRV_VertexCountWithNameIDFromNodeID(int nodeID, int vertexID, int nameID) const = 0; virtual int DRV_VertexCountWithTypeFromNodeID(int nodeID, int vertexID, e4_VertexType tp) const = 0; virtual int DRV_VertexCountWithValueFromNodeID(int nodeID, int vertexID, const e4_Value &v) const = 0; /* * If parentID is a parent of childID then return true, else false. */ virtual bool DRV_IsParentID(int parentID, int childID) const = 0; /* * Find the rank of a child node in the vertex list of a node. */ virtual int DRV_GetRankOfChildNode(int parentID, int childID, int ith) const = 0; /* * Set a vertex whose vertex ID is given. */ virtual bool DRV_SetVertex(int vertexID, int nameID, int vertexType, int itemID) = 0; /* * Add a vertex according to the rank and io arguments to a node whose * node ID is given. */ virtual int DRV_AddVertex(int nodeID, e4_InsertOrder io, int &rank) = 0; /* * Find the rank of a vertex with a given index in a node whose node ID * is given. */ virtual int DRV_RankFromVertexID(int nodeID, int vertexID) const = 0; /* * Find the nth vertex with a given name in a list of vertices. */ virtual int DRV_VertexIDFromNthVertex(int nodeID, int nameID, int nth, int &rank) const = 0; /* * Given the rank of a vertex in this node, find the corresponding * vertex ID. */ virtual int DRV_VertexIDFromRank(int nodeID, int rank) const = 0; /* * Get the parent node of a node or the parent ID, given the child node ID. */ virtual e4_NodeImpl *DRV_GetParentNode(int childID, int nth) const = 0; virtual int DRV_GetParentNodeID(int childID, int nth) const = 0; /* * Find the next vertex after this one in the node containing this * one. */ virtual e4_VertexImpl *DRV_NextVertex(int num, int vertexID) const = 0; /* * Find the previous vertex before this one in the node containing * this vertex. */ virtual e4_VertexImpl *DRV_PrevVertex(int num, int vertexID) const = 0; /* * Find the vertex ID for the next vertex after the one identified by * the given vertexID. */ virtual int DRV_NextVertexID(int vertexID) const = 0; /* * Find the vertex ID for the previous vertex before the one identified * by the given vertexID. */ virtual int DRV_PrevVertexID(int vertexID) const = 0; /* * Get the vertex ID for the vertex containing this node in its parent. */ virtual int DRV_GetVertexIDInParent(int parentID, int nodeID, int nth) const = 0; /* * Get vertex IDs for the first or last vertex in a node, given * the node ID. */ virtual int DRV_GetFirstVertexID(int nodeID) const = 0; virtual int DRV_GetLastVertexID(int nodeID) const = 0; /* * Given a vertex ID, find the e4_NodeImpl instance representing the node * that contains that vertex. */ virtual e4_NodeImpl *DRV_ContainingNodeFromVertexID(int vertexID) const = 0; virtual int DRV_ContainingNodeIDFromVertexID(int vertexID) const = 0; /* * Check that a node ID is legal. */ virtual bool DRV_IsLegalNodeID(int index) const = 0; /* * Check that a vertex ID is legal. */ virtual bool DRV_IsLegalVertexID(int index) const = 0; /* * Get the value of a vertex whose vertex ID is given. */ virtual bool DRV_GetVertexByIndex(int index, e4_ValueImpl *&v) const = 0; virtual bool DRV_GetVertexByIndex(int index, e4_NodeImpl *&n) const = 0; virtual bool DRV_GetVertexByIndex(int index, int &v) const = 0; virtual bool DRV_GetVertexByIndex(int index, double &f) const = 0; virtual bool DRV_GetVertexByIndex(int index, const char *&s) const = 0; virtual bool DRV_GetVertexByIndex(int index, const void *&bytes, int &nbytes) const = 0; /* * Set the value of a vertex whose vertex ID is given. */ virtual bool DRV_SetVertexByIndex(int index, int v) = 0; virtual bool DRV_SetVertexByIndex(int index, double f) = 0; virtual bool DRV_SetVertexByIndex(int index, const char *s) = 0; virtual bool DRV_SetVertexByIndex(int index, const void *bytes, int nbytes) = 0; virtual bool DRV_SetVertexByIndexToNode(int index, int childID) = 0; /* * Rename a vertex whose index is given. */ virtual bool DRV_RenameVertexByVertexID(int vertexID, int nameID) = 0; /* * Return the vertex type and name of the vertex whose ID is given. */ virtual e4_VertexType DRV_VertexTypeFromVertexID(int vertexID) const = 0; virtual int DRV_NodeIDFromVertexID(int vertexID) const = 0; virtual const char *DRV_VertexNameFromVertexID(int vertexID) const = 0; virtual int DRV_NameIDFromVertexID(int vertexID) const = 0; /* * Retrieve the value of an entry. If the vertex identified by the * given index contains a value of the requested type, the value is * placed in the output parameter and true is returned. Otherwise, * false is returned and the value of the output parameter is left * unmodified. */ virtual bool DRV_GetNode(int index, e4_NodeImpl *&value) const = 0; virtual bool DRV_GetInt(int index, int &value) const = 0; virtual bool DRV_GetDouble(int index, double &value) const = 0; virtual bool DRV_GetString(int index, char *&value) const = 0; virtual bool DRV_GetBinary(int index, void *&value, int &nbytes) const = 0; virtual bool DRV_GetVertexName(int index, const char *&value) const = 0; /* * Get the raw value of a specific vertex as an index. For use only * by GC. */ virtual bool DRV_GetRawValue(int index, int &value) const = 0; /* * Get the index of the node that is the value of the given vertex. */ virtual bool DRV_GetNodeID(int index, int &value) const = 0; /* * Specialized version of GetNode that also returns an indication * whether the node is newly created. */ virtual bool DRV_GetNode(int index, e4_NodeImpl *&value, bool *isNew) const = 0; /* * Add a new entry to one of the type-specific spaces. The operation * returns the index of the new item. */ virtual int DRV_ReserveNodeID() = 0; virtual int DRV_ReserveVertexID(int nameID) = 0; virtual int DRV_AddInt(int value) = 0; virtual int DRV_AddDouble(double value) = 0; virtual int DRV_AddString(const char *value) = 0; virtual int DRV_AddBinary(const void *value, int nbytes) = 0; virtual int DRV_AddName(const char *nm) = 0; /* * Move the vertex identified by vertexID into the node identified by * nodeID as the first vertex. */ virtual bool DRV_MoveVertexToFirst(int vertexID, int nodeID) = 0; /* * Move the vertex identified by vertexID into the node identified by * nodeID as the last vertex. */ virtual bool DRV_MoveVertexToLast(int vertexID, int nodeID) = 0; /* * Move the vertex identified by vertexID to immediately after the * vertex identified by afterVertexID. */ virtual bool DRV_MoveVertexAfter(int vertexID, int afterVertexID, int rank) = 0; /* * Use driver-specific methods to copy from one storage to another. */ virtual bool DRV_CopyTo(e4_StorageImpl *osp) = 0; /* * Use driver-specific methods to destroy the physical storage. */ virtual void DRV_Destroy() = 0; /* * Retrieve the nth vertex in the parent identified by parentID whose * value is the node identified by nodeID. */ virtual e4_VertexImpl *DRV_GetVertexRefFromParent(int parentID, int nodeID, int nth) const = 0; /* * Retrieve the nth vertex in the ith parent of the node identified by * nodeID whose value is the node identified by nodeID. */ virtual e4_VertexImpl *DRV_GetVertexRefFromIthParent(int i, int nodeID, int nth) const = 0; /* * How many nodes in this storage are parents of the node with the * given ID? */ virtual int DRV_ParentCount(int nodeID) const = 0; /* * How many times does the node with the given ID appear as the * value of a vertex in this storage? */ virtual int DRV_OccurrenceCount(int nodeID) const = 0; /* * How many times does the node with the given child ID appear as * the value of a vertex in the node with the given parent ID? */ virtual int DRV_OccurrenceCount(int nodeID, int parentID) const = 0; /* * What is the rank of the node with the given parent ID for the * node with the given child ID? */ virtual int DRV_ParentRank(int nodeID, int parentID) const = 0; /* * User data manipulation facility: */ virtual bool DRV_GetNodeUserData(int nodeID, int &userData) const = 0; virtual bool DRV_GetVertexUserData(int vertexID, int &userData) const = 0; virtual bool DRV_SetNodeUserData(int nodeID, int userData) = 0; virtual bool DRV_SetVertexUserData(int vertexID, int userData) = 0; }; /* * The e4_NodeImpl class: */ class e4_DLL e4_NodeImpl : public e4_RefCounter { private: int flags; /* Transient flags. */ int cachePolicy; /* Cache policy for * this node. */ int nodeID; /* The ID for this node. */ e4_StorageImpl *storage; /* In which storage is this * node? */ e4_HashTable *cachedVertexIDs; /* The cache mapping from * rank or name+nth to a * vertex ID. */ bool cacheNonEmpty; /* Set to true when some * some information is cached * in the cache. If false then * no need to flush cache if * the node changed. */ e4_NodeImpl(); /* Ensure that noone can * use the default * constructor. */ e4_NodeImpl(const e4_NodeImpl &); /* Nor copy construction */ void operator= (const e4_NodeImpl *); /* Nor assignment */ public: /* * There is no public constructor. The only way to get an * e4_NodeImpl instance is to call an API on a storage or * another entity that returns a node. */ virtual ~e4_NodeImpl(); /* Deletes the e4_NodeImpl *BUT * NOT* the datum. This * just releases the program * memory data structure which * is only a cache for the * node in its view. Use * e4_NodeImpl::Detach() * to detach a node. */ /* * How many vertices are currently in this node? */ int VertexCount() const; /* * How many vertices in this node have the given name, type or value? */ int VertexCountWithName(const char *nm) const; int VertexCountWithType(e4_VertexType tp) const; int VertexCountWithValue(const e4_Value &v) const; /* * Set or add a vertex whose value is a node: */ e4_NodeImpl *SetNthNode(const char *nm, int nth); e4_NodeImpl *SetNode(const char *nm); e4_NodeImpl *SetNodeByRank(int rank); e4_NodeImpl *AddNode(const char *nm, e4_InsertOrder order, int &rank); /* * Operations to set data into existing vertices in this node. */ bool SetNthVertex(const char *nm, int nth, int v); bool SetNthVertex(const char *nm, int nth, double f); bool SetNthVertex(const char *nm, int nth, const char *s); bool SetNthVertex(const char *nm, int nth, const void *b, int nbytes); bool SetNthVertexToNode(const char *nm, int nth, int childID); /* * Set the value of a vertex identified by rank. The return value is * true if the vertex is new and false if it existed beforehand. */ bool SetVertexByRank(int rank, int v); bool SetVertexByRank(int rank, double f); bool SetVertexByRank(int rank, const char *s); bool SetVertexByRank(int rank, const void *bytes, int nbytes); bool SetVertexByRankToNode(int rank, int childID); /* * These operations create a new vertex with the requested name and * add it at the position specified by the order and rank arguments. * The rank argument is in-out; on the way in, in combination with * the order argument, it determines where in the node the new vertex * is created. On the way out, it gives the caller the rank of the * new vertex created. Upon success, true is returned. If an error * occurred, rank is set to E4_VERTEXNOTCREATED and false is returned. */ bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, int v); bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, double f); bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, const char *s); bool AddVertex(const char *nm, e4_InsertOrder order, int &rank, const void *b, int nbytes); bool AddVertexWithNode(const char *nm, e4_InsertOrder order, int &rank, int childID); /* * Operations to add a vertex and return an e4_VertexImpl for the * new vertex in one step. This is much more efficient than AddVertex * followed by GetVertexRef. */ e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order, int &rank, int v); e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order, int &rank, double f); e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order, int &rank, const char *s); e4_VertexImpl *AddVertexRef(const char *nm, e4_InsertOrder order, int &rank, const void *b, int nbytes); e4_VertexImpl *AddVertexRefWithNode(const char *nm, e4_InsertOrder order, int &rank, int childID); e4_VertexImpl *AddNodeRef(const char *nm, e4_InsertOrder order, int &rank, e4_NodeImpl *&n); /* * Operations to get data from vertices in this node. These operations * return true if the vertex is found and then the output parameter is * modified to refer to the vertex value. If the vertex is not found then * the operation returns false and the output parameter is not modified. * * The char * and void * returned are valid only until the next call to * any e4Tree API. If the caller needs to keep access to the value, * copy the value into memory owned by the caller. */ bool GetNthVertex(const char *nm, int nth, e4_ValueImpl *&v); bool GetNthVertex(const char *nm, int nth, e4_NodeImpl *&n); bool GetNthVertex(const char *nm, int nth, int &v); bool GetNthVertex(const char *nm, int nth, double &f); bool GetNthVertex(const char *nm, int nth, const char *&s); bool GetNthVertex(const char *nm, int nth, const void *&v, int &nbytes); bool GetVertexByRank(int rank, e4_ValueImpl *&v); bool GetVertexByRank(int rank, e4_NodeImpl *&n); bool GetVertexByRank(int rank, int &v); bool GetVertexByRank(int rank, double &f); bool GetVertexByRank(int rank, const char *&s); bool GetVertexByRank(int rank, const void *&v, int &nbytes); /* * Detach a vertex: */ bool DetachVertex(const char *nm, int nth); bool DetachVertexByRank(int rank); /* * Detach the first vertex whose value is a given child node. */ bool DetachFirstVertexWithNode(e4_NodeImpl *childImpl); /* * Get an e4_VertexImpl pointer for a vertex identified either by rank or * by name and nth. */ e4_VertexImpl *GetVertexRef(const char *nm, int nth); e4_VertexImpl *GetVertexRefByRank(int rank); /* * This operation returns the type of the datum stored in the * named vertex. If the vertex does not exist then E4_VERTEXNOTFOUND * is returned. */ e4_VertexType VertexType(const char *nm, int nth); e4_VertexType VertexTypeByRank(int rank); /* * Return the name of the vertex whose rank is given. Returns NULL * if no such vertex is present. */ const char *VertexName(int rank); /* * Rename a vertex identified by a rank. Returns true if the vertex * exists, false otherwise. */ bool RenameVertex(int rank, const char *newNm); /* * This operation retrieves the rank of the "n"th vertex with the given * name in this node. The operation returns E4_VERTEXNOTFOUND if there is * no matching vertex, or the rank of the matching vertex. */ int VertexRank(const char *nm, int nth); bool Exists(const char *nm, int nth); /* * Node->Node operations: */ e4_NodeImpl *GetParent(int nth) const; /* * Retrieve the nth vertex in the ith parent of this node whose * value is this node. */ e4_VertexImpl *GetVertexRefFromParent(int i, int nth) const; /* * Retrieve the nth vertex in the given parent p of this node whose * value is this node. */ e4_VertexImpl *GetVertexRefFromParent(e4_NodeImpl *p, int nth) const; /* * How many parents does this node have? */ int ParentCount() const; /* * In how many different vertices is this node the vertex target? */ int OccurrenceCount() const; /* * How many vertices point from this parent to this child node? */ int OccurrenceCount(int parentID) const; /* * What is the rank of the given parent for this node? */ int ParentRank(int parentID) const; /* * Node->Storage: get the storage in which this node appears. */ e4_StorageImpl *GetStorage() const; /* * Compute the rank of the ith vertex in the nth parent of this node * whose value is this node. If not found, returns -1. */ int GetRankInParent(int nth, int ith) const; int GetRankInParent(e4_NodeImpl *p, int ith) const; /* * Retrieve the name of the ith vertex in the nth parent of this node * whose value is this node. If not found, returns NULL. */ const char *GetNameInParent(int nth, int ith) const; const char *GetNameInParent(e4_NodeImpl *p, int ith) const; /* * A node is the "root" if it is the node returned by s.GetRootNode() * when called on its storage. */ bool IsRoot() const; /* * This operation returns an ID which uniquely identifies this e4_NodeImpl * in the e4_StorageImpl that contains it. */ int GetUniqueID() const; /* * Detach this node from all vertices for which it is the value. */ bool Detach(); /* * Is this node detached? */ bool IsDetached() const; /* * Is this instance valid? */ virtual bool IsValid() const; /* * Manage the user data associated with this node. */ bool GetUserData(int &userData) const; bool SetUserData(int userData); /* * Get/Set user data for contained vertex. */ bool GetVertexUserData(const char *nm, int nth, int &userData); bool SetVertexUserData(const char *nm, int nth, int userData); bool GetVertexUserDataByRank(int rank, int &userData); bool SetVertexUserDataByRank(int rank, int userData); /* * Move the vertex identified by vertexID into the node identified * by nodeID at the given rank. */ bool MoveVertex(int vertexID, e4_InsertOrder order, int rank); /* * This is a node: */ inline virtual e4_RefKind Kind() const {return E4_RKNODE;} /* * Manage transient flags: */ /* * Return true if all the flags in the given mask are set for this * vertex. */ inline bool HasFlags(int mask) const { return ((flags & mask) == mask) ? true : false; } /* * Set all the flags in the given mask. */ inline void SetFlags(int mask) { flags |= mask; } /* * Clear all the flags in the given mask. */ inline void ClearFlags(int mask) { flags &= (~(mask)); } /* * Set/get advisory cache management policy flags. */ inline int SetAdvisoryCachingPolicy(bool set, int mask) { int oldFlags = cachePolicy; if (set) { cachePolicy |= mask; } else { cachePolicy &= (~(mask)); } return oldFlags; } inline int GetAdvisoryCachingPolicy() const {return cachePolicy;} /* * Pre-cache vertices in this node. */ void PreCache(); void PreCache(int mask); protected: /* * This method is called when the reference count goes to (or below) * zero. */ virtual void NotReferenced(); /* * These methods are for use by e4_StorageImpl and e4_VertexImpl only: */ friend class e4_StorageImpl; friend class e4_VertexImpl; /* * Constructor which takes a node ID: */ e4_NodeImpl(e4_StorageImpl *s, int nodeID); /* * Cache APIs: */ void FlushCache(); void CacheVertexIDByName(int nameID, int nth, int vid); void CacheVertexIDByRank(int rank, int vid); void CacheVertexRankByID(int vid, int rank); int GetCachedVertexIDByName(int nameID, int nth) const; int GetCachedVertexIDByRank(int rank) const; int GetCachedVertexRankByID(int vid) const; /* * Get the index of the first and last vertex in this node. */ int GetFirstVertexID() const; int GetLastVertexID() const; /* * Get the node ID. */ int GetNodeID() const; /* * Set the storage instance variable. */ void SetStorage(e4_StorageImpl *newstorage); }; /* * The e4_VertexImpl class: */ class e4_DLL e4_VertexImpl : public e4_RefCounter { private: e4_VertexImpl(); /* Ensure that noone can * use the default * constructor. */ e4_VertexImpl(const e4_VertexImpl &); /* Nor copy construction. */ void operator= (const e4_VertexImpl &); /* Nor assignment. */ int flags; /* Transient flags. */ int vertexID; /* Unique ID for this * vertex. */ e4_StorageImpl *s; /* The e4_StorageImpl that the * containing vertex appears * in. */ public: /* * Destructor: */ virtual ~e4_VertexImpl(); /* Deletes the e4_VertexImpl * BUT NOT the datum. This just * releases the program * memory data structure which * is only a cache for the * view-based vertex. To remove * the underlying vertex, use * e4_VertexImpl::Detach and * invalidate all references * to it. Storage is recycled * automatically. */ /* * Get the vertex content. */ bool Get(e4_ValueImpl *&v) const; bool Get(e4_NodeImpl *&node) const; bool Get(int &v) const; bool Get(double &d) const; bool Get(const char *&str) const; bool Get(const void *&bytes, int &nbytes) const; /* * Set the target (value) of the vertex (and potentially its type). */ bool Set(int v); bool Set(double v); bool Set(const char *v); bool Set(const void *bytes, int nbytes); bool SetToNode(int childID); /* * Set the value (target) of this vertex to a new node. */ e4_NodeImpl *SetNode() const; /* * Get the rank of this vertex in its source node. */ int Rank() const; /* * Get the count of vertices up to this one with the same * name as this one in the node containing this vertex. * Return -1 if this vertex is detached. */ int CountWithName() const; /* * Get the total count of vertices in the node containing * this one with the same name as this vertex. If this * vertex is detached then return -1. */ int TotalCountWithName() const; /* * Get the count of vertices up to this one with the same * type as this one in the node countaining this vertex. * Return -1 if this vertex is detached. */ int CountWithType() const; /* * Get the total count of vertices in the node containing * this one with the same type as this vertex. If this * vertex is detached then return -1. */ int TotalCountWithType() const; /* * Return the next vertex after this in this node. */ inline e4_VertexImpl *Next(int num) const { if (s == NULL) { return NULL; } return s->DRV_NextVertex(num, vertexID); } /* * Return the previous vertex before this in this node. */ inline e4_VertexImpl *Prev(int num) const { if (s == NULL) { return NULL; } return s->DRV_PrevVertex(num, vertexID); } /* * Detach this vertex from its containing node. */ bool Detach(); /* * Is this vertex detached? */ bool IsDetached() const; /* * Is this vertex valid? */ inline virtual bool IsValid() const { if (s == NULL) { return false; } return (s->IsValid() && s->DRV_IsLegalVertexID(vertexID)); } /* * Get the vertex type for this vertex. */ inline e4_VertexType Type() const { if (s == NULL) { return E4_VTUNKNOWN; } return s->DRV_VertexTypeFromVertexID(vertexID); } /* * Get the name of this vertex. */ inline const char *Name() const { if (s == NULL) { return NULL; } return s->DRV_VertexNameFromVertexID(vertexID); } /* * Rename this vertex. */ bool Rename(const char *newname) const; /* * This operation returns an ID which uniquely identifies this * e4_VertexImpl within the e4_StorageImpl that contains it. */ inline int GetUniqueID() const { if (s == NULL) { return E4_VERTEXNOTFOUND; } return vertexID; } /* * Get the storage and node back out of this vertex. */ inline e4_StorageImpl *GetStorage() const {return s;} inline e4_NodeImpl *GetNode() const { if (s == NULL) { return NULL; } return s->DRV_ContainingNodeFromVertexID(vertexID); } /* * Move the vertex identified by moveVertexID to the given position * within the node containing this vertex. */ bool MoveVertex(int moveVertexID, int rank) const; /* * Manage the user data associated with this vertex. */ bool GetUserData(int &userData) const; bool SetUserData(int userData); /* * This is a vertex. */ inline virtual e4_RefKind Kind() const {return E4_RKVERTEX;} /* * Manage transient flags: */ /* * Return true if all the flags in the given mask are set for this * vertex. */ inline bool HasFlags(int mask) const { return ((flags & mask) == mask) ? true : false; } /* * Set all the flags in the given mask. */ inline void SetFlags(int mask) { flags |= mask; } /* * Clear all the flags in the given mask. */ inline void ClearFlags(int mask) { flags &= (~(mask)); } protected: /* * This method is called when the reference count goes to (or below) * zero. */ virtual void NotReferenced(); /* * These operations are for use by e4_StorageImpl and e4_NodeImpl only: */ friend class e4_StorageImpl; friend class e4_NodeImpl; /* * Constructor: */ e4_VertexImpl(e4_StorageImpl *st, int ii); /* * Set the storage instance variable of this vertex. */ inline void SetStorage(e4_StorageImpl *ns) {s = ns;} }; /* * This defines the type of driver construction functions: */ typedef e4_StorageImpl *(*e4_StorageConstructor)(const char *, int state, int perms); /* * This defines the type of driver storage version getter functions: */ typedef bool (*e4_StorageVersionGetter)(const char *, int &, int &, e4_ReleaseStatus &, int &); /* * This class is used to associate functions with a given driver * name. */ class e4_DriverFunctions { public: e4_StorageConstructor Constructor; e4_StorageVersionGetter StorageVersionGetter; /* * Constructor: */ e4_DriverFunctions(e4_StorageConstructor sc, e4_StorageVersionGetter sv) { Constructor = sc; StorageVersionGetter = sv; }; }; /* * The Initialize method initializes and pre-registers all the * built-in drivers. You can call this many times, it protects * against re-initialization. */ e4_DLL void e4_InitializeStorageRegistry(); /* * Given a driver name get its registered storage constructor. */ e4_DLL e4_StorageConstructor e4_GetStorageConstructor(const char *drivername); /* * Given a driver name get its version getter function. */ e4_DLL e4_StorageVersionGetter e4_GetStorageVersionGetter(const char *dn); /* * Register storage driver functions so that they are retrievable * given a specified name. */ e4_DLL bool e4_RegisterStorageFunctions(e4_StorageConstructor scp, e4_StorageVersionGetter svp, const char *drivername); /* * Deregister storage driver functions for a given storage driver. */ e4_DLL bool e4_UnregisterStorageFunctions(const char *drivername); /* * Is there a driver registered under the given name? */ e4_DLL bool e4_NamedDriverExists(const char *drivername); #endif /* __E4_GRAPHIMPL_H__ */