static void test_stSet_getUnion(CuTest* testCase) { testSetup(); // Check union of empty sets is empty stSet *set2 = stSet_construct(); stSet *set3 = stSet_construct(); stSet *set4 = stSet_getUnion(set2, set3); CuAssertTrue(testCase, stSet_size(set4) == 0); stSet_destruct(set2); stSet_destruct(set3); stSet_destruct(set4); // Check union of non empty set and empty set is non-empty set2 = stSet_construct(); set3 = stSet_getUnion(set0, set2); CuAssertTrue(testCase, stSet_size(set3) == 6); stSet_destruct(set2); stSet_destruct(set3); // Check union of two non-empty overlapping sets is correct set2 = stSet_construct(); set3 = stSet_construct(); stIntTuple **uniqs = (stIntTuple **) st_malloc(sizeof(*uniqs) * 4); uniqs[0] = stIntTuple_construct2(9, 0); uniqs[1] = stIntTuple_construct2(9, 1); uniqs[2] = stIntTuple_construct2(9, 2); uniqs[3] = stIntTuple_construct2(9, 3); stIntTuple **common = (stIntTuple **) st_malloc(sizeof(*uniqs) * 5); common[0] = stIntTuple_construct2(5, 0); common[1] = stIntTuple_construct2(5, 1); common[2] = stIntTuple_construct2(5, 2); common[3] = stIntTuple_construct2(5, 3); common[4] = stIntTuple_construct2(5, 4); for (int i = 0; i < 5; ++i) { stSet_insert(set2, common[i]); stSet_insert(set3, common[i]); } stSet_insert(set2, uniqs[0]); stSet_insert(set2, uniqs[1]); stSet_insert(set3, uniqs[2]); stSet_insert(set3, uniqs[3]); set4 = stSet_getUnion(set2, set3); CuAssertTrue(testCase, stSet_size(set4) == 9); for (int i = 0; i < 4; ++i) { CuAssertTrue(testCase, stSet_search(set4, uniqs[i]) != NULL); } for (int i = 0; i < 5; ++i) { CuAssertTrue(testCase, stSet_search(set4, common[i]) != NULL); } stSet_destruct(set2); stSet_destruct(set3); stSet_destruct(set4); // Check we get an exception with sets with different functions. stTry { stSet_getUnion(set0, set1); } stCatch(except) { CuAssertTrue(testCase, stExcept_getId(except) == SET_EXCEPTION_ID); } stTryEnd testTeardown(); }
// Compute the connected components, if they haven't been computed // already since the last modification. static void computeConnectedComponents(stNaiveConnectivity *connectivity) { if (connectivity->connectedComponentCache != NULL) { // Already computed the connected components. return; } stHashIterator *nodeIt = stHash_getIterator(connectivity->nodesToAdjList); void *node; stNaiveConnectedComponent *componentsHead = NULL; while ((node = stHash_getNext(nodeIt)) != NULL) { stSet *myNodeSet = stSet_construct(); stSet_insert(myNodeSet, node); struct adjacency *adjList = stHash_search(connectivity->nodesToAdjList, node); if (adjList != NULL) { while (adjList != NULL) { stSet_insert(myNodeSet, adjList->toNode); adjList = adjList->next; } } // Now go through the existing connected components and see if // this overlaps any of them. If it's not a full overlap, then // this set becomes the union, and we continue looking for // additional overlaps, then this becomes a new connected // component. If we find that this is a subset of an existing // component, we can quit early, since we can't possibly add // to it or any others. stNaiveConnectedComponent *curComponent = componentsHead; while (curComponent != NULL) { stNaiveConnectedComponent *next = curComponent->next; // Find out whether our node set is a subset of this // connected component, or if it shares any overlap. bool isSubset = true; bool overlap = false; stSetIterator *myNodeIt = stSet_getIterator(myNodeSet); void *node; while ((node = stSet_getNext(myNodeIt)) != NULL) { if (stSet_search(curComponent->nodes, node)) { overlap = true; } else { isSubset = false; } } stSet_destructIterator(myNodeIt); if (isSubset) { assert(overlap == true); // Quit early. stSet_destruct(myNodeSet); myNodeSet = NULL; break; } else if (overlap) { stSet *newNodeSet = stSet_getUnion(myNodeSet, curComponent->nodes); stSet_destruct(myNodeSet); removeComponent(&componentsHead, curComponent); myNodeSet = newNodeSet; } curComponent = next; } if (myNodeSet != NULL) { // We have a new (or possibly merged) connected component to // add to the list. stNaiveConnectedComponent *newComponent = malloc(sizeof(stNaiveConnectedComponent)); newComponent->nodes = myNodeSet; newComponent->next = componentsHead; componentsHead = newComponent; } } stHash_destructIterator(nodeIt); connectivity->connectedComponentCache = componentsHead; }