/* LIBDGL -- a Directed Graph Library implementation * Copyright (C) 2002 Roberto Micarelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * best view with tabstop=4 */ int DGL_ADD_NODE_FUNC( dglGraph_s * pgraph, dglInt32_t nId, void * pvNodeAttr, dglInt32_t nFlags ) { DGL_T_NODEITEM_TYPE * pNodeItem; dglInt32_t * pnode; if ( pgraph->Flags & DGL_GS_FLAT ) { pgraph->iErrno = DGL_ERR_BadOnFlatGraph; return -pgraph->iErrno; } if ( (pNodeItem = DGL_T_NODEITEM_Add( pgraph->pNodeTree , nId )) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } if ( DGL_T_NODEITEM_NodePTR(pNodeItem) == NULL ) { if ( (pnode = DGL_NODE_ALLOC( pgraph->NodeAttrSize )) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } memset( pnode, 0, DGL_NODE_SIZEOF(pgraph->NodeAttrSize) ); DGL_NODE_ID(pnode) = nId; DGL_NODE_STATUS(pnode) = DGL_NS_ALONE; DGL_T_NODEITEM_Set_NodePTR(pNodeItem,pnode); pgraph->cNode ++; pgraph->cAlone ++; } else { /* node already exists */ pgraph->iErrno = DGL_ERR_NodeAlreadyExist; return -pgraph->iErrno; } return 0; } #if !defined(_DGL_V1) /* * Delete the link from the node's out-edgeset */ int DGL_DEL_NODE_OUTEDGE_FUNC(dglGraph_s * pgraph, dglInt32_t nNode, dglInt32_t nEdge) { DGL_T_NODEITEM_TYPE * pNodeItem , findNodeItem; dglInt32_t * pnEdgeset, * pnEdge, * pnNode; dglEdgesetTraverser_s t; findNodeItem.nKey = nNode; if ( (pNodeItem = avl_find( pgraph->pNodeTree, &findNodeItem )) != NULL) { pnNode = DGL_T_NODEITEM_NodePTR(pNodeItem); if ( DGL_NODE_STATUS(pnNode) == DGL_NS_ALONE ) { return 0; } if ( (pnEdgeset = DGL_T_NODEITEM_OutEdgesetPTR(pNodeItem)) != NULL ) { if ( DGL_EDGESET_T_INITIALIZE_FUNC(pgraph,&t,pnEdgeset) >= 0 ) { for ( pnEdge = DGL_EDGESET_T_FIRST_FUNC(&t) ; pnEdge ; pnEdge = DGL_EDGESET_T_NEXT_FUNC(&t) ) { if (DGL_EDGE_ID(pnEdge) == nEdge) { register dglInt32_t * pnSet; register int i1, i2, c; c = pnEdgeset[0]; if ((pnSet = malloc(sizeof(dglInt32_t) * (c + 1))) == NULL) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } for(i1 = 0, i2 = 0 ; i2 < c ; i2++) { if (pnEdgeset[1 + i2] != nEdge) { pnSet[1 + i1++] = pnEdgeset[1 + i2]; } } pnSet[0] = i1; free(pnEdgeset); DGL_T_NODEITEM_Set_OutEdgesetPTR(pNodeItem,pnSet); break; } } } } { /* check alone status */ dglInt32_t *pIn, *pOut, *pNode; pOut = DGL_T_NODEITEM_OutEdgesetPTR(pNodeItem); pIn = DGL_T_NODEITEM_InEdgesetPTR(pNodeItem); pNode = DGL_T_NODEITEM_NodePTR(pNodeItem); if ( (pOut == NULL || DGL_EDGESET_EDGECOUNT(pOut) == 0) && (pIn == NULL || DGL_EDGESET_EDGECOUNT(pIn) == 0) ) { if (DGL_NODE_STATUS(pNode) & DGL_NS_HEAD) pgraph->cHead--; if (DGL_NODE_STATUS(pNode) & DGL_NS_TAIL) pgraph->cTail--; DGL_NODE_STATUS(pNode) = DGL_NS_ALONE; pgraph->cAlone++; } } } return 0; } int DGL_DEL_NODE_INEDGE_FUNC(dglGraph_s * pgraph, dglInt32_t nNode, dglInt32_t nEdge) { DGL_T_NODEITEM_TYPE * pNodeItem , findNodeItem; dglInt32_t * pnEdgeset, * pnEdge, * pnNode; dglEdgesetTraverser_s t; findNodeItem.nKey = nNode; if ( (pNodeItem = avl_find( pgraph->pNodeTree, &findNodeItem )) != NULL) { pnNode = DGL_T_NODEITEM_NodePTR(pNodeItem); if ( DGL_NODE_STATUS(pnNode) == DGL_NS_ALONE ) { return 0; } if ( (pnEdgeset = DGL_T_NODEITEM_InEdgesetPTR(pNodeItem)) != NULL ) { if ( DGL_EDGESET_T_INITIALIZE_FUNC(pgraph,&t,pnEdgeset) >= 0 ) { for ( pnEdge = DGL_EDGESET_T_FIRST_FUNC(&t) ; pnEdge ; pnEdge = DGL_EDGESET_T_NEXT_FUNC(&t) ) { if (DGL_EDGE_ID(pnEdge) == nEdge) { register dglInt32_t * pnSet; register int i1, i2, c; c = pnEdgeset[0]; if ((pnSet = malloc(sizeof(dglInt32_t) * (c + 1))) == NULL) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } for(i1 = 0, i2 = 0 ; i2 < c ; i2++) { if (pnEdgeset[1 + i2] != nEdge) { pnSet[1 + i1++] = pnEdgeset[1 + i2]; } } pnSet[0] = i1; free(pnEdgeset); DGL_T_NODEITEM_Set_InEdgesetPTR(pNodeItem,pnSet); break; } } } } { /* check alone status */ dglInt32_t *pIn, *pOut, *pNode; pOut = DGL_T_NODEITEM_OutEdgesetPTR(pNodeItem); pIn = DGL_T_NODEITEM_InEdgesetPTR(pNodeItem); pNode = DGL_T_NODEITEM_NodePTR(pNodeItem); if ( (pOut == NULL || DGL_EDGESET_EDGECOUNT(pOut) == 0) && (pIn == NULL || DGL_EDGESET_EDGECOUNT(pIn) == 0) ) { if (DGL_NODE_STATUS(pNode) & DGL_NS_HEAD) pgraph->cHead--; if (DGL_NODE_STATUS(pNode) & DGL_NS_TAIL) pgraph->cTail--; DGL_NODE_STATUS(pNode) = DGL_NS_ALONE; pgraph->cAlone++; } } } return 0; } #endif int DGL_DEL_NODE_FUNC( dglGraph_s * pgraph, dglInt32_t nNodeId ) { #if defined(_DGL_V1) pgraph->iErrno = DGL_ERR_NotSupported; return -pgraph->iErrno; #else DGL_T_NODEITEM_TYPE * pNodeItem, findNodeItem; dglInt32_t * pEdgeset; dglInt32_t * pnode; dglInt32_t * pEdge; dglEdgesetTraverser_s trav; dglTreeEdge_s * pEdgeItem; if ( pgraph->Flags & DGL_GS_FLAT ) { pgraph->iErrno = DGL_ERR_BadOnFlatGraph; return -pgraph->iErrno; } if ( pgraph->pNodeTree == NULL ) { pgraph->iErrno = DGL_ERR_UnexpectedNullPointer; return -pgraph->iErrno; } findNodeItem.nKey = nNodeId; if ( (pNodeItem = avl_find( pgraph->pNodeTree, &findNodeItem )) == NULL) { pgraph->iErrno = DGL_ERR_NodeNotFound; return -pgraph->iErrno; } pnode = DGL_T_NODEITEM_NodePTR(pNodeItem); if ( DGL_NODE_STATUS(pnode) & DGL_NS_ALONE ) goto node_is_alone; pEdgeset = DGL_T_NODEITEM_OutEdgesetPTR(pNodeItem); if ( DGL_EDGESET_T_INITIALIZE_FUNC(pgraph,&trav,pEdgeset) < 0 ) return -pgraph->iErrno; for ( pEdge = DGL_EDGESET_T_FIRST_FUNC(&trav) ; pEdge ; pEdge = DGL_EDGESET_T_NEXT_FUNC(&trav) ) { if ( DGL_EDGE_TAILNODE_OFFSET(pEdge) != DGL_NODE_ID(pnode) ) { if ( DGL_DEL_NODE_INEDGE_FUNC(pgraph, DGL_EDGE_TAILNODE_OFFSET(pEdge), DGL_EDGE_ID(pEdge)) < 0 ) { return -pgraph->iErrno; } } if ( (pEdgeItem = trav.pvCurrentItem) != NULL ) { /* prioritizer sync */ if (pgraph->nOptions & DGL_GO_EdgePrioritize_COST) { if ( dgl_edge_prioritizer_del(pgraph,DGL_EDGE_ID(pEdge),DGL_EDGE_COST(pEdge)) < 0) { return -pgraph->iErrno; } } /* */ pgraph->cEdge--; pgraph->nnCost -= (dglInt64_t)DGL_EDGE_COST(pEdge); avl_delete(pgraph->pEdgeTree, pEdgeItem); dglTreeEdgeCancel(pEdgeItem,NULL); } } DGL_EDGESET_T_RELEASE_FUNC(&trav); pEdgeset = DGL_T_NODEITEM_InEdgesetPTR(pNodeItem); if ( DGL_EDGESET_T_INITIALIZE_FUNC(pgraph,&trav,pEdgeset) < 0 ) return -pgraph->iErrno; for ( pEdge = DGL_EDGESET_T_FIRST_FUNC(&trav) ; pEdge ; pEdge = DGL_EDGESET_T_NEXT_FUNC(&trav) ) { if ( DGL_EDGE_HEADNODE_OFFSET(pEdge) != DGL_NODE_ID(pnode) ) { if ( DGL_DEL_NODE_OUTEDGE_FUNC(pgraph, DGL_EDGE_HEADNODE_OFFSET(pEdge), DGL_EDGE_ID(pEdge)) < 0 ) { return -pgraph->iErrno; } } if ( (pEdgeItem = trav.pvCurrentItem) != NULL ) { /* prioritizer sync */ if (pgraph->nOptions & DGL_GO_EdgePrioritize_COST) { if ( dgl_edge_prioritizer_del(pgraph,DGL_EDGE_ID(pEdge),DGL_EDGE_COST(pEdge)) < 0) { return -pgraph->iErrno; } } /* */ pgraph->cEdge--; pgraph->nnCost -= (dglInt64_t)DGL_EDGE_COST(pEdge); avl_delete(pgraph->pEdgeTree, pEdgeItem); dglTreeEdgeCancel(pEdgeItem,NULL); } } DGL_EDGESET_T_RELEASE_FUNC(&trav); if ( DGL_NODE_STATUS(pnode) & DGL_NS_HEAD ) pgraph->cHead--; if ( DGL_NODE_STATUS(pnode) & DGL_NS_TAIL ) pgraph->cTail--; node_is_alone: if ( DGL_NODE_STATUS(pnode) & DGL_NS_ALONE ) pgraph->cAlone--; pgraph->cNode--; avl_delete( pgraph->pNodeTree, pNodeItem ); DGL_T_NODEITEM_Cancel(pNodeItem, NULL); return 0; #endif } dglInt32_t * DGL_GET_NODE_FUNC( dglGraph_s * pgraph , dglInt32_t nodeid ) { register dglInt32_t top; /* top of table */ register dglInt32_t pos; /* current position to compare */ register dglInt32_t bot; /* bottom of table */ register dglInt32_t * pref; register int cwords; /* size of a node in words of 32 bit */ register dglTreeNode_s * ptreenode; dglTreeNode_s findnode; dglInt32_t id; pgraph->iErrno = 0; if ( pgraph->Flags & DGL_GS_FLAT ) { cwords = DGL_NODE_WSIZE(pgraph->NodeAttrSize); /*bot = pgraph->iNodeBuffer / DGL_NODE_SIZEOF(pgraph->NodeAttrSize);*/ bot = pgraph->cNode; top = 0; pos = 0; pref = (dglInt32_t*)pgraph->pNodeBuffer; /* perform a binary search */ while( top != bot ) { pos = top + (bot - top) / 2; id = DGL_NODE_ID(& pref[pos * cwords]); if ( id == nodeid ) { break; } else if ( nodeid < id ) { bot = pos; } else if ( nodeid > id ) { top = pos + 1; } } if ( top == bot ) { return NULL; } return & pref[ pos * cwords ]; } else { findnode.nKey = nodeid; ptreenode = avl_find( pgraph->pNodeTree , &findnode ); if ( ptreenode && ptreenode->pv ) { return ptreenode->pv; } return NULL; } } /* * if graph is FLAT retrieve the edge area from the pEdgeBuffer * if graph is TREE retrieve the node from the pNodeTree avl and return pv field */ dglInt32_t * DGL_GET_NODE_OUTEDGESET_FUNC( dglGraph_s * pgraph , dglInt32_t * pnode ) { DGL_T_NODEITEM_TYPE * ptreenode, findnode; dglInt32_t * pEdgeset; pgraph->iErrno = 0; if ( pnode == NULL ) { pgraph->iErrno = DGL_ERR_UnexpectedNullPointer; return NULL; } if ( DGL_NODE_STATUS(pnode) & DGL_NS_ALONE) { pgraph->iErrno = DGL_ERR_NodeIsAComponent; return NULL; } if ( pgraph->Flags & DGL_GS_FLAT ) { pEdgeset = DGL_EDGEBUFFER_SHIFT(pgraph, DGL_NODE_EDGESET_OFFSET(pnode)); return pEdgeset; } else { findnode.nKey = DGL_NODE_ID(pnode); ptreenode = avl_find( pgraph->pNodeTree , &findnode ); if ( ptreenode && DGL_T_NODEITEM_OutEdgesetPTR(ptreenode) ) { return DGL_T_NODEITEM_OutEdgesetPTR(ptreenode); } return NULL; } } dglInt32_t * DGL_GET_NODE_INEDGESET_FUNC( dglGraph_s * pgraph , dglInt32_t * pnode ) { #if defined(_DGL_V1) pgraph->iErrno = DGL_ERR_NotSupported; return NULL; #endif #if defined(_DGL_V2) DGL_T_NODEITEM_TYPE * ptreenode, findnode; dglInt32_t * pEdgeset; pgraph->iErrno = 0; if ( pnode == NULL ) { pgraph->iErrno = DGL_ERR_UnexpectedNullPointer; return NULL; } if ( DGL_NODE_STATUS(pnode) & DGL_NS_ALONE) { pgraph->iErrno = DGL_ERR_NodeIsAComponent; return NULL; } if ( pgraph->Flags & DGL_GS_FLAT ) { pEdgeset = DGL_EDGEBUFFER_SHIFT(pgraph, DGL_NODE_EDGESET_OFFSET(pnode)); pEdgeset += DGL_EDGESET_WSIZE(DGL_EDGESET_EDGECOUNT(pEdgeset), pgraph->EdgeAttrSize); return pEdgeset; } else { findnode.nKey = DGL_NODE_ID(pnode); ptreenode = avl_find( pgraph->pNodeTree , &findnode ); if ( ptreenode && DGL_T_NODEITEM_InEdgesetPTR(ptreenode) ) { return DGL_T_NODEITEM_InEdgesetPTR(ptreenode); } return NULL; } #endif }