Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 49 additions & 38 deletions planarity/c/graphLib/extensionSystem/graphExtensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,10 @@ static int moduleIDGenerator = 0;
An instance of this context structure is passed to the "context"
parameter of gp_AddExtension().

3) Define a function capable of duplicating your context data
structure. It receives a void pointer indicating the context
to duplicate and a void pointer that can be cast to a graph
pointer indicating the graph for which the context is being
duplicated. The void pointer returned indicates the newly
allocated context structure. The pointer to this function is
passed to the "dupContext" parameter of gp_AddExtension()

Note: It is useful to store in your context structure a pointer
to the graph that the context is extending. There are certain
function overloads you will perform that will only receive
the context, and you may need to know things about the graph,
such as the number of vertices or edges.
3) Define a function capable of copying your context data. It receives
void pointers to destination and source contexts, and then copies the
extension-specific data from source to destination. This function's
pointer is passed to the "copyData" parameter of gp_AddExtension()

4) Define a function that can free the memory used by your context
data structure. It will receive a void pointer indicating the
Expand Down Expand Up @@ -132,7 +123,8 @@ static int moduleIDGenerator = 0;
of fpReadPostprocess() and fpWritePostprocess() are needed.

7) Define internal functions for _Feature_ClearStructures(),
_Feature_CreateStructures() and _Feature_InitStructures();
_Feature_CreateStructures(), _Feature_InitStructures(), and
_Feature_CopyStructures();

a) The _Feature_ClearStructures() should simply null out pointers
to extra structures on its first invocation, but thereafter it
Expand All @@ -151,6 +143,13 @@ static int moduleIDGenerator = 0;
needed to initialize the custom VertexRec, VertexInfo and
EdgeRec data members, if any.

d) The _Feature_CopyStructures() should invoke just the functions
needed to copy the custom VertexRec, VertexInfo and EdgeRec data
members, if any, from a source extension context to a destination
extension context. For custom EdgeRec arrays, if the destination
has more capacitiy than the source, then the implementation should
also ensure the extra EdgeRecs are initialized in the destination.

8) Define a function gp_Detach_Feature() that invokes gp_RemoveExtension()
This should be done for consistency, so that users of a feature
do not attach it with gp_ExtendWith_Feature() and remove it with
Expand All @@ -170,7 +169,7 @@ static int moduleIDGenerator = 0;
value can be used to find and remove the extension from any graph
@param context - the data storage for the extension being added
The context is owned by the extension and freed with freeContext()
@param dupContext - a function capable of duplicating the context data
@param copyData - a function capable of copying the context data
@param freeContext - a function capable of freeing the context data
@param functions - pointer to a table of functions stored in the data context.
The table of functions is an input and output parameter.
Expand All @@ -190,14 +189,14 @@ static int moduleIDGenerator = 0;
int gp_AddExtension(graphP theGraph,
int *pModuleID,
void *context,
void *(*dupContext)(void *, void *),
int (*copyData)(void *, void *),
void (*freeContext)(void *),
graphFunctionTableP functions)
{
graphExtensionP newExtension = NULL;

if (theGraph == NULL || pModuleID == NULL ||
context == NULL || dupContext == NULL || freeContext == NULL ||
context == NULL || copyData == NULL || freeContext == NULL ||
functions == NULL)
{
return NOTOK;
Expand All @@ -224,7 +223,7 @@ int gp_AddExtension(graphP theGraph,
// Assign the data payload of the extension
newExtension->moduleID = *pModuleID;
newExtension->context = context;
newExtension->dupContext = dupContext;
newExtension->copyData = copyData;
newExtension->freeContext = freeContext;
newExtension->functions = functions;

Expand Down Expand Up @@ -459,39 +458,51 @@ graphExtensionP _FindNearestOverload(graphP theGraph, graphExtensionP target, in
gp_CopyExtensions()
********************************************************************/

// This number can just be made bigger if ever needed
#define MAXNUMSUPPORTEDEXTENSIONS 32

int gp_CopyExtensions(graphP dstGraph, graphP srcGraph)
{
graphExtensionP next = NULL, newNext = NULL, newLast = NULL;
graphExtensionP dstExtension = NULL, srcExtension = NULL;
graphExtensionP srcExtensionIDMap[MAXNUMSUPPORTEDEXTENSIONS+1];

if (srcGraph == NULL || dstGraph == NULL)
return NOTOK;

gp_FreeExtensions(dstGraph);
if (gp_GetN(dstGraph) != gp_GetN(srcGraph) || gp_GetN(dstGraph) == 0)
return NOTOK;

next = srcGraph->extensions;
// NULL out the pointers in the srcExtensionIDMap
memset(srcExtensionIDMap, 0, (MAXNUMSUPPORTEDEXTENSIONS+1)*sizeof(graphExtensionP));

while (next != NULL)
// Run through the srcGraph extensions linked list and put the pointer to
// each extension in the srcExtensionIDMap at the index location indicated
// by the extension module ID. This mapping is needed because the srcGraph
// may have been extended with the extensions in a different order than the
// dstGraph, but the moduleID for each extension is the same across graphs.
srcExtension = srcGraph->extensions;
while (srcExtension != NULL)
{
if ((newNext = (graphExtensionP)malloc(sizeof(graphExtensionStruct))) == NULL)
{
gp_FreeExtensions(dstGraph);
if (srcExtension->moduleID < 0 || srcExtension->moduleID > MAXNUMSUPPORTEDEXTENSIONS)
return NOTOK;
}

newNext->moduleID = next->moduleID;
newNext->context = next->dupContext(next->context, dstGraph);
newNext->dupContext = next->dupContext;
newNext->freeContext = next->freeContext;
newNext->functions = next->functions;
newNext->next = NULL;
srcExtensionIDMap[srcExtension->moduleID] = srcExtension;
srcExtension = (graphExtensionP)srcExtension->next;
}

if (newLast != NULL)
newLast->next = (struct graphExtensionStruct *)newNext;
else
dstGraph->extensions = newNext;
// For each extension in the dstGraph, if the srcGraph has the same extension,
// then we invoke the extension's copyData to copy from srcGraph to dstGraph.
// If the dstGraph has an extension that the srcGraph does not have, then
// NULL is passed for the srcGraph extension, which is expected to cause
// the extension's copyData() to reset/reinitialize the dstGraph structures.
dstExtension = dstGraph->extensions;
while (dstExtension != NULL)
{
srcExtension = srcExtensionIDMap[dstExtension->moduleID];
if (dstExtension->copyData(dstExtension->context, srcExtension ? srcExtension->context : NULL) != OK)
return NOTOK;

newLast = newNext;
next = (graphExtensionP)next->next;
dstExtension = (graphExtensionP)dstExtension->next;
}

return OK;
Expand Down
2 changes: 1 addition & 1 deletion planarity/c/graphLib/extensionSystem/graphExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extern "C"
int gp_AddExtension(graphP theGraph,
int *pModuleID,
void *context,
void *(*dupContext)(void *, void *),
int (*copyData)(void *, void *),
void (*freeContext)(void *),
graphFunctionTableP overloadTable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extern "C"
{
int moduleID;
void *context;
void *(*dupContext)(void *, void *);
int (*copyData)(void *, void *);
void (*freeContext)(void *);

graphFunctionTableP functions;
Expand Down
52 changes: 19 additions & 33 deletions planarity/c/graphLib/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ int _ClearAllVisitedFlagsOnPath(graphP theGraph, int u, int v, int w, int x);
int _SetAllVisitedFlagsOnPath(graphP theGraph, int u, int v, int w, int x);

int _ComputeEdgeRecordType(graphP theGraph, int a, int b, int edgeType);
int _SetEdgeType(graphP theGraph, int u, int v);
int _RestoreEdgeType(graphP theGraph, int u, int v);

int _HideInternalEdges(graphP theGraph, int vertex);
int _RestoreInternalEdges(graphP theGraph, int stackBottom);
Expand Down Expand Up @@ -306,7 +306,7 @@ void _InitEdges(graphP theGraph)

#ifdef USE_1BASEDARRAYS
#else
for (int e = gp_BeginEdgeStorage(theGraph); e != gp_EndEdgeStorage(theGraph); ++e)
for (int e = gp_LowerBoundEdgeStorage(theGraph); e < gp_UpperBoundEdgeStorage(theGraph); ++e)
gp_InitEdgeFlags(theGraph, e);
#endif
}
Expand Down Expand Up @@ -1002,20 +1002,6 @@ int gp_CopyGraph(graphP dstGraph, graphP srcGraph)
return NOTOK;
}

// If the dstGraph has a larger edge capacity than the srcGraph
// then we report failure because the code below only gives valid
// values to edge records up to the edge capacity of the srcGraph
// It would be possible to invoke _InitEdgeRec() on the extra
// edge records in dstGraph, but we do not support this
// currently because we would need to have and currently do
// not have a way to reinitialize the edge record extensions
// (gp_CopyExtensions() only copies the content in extension
// content up to the size of data structures in srcGraph).
if (dstGraph->edgeCapacity > srcGraph->edgeCapacity)
{
return NOTOK;
}

// Copy the vertices (non-virtual only). Augmentations to vertices created
// by extensions are copied below by gp_CopyExtensions()
for (v = gp_LowerBoundVertices(srcGraph); v < gp_UpperBoundVertices(srcGraph); ++v)
Expand Down Expand Up @@ -1043,6 +1029,15 @@ int gp_CopyGraph(graphP dstGraph, graphP srcGraph)
for (e = gp_LowerBoundEdgeStorage(srcGraph); e < gp_UpperBoundEdgeStorage(srcGraph); e++)
_gp_CopyEdgeRec(dstGraph, e, srcGraph, e);

// If the dstGraph has more edge storage than the srcGraph, then we clear the extra
// base edgeRec structures. In gp_CopyExtensions(), the various extensions' copyData()
// functions are expected to clear out any extension-specific extra edgeRec structures
if (gp_UpperBoundEdgeStorage(dstGraph) > gp_UpperBoundEdgeStorage(srcGraph))
{
for (e = gp_UpperBoundEdgeStorage(srcGraph); e < gp_UpperBoundEdgeStorage(dstGraph); e++)
_InitEdgeRec(dstGraph, e);
}

// Give the dstGraph the same size and intrinsic properties
dstGraph->N = gp_GetN(srcGraph);
dstGraph->NV = gp_GetNV(srcGraph);
Expand All @@ -1062,21 +1057,12 @@ int gp_CopyGraph(graphP dstGraph, graphP srcGraph)
if (gp_CopyExtensions(dstGraph, srcGraph) != OK)
return NOTOK;

// Copy the graph's function table, which has the pointers to
// the most recent extension overloads of each function (or
// the original function pointer if a particular function has
// not been overloaded).
//
// This must be done after copying the extension because the
// first step of copying the extensions is to free the extensions
// of the dstGraph, which performs _InitFunctionTable() on dstGraph.
// Therefore, assigning the srcGraph functions to dstGraph *before*
// copying the extensions doesn't work because the assignment would be
// wiped out. This, in turn, means that the DupContext function of an
// extension *cannot* depend on any extension function overloads;
// the extension must directly invoke extension functions only.
*(dstGraph->functions) = *(srcGraph->functions);

// We do not copy the function table of srcGraph to the dstGraph
// because copy extensions now copies all possible data from
// srcGraph to dstGraph, but it does not extend dstGraph with
// any extensions it doesn't already have, so the dstGraph
// function table is already correct for its type.

return OK;
}

Expand Down Expand Up @@ -2754,7 +2740,7 @@ int _ComputeEdgeRecordType(graphP theGraph, int a, int b, int edgeType)
}

/****************************************************************************
_SetEdgeType()
_RestoreEdgeType()

When we are restoring an edge, we must restore its type (tree edge or cycle edge).
We can deduce what the type was based on other information in the graph.
Expand All @@ -2763,7 +2749,7 @@ int _ComputeEdgeRecordType(graphP theGraph, int a, int b, int edgeType)
constant time if u is known to have a degree bound by a constant.
****************************************************************************/

int _SetEdgeType(graphP theGraph, int u, int v)
int _RestoreEdgeType(graphP theGraph, int u, int v)
{
int e, eTwin, u_orig, v_orig;

Expand Down
47 changes: 19 additions & 28 deletions planarity/c/graphLib/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,26 +144,17 @@ extern "C"
#ifdef USE_1BASEDARRAYS
/*********************************************/

// These lower and upper bounds for edge storage are used for initializing and for
// iterating through all of the edge storage, including space not yet containing edges.
#define gp_LowerBoundEdgeStorage(theGraph) (2)
#define gp_UpperBoundEdgeStorage(theGraph) (gp_LowerBoundEdgeStorage(theGraph) + ((theGraph)->edgeCapacity << 1))
// Lower and upper edge bounds methods are used to test whether a given valid
// edge storage location falls within the range of locations occupied by edges
// of the graph. Often used in combination with gp_EdgeInUse(), defined below.
#define gp_LowerBoundEdges(theGraph) (2)
#define gp_UpperBoundEdges(theGraph) (gp_LowerBoundEdges(theGraph) + ((gp_GetM(theGraph) + (theGraph)->numEdgeHoles) << 1))

// Test whether an index e indicates a valid edge storage location
// (versus NIL in non-debug, or including bounds checking in DEBUG mode
#define gp_IsEdge(theGraph, e) (e)
#define gp_IsNotEdge(theGraph, e) (!(e))

#ifdef DEBUG
#undef gp_IsEdge
#define gp_IsEdge(theGraph, e) \
((e) == NIL \
? 0 \
: ((e) < gp_LowerBoundEdgeStorage(theGraph) || (e) >= gp_UpperBoundEdgeStorage(theGraph) \
? (NOTOK, 0) \
: 1))
#endif

// Given a valid edge record storage index e, we test whether e is in use by an
// existing edge by testing whether or not it indicates a neighbor vertex (versus NIL)
// This test is needed to avoid edge index holes created by gp_DeleteEdge()).
Expand All @@ -173,12 +164,24 @@ extern "C"
/*********************************************/
#else /* When using 0-based Arrays ***********/
/*********************************************/
#define gp_LowerBoundEdgeStorage(theGraph) (0)
#define gp_UpperBoundEdgeStorage(theGraph) (gp_LowerBoundEdgeStorage(theGraph) + ((theGraph)->edgeCapacity << 1))
#define gp_LowerBoundEdges(theGraph) (0)
#define gp_UpperBoundEdges(theGraph) (gp_LowerBoundEdges(theGraph) + ((gp_GetM(theGraph) + (theGraph)->numEdgeHoles) << 1))

#define gp_IsEdge(theGraph, e) ((e) != NIL)
#define gp_IsNotEdge(theGraph, e) ((e) == NIL)

#define gp_EdgeInUse(theGraph, e) (gp_GetNeighbor(theGraph, e) != NIL)
#define gp_EdgeNotInUse(theGraph, e) (gp_GetNeighbor(theGraph, e) == NIL)
/*********************************************/
#endif /* End of macros for 0-based Arrays ***/
/*********************************************/

// These lower and upper bounds for edge storage are used for initializing and for
// iterating through all of the edge storage, including space not yet containing edges.
#define gp_LowerBoundEdgeStorage(theGraph) (gp_LowerBoundEdges(theGraph))
#define gp_UpperBoundEdgeStorage(theGraph) (gp_LowerBoundEdgeStorage(theGraph) + ((theGraph)->edgeCapacity << 1))

// A nice bounds-checking version for DEBUG mode compilation
#ifdef DEBUG
#undef gp_IsEdge
#define gp_IsEdge(theGraph, e) \
Expand All @@ -189,18 +192,6 @@ extern "C"
: 1))
#endif

#define gp_EdgeInUse(theGraph, e) (gp_GetNeighbor(theGraph, e) != NIL)
#define gp_EdgeNotInUse(theGraph, e) (!gp_GetNeighbor(theGraph, e) == NIL)
/*********************************************/
#endif /* End of macros for 0-based Arrays ***/
/*********************************************/

// Lower and upper edge bounds methods are used to test whether a given valid
// edge storage location falls within the range of locations occupied by edges
// of the graph. May be used in combination with gp_EdgeInUse().
#define gp_LowerBoundEdges(theGraph) (gp_LowerBoundEdgeStorage(theGraph))
#define gp_UpperBoundEdges(theGraph) (gp_LowerBoundEdges(theGraph) + ((gp_GetM(theGraph) + (theGraph)->numEdgeHoles) << 1))

// An edge is represented by two consecutive edge records in the edge array E.
// If an even number, xor 1 will add one; if an odd number, xor 1 will subtract 1
#define gp_GetTwin(theGraph, e) ((e) ^ 1)
Expand Down
19 changes: 5 additions & 14 deletions planarity/c/graphLib/homeomorphSearch/graphK23Search_Extensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ int _K23Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph);

/* Forward declarations of functions used by the extension system */

void *_K23Search_DupContext(void *pContext, void *theGraph);
int _K23Search_CopyData(void *, void *);
void _K23Search_FreeContext(void *);

/****************************************************************************
Expand Down Expand Up @@ -85,7 +85,7 @@ int gp_ExtendWith_K23Search(graphP theGraph)
// Store the K23 search context, including the data structure and the
// function pointers, as an extension of the graph
if (gp_AddExtension(theGraph, &K23SEARCH_ID, (void *)context,
_K23Search_DupContext, _K23Search_FreeContext,
_K23Search_CopyData, _K23Search_FreeContext,
&context->functions) != OK)
{
_K23Search_FreeContext(context);
Expand All @@ -107,20 +107,11 @@ int gp_Detach_K23Search(graphP theGraph)
}

/********************************************************************
_K23Search_DupContext()
_K23Search_CopyData()
********************************************************************/

void *_K23Search_DupContext(void *pContext, void *theGraph)
int _K23Search_CopyData(void *dstContext, void *srcContext)
{
K23SearchContext *context = (K23SearchContext *)pContext;
K23SearchContext *newContext = (K23SearchContext *)malloc(sizeof(K23SearchContext));

if (newContext != NULL)
{
*newContext = *context;
}

return newContext;
return OK;
}

/********************************************************************
Expand Down
Loading