/* * i4vertex.cpp -- * * This file provides the implementation of the e4_VertexImpl * class defined in e4graphimpl.h. * * Authors: Jacob Levy and Jean-Claude Wippler. * jyl@best.com jcw@equi4.com * * 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. */ #include "e4graphimpl.h" /* * Constructor: */ e4_VertexImpl::e4_VertexImpl(e4_StorageImpl *st, int i) : e4_RefCounter(), flags(0), vertexID(i), s(st) { } /* * Destructor: */ e4_VertexImpl::~e4_VertexImpl() { e4_StorageImpl *lsp = s; if (s != NULL) { /* * Don't bother about cleanups if the storage itself is invalid. */ if (!s->IsValid()) { return; } /* * Remove this vertex from the cache. */ s->ForgetVertex(vertexID); /* * Don't bother about GC if we cannot modify the underlying * storage. */ if ((lsp->GetPermissions() & E4_SPMODIFY) == 0) { return; } /* * Can't use the "s" instance variable because * ForgetVertex resets it to NULL. * * If this vertex is detached, it just became unreachable. If GC * is not deferred, clean up right away. */ if (lsp->DRV_IsDetachedVertexID(vertexID)) { lsp->RegisterUnreachableVertexID(vertexID); if ((lsp->GetState() & E4_AUTOGC) == E4_AUTOGC) { lsp->DRV_DoGC(E4_AUTOGC); } else { lsp->SetNeedsGC(true); } } } } /* * This method is called when the reference count goes to (or below) zero. */ void e4_VertexImpl::NotReferenced() { delete this; } /* * Set the value of this vertex to a new node. */ e4_NodeImpl * e4_VertexImpl::SetNode() const { int nodeID; e4_NodeImpl *nip; if (s == NULL) { return NULL; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return NULL; } nodeID = s->DRV_ReserveNodeID(); nip = s->FindOrCreateNode(nodeID); if (nip == NULL) { return NULL; } s->MarkUnstable(); nip->IncrRefCount(); s->DRV_SetVertex(vertexID, s->DRV_NameIDFromVertexID(vertexID), E4_VTNODE, nodeID); s->RecordTimeStamp(E4_ECADDNODE | E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECADDNODE)) { s->CauseEventInternal(E4_ECADDNODE, nip, NULL); } if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVMODVALUE); } return nip; } /* * Detach this vertex from its containing node. */ bool e4_VertexImpl::Detach() { int nodeID, childID, mask; e4_NodeImpl *nip; bool detachedNode = false; bool hasNodeValue = false; if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } nodeID = s->DRV_ContainingNodeIDFromVertexID(vertexID); /* * If already detached, just punt. */ if (nodeID == E4_NODENOTFOUND) { return true; } /* * Since we're not detached, if the value is a node, that node may now * become detached. */ if (s->DRV_VertexTypeFromVertexID(vertexID) == E4_VTNODE) { (void) s->DRV_GetRawValue(vertexID, childID); hasNodeValue = true; } /* * Detach the vertex. */ if (!s->DRV_DetachVertexByID(vertexID)) { return false; } s->MarkUnstable(); /* * If the previously containing node is referenced by the user, flush * its cache. */ nip = s->FindReferencedNode(nodeID); if (nip != NULL) { nip->FlushCache(); } /* * Do callback notifications. */ mask = E4_ECMODNODE | E4_ECDETVERTEX; if ((hasNodeValue) && (s->DRV_IsDetachedNodeID(childID))) { mask |= E4_ECDETNODE; detachedNode = true; } s->RecordTimeStamp(mask); if (s->HasCallbacks(E4_ECMODNODE)) { if (nip != NULL) { s->CauseEventInternal(E4_ECMODNODE, nip, (void *) E4_ERMNDETVERTEX); } } if (s->HasCallbacks(E4_ECDETVERTEX)) { s->CauseEventInternal(E4_ECDETVERTEX, this, NULL); SetFlags(E4_CBDETACHDELIVERED); } if ((detachedNode) && (s->HasCallbacks(E4_ECDETNODE))) { nip = s->FindReferencedNode(childID); if (nip != NULL) { s->CauseEventInternal(E4_ECDETNODE, nip, NULL); } } return true; } /* * Is this vertex detached? */ bool e4_VertexImpl::IsDetached() const { if (s == NULL) { return true; } return s->DRV_IsDetachedVertexID(vertexID); } /* * Set a vertex to contain an existing node. */ bool e4_VertexImpl::SetToNode(int childID) { int nodeID = -1; bool wasdetached = false; if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { fprintf(stderr, "1"); return false; } /* * Only assign if the node is not already the value of this * vertex!!! */ if (s->DRV_VertexTypeFromVertexID(vertexID) == E4_VTNODE) { if (!(s->DRV_GetNodeID(vertexID, nodeID)) || (nodeID == E4_NODENOTFOUND) || (nodeID == childID)) { return false; } } wasdetached = s->DRV_IsDetachedNodeID(nodeID); if (!s->DRV_SetVertexByIndexToNode(vertexID, childID)) { return false; } s->MarkUnstable(); /* * Fire the vertex modify event (even in the case where the * node is already the value of this vertex). */ s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, this, (void *) E4_ERMVMODVALUE); } return true; } /* * Get/Set user data associated with this vertex. */ bool e4_VertexImpl::GetUserData(int &userData) const { if (s == NULL) { return false; } return s->DRV_GetVertexUserData(vertexID, userData); } bool e4_VertexImpl::SetUserData(int userData) { if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } if (s->DRV_SetVertexUserData(vertexID, userData)) { s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, this, (void *) E4_ERMVMODUSERDATA); } return true; } return false; } /* * Get and set the value: */ bool e4_VertexImpl::Get(e4_ValueImpl *&v) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, v); } bool e4_VertexImpl::Get(e4_NodeImpl *&node) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, node); } bool e4_VertexImpl::Get(int &v) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, v); } bool e4_VertexImpl::Get(double &fv) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, fv); } bool e4_VertexImpl::Get(const char *&str) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, str); } bool e4_VertexImpl::Get(const void *&bytes, int &nbytes) const { if (s == NULL) { return false; } return s->DRV_GetVertexByIndex(vertexID, bytes, nbytes); } bool e4_VertexImpl::Set(int v) { if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } if (!s->DRV_SetVertexByIndex(vertexID, v)) { return false; } s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVMODVALUE); } return true; } bool e4_VertexImpl::Set(double fv) { if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } if (!s->DRV_SetVertexByIndex(vertexID, fv)) { return false; } s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVMODVALUE); } return true; } bool e4_VertexImpl::Set(const char *str) { if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } if (!s->DRV_SetVertexByIndex(vertexID, str)) { return false; } s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVMODVALUE); } return true; } bool e4_VertexImpl::Set(const void *bytes, int nbytes) { if (s == NULL) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } if (!s->DRV_SetVertexByIndex(vertexID, bytes, nbytes)) { return false; } s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVMODVALUE); } return true; } /* * Get the rank of this vertex in its containing node. */ int e4_VertexImpl::Rank() const { int nodeID; if (s == NULL) { return E4_VERTEXNOTFOUND; } nodeID = s->DRV_NodeIDFromVertexID(vertexID); if (nodeID == E4_NODENOTFOUND) { return E4_VERTEXNOTFOUND; } return s->DRV_RankFromVertexID(nodeID, vertexID); } /* * Get the count of vertices "up to this one" with the same name * as this one, in the node containing this vertex. Returns -1 * if this vertex is detached. */ int e4_VertexImpl::CountWithName() const { int nodeID; if (s == NULL) { return -1; } nodeID = s->DRV_NodeIDFromVertexID(vertexID); if (nodeID == E4_NODENOTFOUND) { return -1; } return s->DRV_VertexCountWithNameIDFromNodeID( nodeID, vertexID, s->DRV_NameIDFromVertexID(vertexID)); } /* * Get the total number of vertices in the node containing this one * that have the same name as this vertex. Returns -1 if this vertex * is detached. */ int e4_VertexImpl::TotalCountWithName() const { int nodeID; if (s == NULL) { return -1; } nodeID = s->DRV_NodeIDFromVertexID(vertexID); if (nodeID == E4_NODENOTFOUND) { return -1; } return s->DRV_VertexCountWithNameIDFromNodeID( nodeID, E4_VERTEXNOTFOUND, s->DRV_NameIDFromVertexID(vertexID)); } /* * Retrieve the number of vertices "up to this one" in the node containing * this vertex, with the same type as this one. Returns -1 if this vertex * is detached. */ int e4_VertexImpl::CountWithType() const { int nodeID; if (s == NULL) { return -1; } nodeID = s->DRV_NodeIDFromVertexID(vertexID); if (nodeID == E4_NODENOTFOUND) { return -1; } return s->DRV_VertexCountWithTypeFromNodeID( nodeID, vertexID, s->DRV_VertexTypeFromVertexID(vertexID)); } /* * Get the total number of vertices in the node containing this one * that have the same type as this vertex. Returns -1 if this vertex * is detached. */ int e4_VertexImpl::TotalCountWithType() const { int nodeID; if (s == NULL) { return -1; } nodeID = s->DRV_NodeIDFromVertexID(vertexID); if (nodeID == E4_NODENOTFOUND) { return -1; } return s->DRV_VertexCountWithTypeFromNodeID( nodeID, E4_VERTEXNOTFOUND, s->DRV_VertexTypeFromVertexID(vertexID)); } /* * Rename this vertex. */ bool e4_VertexImpl::Rename(const char *newname) const { int nid; int nameID; e4_NodeImpl *nip; if ((s == NULL) || (newname == NULL)) { return false; } if ((s->GetPermissions() & E4_SPMODIFY) == 0) { return false; } nameID = s->InternName(newname, true); if (nameID == E4_NEXTNONE) { return false; } if (!s->DRV_RenameVertexByVertexID(vertexID, nameID)) { return false; } s->MarkUnstable(); s->RecordTimeStamp(E4_ECMODVERTEX | E4_ECMODNODE); if (s->HasCallbacks(E4_ECMODVERTEX)) { s->CauseEventInternal(E4_ECMODVERTEX, (e4_RefCounter *) this, (void *) E4_ERMVRENAME); } if (s->HasCallbacks(E4_ECMODNODE)) { nid = s->DRV_ContainingNodeIDFromVertexID(vertexID); nip = s->FindReferencedNode(nid); if (nip != NULL) { nip->FlushCache(); s->CauseEventInternal(E4_ECMODNODE, nip, (void *) E4_ERMNRENVERTEX); } } return true; } /* * Move the vertex identified by moveVertexID to the given position * (by rank) in the node containing this vertex. */ bool e4_VertexImpl::MoveVertex(int moveVertexID, int rank) const { if ((s == NULL) || (s->DRV_IsDetachedVertexID(vertexID)) || ((s->GetPermissions() & E4_SPMODIFY) == 0)) { return false; } return s->MoveVertex(s->DRV_ContainingNodeIDFromVertexID(vertexID), moveVertexID, E4_IOAT, rank); }