diff --git a/examples/treeTest.cpp b/examples/treeTest.cpp index ee32484..54c2eff 100644 --- a/examples/treeTest.cpp +++ b/examples/treeTest.cpp @@ -1,79 +1,632 @@ #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +class StringItem : public ProtoSortedTree::Item +{ +public: + explicit StringItem(const std::string& s) + : key(s) + { + } + + const std::string& GetString() const + { + return key; + } + +private: + const char* GetKey() const override + { + return key.c_str(); + } + + unsigned int GetKeysize() const override + { + return static_cast(8 * key.size()); + } + + std::string key; +}; + +class StringTree : public ProtoSortedTreeTemplate +{ +public: + explicit StringTree(bool uniqueItemsOnly = false) + : ProtoSortedTreeTemplate() + { + (void)uniqueItemsOnly; // template wrapper does not expose ctor arg + } +}; + +static std::string MakeRandomString(std::mt19937_64& rng, + unsigned int minLen, + unsigned int maxLen) +{ + static const char alphabet[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + std::uniform_int_distribution lenDist(minLen, maxLen); + std::uniform_int_distribution charDist(0, sizeof(alphabet) - 2); + + unsigned int len = lenDist(rng); + std::string s; + s.resize(len); + for (unsigned int i = 0; i < len; ++i) + s[i] = alphabet[charDist(rng)]; + return s; +} +struct BenchmarkResult +{ + std::size_t itemCount = 0; + unsigned int minLen = 0; + unsigned int maxLen = 0; + std::uint64_t seed = 0; + bool shuffleRemoval = false; + double insertSeconds = 0.0; + double removeSeconds = 0.0; +}; + +static BenchmarkResult BenchmarkProtoSortedTreeStrings(std::size_t itemCount, + unsigned int minLen, + unsigned int maxLen, + std::uint64_t seed, + bool shuffleRemoval) +{ + BenchmarkResult result; + result.itemCount = itemCount; + result.minLen = minLen; + result.maxLen = maxLen; + result.seed = seed; + result.shuffleRemoval = shuffleRemoval; + + std::mt19937_64 rng(seed); + StringTree tree; + std::vector items; + items.reserve(itemCount); + + for (std::size_t i = 0; i < itemCount; ++i) + { + items.push_back(new StringItem(MakeRandomString(rng, minLen, maxLen))); + } + + auto t0 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + if (!tree.Insert(*items[i])) + { + std::fprintf(stderr, "Insert failed at item %zu\n", i); + std::exit(1); + } + } + auto t1 = std::chrono::steady_clock::now(); + + if (shuffleRemoval) + std::shuffle(items.begin(), items.end(), rng); + + auto t2 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + tree.Remove(*items[i]); + delete items[i]; + } + auto t3 = std::chrono::steady_clock::now(); + + result.insertSeconds = + std::chrono::duration(t1 - t0).count(); + result.removeSeconds = + std::chrono::duration(t3 - t2).count(); + + return result; +} + +#include + +class PlainStringItem : public ProtoTree::Item +{ +public: + explicit PlainStringItem(const std::string& s) + : key(s) + { + } + + const std::string& GetString() const + { + return key; + } + +private: + const char* GetKey() const override + { + return key.c_str(); + } + + unsigned int GetKeysize() const override + { + return static_cast(8 * key.size()); + } + + std::string key; +}; + +class PlainStringTree : public ProtoTreeTemplate +{ +}; + +static BenchmarkResult BenchmarkProtoTreeStrings(std::size_t itemCount, + unsigned int minLen, + unsigned int maxLen, + std::uint64_t seed, + bool shuffleRemoval) +{ + BenchmarkResult result; + result.itemCount = itemCount; + result.minLen = minLen; + result.maxLen = maxLen; + result.seed = seed; + result.shuffleRemoval = shuffleRemoval; + + std::mt19937_64 rng(seed); + PlainStringTree tree; + std::vector items; + items.reserve(itemCount); + + // Pre-generate unique strings outside the timed section so duplicate + // retries do not distort the insert benchmark. + std::unordered_set uniqueKeys; + uniqueKeys.reserve(itemCount * 2); + + while (items.size() < itemCount) + { + std::string s = MakeRandomString(rng, minLen, maxLen); + if (uniqueKeys.insert(s).second) + items.push_back(new PlainStringItem(s)); + } + + auto t0 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + if (!tree.Insert(*items[i])) + { + std::fprintf(stderr, "ProtoTree insert failed at item %zu\n", i); + std::exit(1); + } + } + auto t1 = std::chrono::steady_clock::now(); + + if (shuffleRemoval) + std::shuffle(items.begin(), items.end(), rng); + + auto t2 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + tree.Remove(*items[i]); + delete items[i]; + } + auto t3 = std::chrono::steady_clock::now(); + + result.insertSeconds = + std::chrono::duration(t1 - t0).count(); + result.removeSeconds = + std::chrono::duration(t3 - t2).count(); + + return result; +} + + +// This used to test ProtoSortedTree support for basic lexical ordering (e.g., strings) class IndexedItem : public ProtoSortedTree::Item { public: IndexedItem(const char* const ptr) : string(ptr) {} - + const char* GetKey() const {return string;} unsigned int GetKeysize() const {return strlen(string) * 8;} - + //ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} - + const char* const string; }; - + class Index : public ProtoSortedTreeTemplate { - const char* GetKey(const Item& item) const {return static_cast(item).GetKey();} unsigned int GetKeysize(const Item& item) const {return static_cast(item).GetKeysize();} - - //ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} }; +// This tests/demos the use of a tree where the ProtoSortedTree items are indexed +// by a "double" floating point value +class FloatingItem : public ProtoSortedTree::Item +{ + public: + FloatingItem(double value) : item_key((0.0 == value) ? 0.0 : value) {} + double GetValue() const {return item_key;} + + const char* GetKey() const + {return (char*)&item_key;} + unsigned int GetKeysize() const + {return (sizeof(double) << 3);} + private: + // These configure the key interpretation to properly sort "double" type key values + virtual bool UseSignBit() const {return true;} + virtual bool UseComplement2() const {return false;} + virtual ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} + + double item_key; +}; // end class FloatingItem + +class FloatingTree : public ProtoSortedTreeTemplate {}; + + +// This tests/demos the use of a tree where the ProtoSortedTree items are indexed +// by a "int" floating point value +class IntegerItem : public ProtoSortedTree::Item +{ + public: + IntegerItem(int value) : item_key(value) {} + int GetValue() const {return item_key;} + + private: + const char* GetKey() const + {return (char*)&item_key;} + unsigned int GetKeysize() const + {return (sizeof(int) << 3);} + // These configure the key interpretation to properly sort "int" type key values + virtual bool UseSignBit() const {return true;} + virtual bool UseComplement2() const {return true;} + virtual ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} + + int item_key; +}; // end class IntegerItem + +class IntegerTree : public ProtoSortedTreeTemplate {}; -const char* const strings[] = + +class AddressItem : public ProtoTree::Item +{ + public: + AddressItem(const char* addrString) + { + addr.ConvertFromString(addrString); + memset(addr_key, 0, 16); + memcpy(addr_key, addr.GetRawHostAddress(), addr.GetLength()); + addr_keysize = 8*addr.GetLength(); + } + void SetKeysize(unsigned int size) {addr_keysize = size;} + const ProtoAddress& GetAddress() const {return addr;} + bool IsValid() const {return addr.IsValid();} + + private: + const char* GetKey() const + {return addr_key;} + unsigned int GetKeysize() const + {return addr_keysize;} + ProtoAddress addr; + char addr_key[16]; + unsigned int addr_keysize; +}; // end class AddressItem + +class AddressTree : public ProtoTreeTemplate { - "adamson, brian", - "adamson, nancy", - "adamson, connor", - "batson, amy", - "batson, randy", - "adams, steve", - NULL + public: + AddressItem* FindPrefixSubtree(const char* prefix, + unsigned int prefixSize) const + { + return static_cast(ProtoTree::FindPrefixSubtree(prefix, prefixSize)); + } }; +double MakeRandomFloat(std::mt19937_64& rng, + double minVal, + double maxVal) +{ + std::uniform_real_distribution randDouble(minVal, maxVal); + return randDouble(rng); +} + +static BenchmarkResult BenchmarkProtoSortedTreeFloats(std::size_t itemCount, + unsigned int minLen, + unsigned int maxLen, + std::uint64_t seed, + bool shuffleRemoval) +{ + BenchmarkResult result; + result.itemCount = itemCount; + result.minLen = minLen; + result.maxLen = maxLen; + result.seed = seed; + result.shuffleRemoval = shuffleRemoval; + + std::mt19937_64 rng(seed); + FloatingTree tree; + std::vector items; + items.reserve(itemCount); + + for (std::size_t i = 0; i < itemCount; ++i) + { + items.push_back(new FloatingItem(MakeRandomFloat(rng, -1000.0, 1000.0))); + } + + auto t0 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + if (!tree.Insert(*items[i])) + { + std::fprintf(stderr, "Insert failed at item %zu\n", i); + std::exit(1); + } + } + auto t1 = std::chrono::steady_clock::now(); + + if (shuffleRemoval) + std::shuffle(items.begin(), items.end(), rng); + + auto t2 = std::chrono::steady_clock::now(); + for (std::size_t i = 0; i < items.size(); ++i) + { + tree.Remove(*items[i]); + delete items[i]; + } + auto t3 = std::chrono::steady_clock::now(); + + result.insertSeconds = + std::chrono::duration(t1 - t0).count(); + result.removeSeconds = + std::chrono::duration(t3 - t2).count(); + + return result; +} + int main(int argc, char* argv[]) { - + + std::size_t itemCount = 1000000; + unsigned int minLen = 8; + unsigned int maxLen = 24; + std::uint64_t seed = 0x12345678ULL; + bool shuffleRemoval = false; + + if (argc > 1) itemCount = static_cast(std::strtoull(argv[1], nullptr, 10)); + if (argc > 2) minLen = static_cast(std::strtoul(argv[2], nullptr, 10)); + if (argc > 3) maxLen = static_cast(std::strtoul(argv[3], nullptr, 10)); + if (argc > 4) seed = static_cast(std::strtoull(argv[4], nullptr, 10)); + if (argc > 5) shuffleRemoval = (0 != std::atoi(argv[5])); + + if ((0 == minLen) || (minLen > maxLen)) + { + std::fprintf(stderr, "Invalid min/max string length\n"); + return 1; + } + + // SOME BASIC FUNCTION TESTS/DEMOS + + // Test/demo prefix tree operation + const char* const addrs[] = + { + "192.168.1.11", + "192.168.1.10", + "192.168.1.0", + "192.168.2.2", + "192.168.3.3", + "192.168.1.100", + NULL + }; + int count = 0; + AddressTree addrTree; + const char* const* aptr = addrs; + while (NULL != *aptr) + { + count++; + printf("adding address %s\n", *aptr); + AddressItem* addrItem = new AddressItem(*aptr++); + if (3 == count) + { + addrItem->SetKeysize(24); + } + else if (5 == count) + { + addrItem->SetKeysize(16); + } + assert(addrItem->IsValid()); + addrTree.Insert(*addrItem); + } + + ProtoAddress addr("192.168.2.99"); + //AddressItem* match = addrTree.FindClosestMatch(addr.GetRawHostAddress(), 8*addr.GetLength()); + AddressItem* match = addrTree.FindPrefix(addr.GetRawHostAddress(), 8*addr.GetLength()); + //AddressItem* match = addrTree.FindPrefixSubtree(addr.GetRawHostAddress(), 24); + if (NULL != match) + { + printf("Best match is %s\n", match->GetAddress().GetHostString()); + } + else + { + printf("No match to %s\n", addr.GetHostString()); + } + + + // Test/demo lexical sorted items (e.g., strings) + const char* const strings[] = + { + "smithson, bob", + "smithson, jane", + "smithson, john", + "jones, brandy", + "jones, tony", + "smith, steve", + NULL + }; Index index; - const char* const* ptr = strings; - int i = 0; IndexedItem* itemx; - + while (NULL != *ptr) { IndexedItem* item = new IndexedItem(*ptr++); index.Insert(*item); if (++i == 1) itemx = item; } - - + Index::Iterator iterator(index, true);//, itemx);//->GetKey(), item15->GetKeysize()); - - //index.Remove(*itemx); - - iterator.SetCursor(itemx); - - //iterator.Reset(true, itemx->string, 8); - + index.Remove(*itemx); + //iterator.SetCursor(itemx); + iterator.Reset(true, itemx->string, 8*strlen(itemx->string)); //iterator.Reset();//, item15->GetKey(), (sizeof(unsigned int) << 3) - 0); IndexedItem* item; - while (NULL != (item = iterator.GetNextItem())) + //while (NULL != (item = iterator.GetNextItem())) + while (NULL != (item = iterator.GetPrevItem())) { printf("got item %s\n", item->string); //index.Remove(*item); } - -} + + + // Test/demo floating point sorting + FloatingTree floatTree; + // Fill with random numbers + double RANGE_MIN = -100.0; + double RANGE_MAX = 100.0; + srand((unsigned int)time(NULL)); // seed RNG + FloatingItem* fitemx = NULL; + for (int i = 0; i < 10; i++) + { + double value; + if (0 == i) + value = 0.0; + else if (5 == i) + value = -0.0; + else + value = ((double)rand() / RAND_MAX) * (RANGE_MAX - RANGE_MIN) - (RANGE_MAX - RANGE_MIN)/ 2.0; + FloatingItem* fitem = new FloatingItem(value); + floatTree.Insert(*fitem); + if (8 == i) fitemx = fitem; + } + FloatingTree::Iterator fiterator(floatTree); + + floatTree.Remove(*fitemx); + //iterator.SetCursor(itemx); + fiterator.Reset(true, fitemx->GetKey(), fitemx->GetKeysize()); + + FloatingItem* fitem; + while (NULL != (fitem = fiterator.GetNextItem())) + //while (NULL != (fitem = fiterator.GetPrevItem())) + { + printf("got FloatingItem %f\n", fitem->GetValue()); + //index.Remove(*item); + } + + + // Test/demo Integer point sorting + IntegerTree integerTree; + // Fill with random numbers + int NUM_MIN = -100; + int NUM_MAX = 100; + for (int i = 0; i < 10; i++) + { + int value; + if (0 == i) + value = 0; + //else if (5 == i) + // value = INT_MAX; + else + value = (int)rand() % (NUM_MAX - NUM_MIN + 1) - (NUM_MAX - NUM_MIN)/ 2; + IntegerItem* intem = new IntegerItem(value); + integerTree.Insert(*intem); + //IntegerItem* intem2 = new IntegerItem(value); + //integerTree.Insert(*intem2); + } + IntegerTree::Iterator interator(integerTree); + IntegerItem* intem; + while (NULL != (intem = interator.GetNextItem())) + //while (NULL != (item = iterator.GetPrevItem())) + { + printf("got IntegerItem %d\n", intem->GetValue()); + //index.Remove(*item); + } + + return 0; + + // BENCHMARK INSERT / REMOVAL + BenchmarkResult result = BenchmarkProtoSortedTreeStrings(itemCount, + minLen, + maxLen, + seed, + shuffleRemoval); + + std::printf("ProtoSortedTree string benchmark\n"); + std::printf(" itemCount : %zu\n", result.itemCount); + std::printf(" minLen : %u\n", result.minLen); + std::printf(" maxLen : %u\n", result.maxLen); + std::printf(" seed : %llu\n", + static_cast(result.seed)); + std::printf(" shuffleRemoval : %s\n", + result.shuffleRemoval ? "true" : "false"); + std::printf(" insertSeconds : %.9f\n", result.insertSeconds); + std::printf(" removeSeconds : %.9f\n", result.removeSeconds); + std::printf(" insertRate : %.3f ops/sec\n", + result.itemCount / result.insertSeconds); + std::printf(" removeRate : %.3f ops/sec\n", + result.itemCount / result.removeSeconds); + + result = BenchmarkProtoTreeStrings(itemCount, + minLen, + maxLen, + seed, + shuffleRemoval); + + std::printf("ProtoTree string benchmark\n"); + std::printf(" itemCount : %zu\n", result.itemCount); + std::printf(" minLen : %u\n", result.minLen); + std::printf(" maxLen : %u\n", result.maxLen); + std::printf(" seed : %llu\n", + static_cast(result.seed)); + std::printf(" shuffleRemoval : %s\n", + result.shuffleRemoval ? "true" : "false"); + std::printf(" insertSeconds : %.9f\n", result.insertSeconds); + std::printf(" removeSeconds : %.9f\n", result.removeSeconds); + std::printf(" insertRate : %.3f ops/sec\n", + result.itemCount / result.insertSeconds); + std::printf(" removeRate : %.3f ops/sec\n", + result.itemCount / result.removeSeconds); + + result = BenchmarkProtoSortedTreeFloats(itemCount, + minLen, + maxLen, + seed, + shuffleRemoval); + + std::printf("ProtoTree double benchmark\n"); + std::printf(" itemCount : %zu\n", result.itemCount); + std::printf(" minLen : %u\n", result.minLen); + std::printf(" maxLen : %u\n", result.maxLen); + std::printf(" seed : %llu\n", + static_cast(result.seed)); + std::printf(" shuffleRemoval : %s\n", + result.shuffleRemoval ? "true" : "false"); + std::printf(" insertSeconds : %.9f\n", result.insertSeconds); + std::printf(" removeSeconds : %.9f\n", result.removeSeconds); + std::printf(" insertRate : %.3f ops/sec\n", + result.itemCount / result.insertSeconds); + std::printf(" removeRate : %.3f ops/sec\n", + result.itemCount / result.removeSeconds); + +} // end main() diff --git a/include/manetGraph.h b/include/manetGraph.h index e815ceb..312478e 100755 --- a/include/manetGraph.h +++ b/include/manetGraph.h @@ -12,9 +12,9 @@ * for maintaining state, computing Dijkstra or other traversals, for * Mobile Ad-hoc Network (MANET) routing, etc. * -* (It is also useful for any routing, but the motivation for this is to -* support MANET R&D we are conducting. The "NetGraph" contains a set of -* "NetGraph::Interface" instances that may be connected with some associated +* (It is also useful for any routing, but the motivation for this is to +* support MANET R&D we are conducting. The "NetGraph" contains a set of +* "NetGraph::Interface" instances that may be connected with some associated * "Cost" with "NetGraph::Link" instances (NetGraph::Link's are uni-directional, * but convenience methods for bi-directional connectivity are provided). * Additionally, a "ManetNode" class is provide to associate a set of @@ -26,14 +26,14 @@ // keep the name "NetGraph" free or just use it for our example // template usage instead of ManetGraph and actually rename this // entire ".h" as "netGraph.h" instead of "manetGraph.h" and then -// "ManetGraph" would be available as a name. +// "ManetGraph" would be available as a name. // // This would makes sense since "NetGraph" here essentially just adds // the notion of "cost" to graph edges and provides for some // cost-based traversals (e.g. Dijkstra). It also defines "Interfaces" // as vertices that are identified by a ProtoAddress. Then the derived // Protolib "ManetGraph" could add ProtoTimer and other elements to -// to links (edges) and interfaces (vertices) that are more applicable +// to links (edges) and interfaces (vertices) that are more applicable // for the dynamic wireless environment that MANET strives to support. @@ -41,7 +41,7 @@ class NetGraph : public ProtoGraph { public: virtual ~NetGraph(); - + /** * @class NetGraph::Cost * @@ -52,88 +52,88 @@ class NetGraph : public ProtoGraph { public: virtual ~Cost(); - + // Required overrides virtual const char* GetCostKey() const = 0; virtual unsigned int GetCostKeysize() const = 0; // in bits - + // These methods help ProtoSortedTree when comparing keys (i.e. cost value) // (Note the ProtoSortedTree does a modified lexical sort based on these) virtual bool GetCostKeySigned() const = 0; virtual bool GetCostKeyComplement2() const = 0; virtual ProtoTree::Endian GetCostKeyEndian() const = 0; - - // Copy operator + + // Copy operator virtual Cost& operator=(const Cost& cost) = 0; - + // Value control virtual void Minimize() = 0; - + // Addition operator virtual void operator+=(const Cost& cost) = 0; - + // Cost comparison methods virtual bool operator>(const Cost& cost) const = 0; - + virtual bool operator==(const Cost& cost) const = 0; - + bool operator!=(const Cost& cost) const {return (!(cost == *this));} - + bool operator>=(const Cost& cost) const {return ((*this > cost) || (*this == cost));} - + bool operator<(const Cost& cost) const {return ((*this >= cost) ? false : true);} - + bool operator<=(const Cost& cost) const {return ((*this > cost) ? false : true);} - + protected: Cost(); - + }; // end class NetGraph::Cost - + /** * @class NetGraph::SimpleCostTemplate * * @brief This wraps "double" floating point cost value. We assume - * IEEE754 format for the "value" member (I do have code for - * converting native machine floating point values to/from - * IEEE754 if needed) + * IEEE754 format for the "value" member (I do have code for + * converting native machine floating point values to/from + * IEEE754 if needed) * * (TBD) Make "SimpleCost" a template class based upon a built-in type? * (e.g., double, int, etc) */ template class SimpleCostTemplate : public Cost - { + { public: SimpleCostTemplate() : value(0) {} SimpleCostTemplate(SIMPLE_TYPE theValue) : value(theValue) {} virtual ~SimpleCostTemplate() {} - + void SetValue(SIMPLE_TYPE theValue) {value = theValue;} - + SIMPLE_TYPE GetValue() const {return value;} - + operator SIMPLE_TYPE() const {return value;} - + SimpleCostTemplate& operator=(SIMPLE_TYPE theValue) { value = theValue; return *this; } - + SimpleCostTemplate& operator=(const SimpleCostTemplate& cost) { value = cost.value; return *this; } - + // Required overrides of pure virtual methods // (These are used to help sorting by value) const char* GetCostKey() const @@ -146,46 +146,46 @@ class NetGraph : public ProtoGraph {return false;} virtual ProtoTree::Endian GetCostKeyEndian() const {return ProtoTree::GetNativeEndian();} - - Cost& operator=(const Cost& cost) + + Cost& operator=(const Cost& cost) { ASSERT(NULL != dynamic_cast(&cost)); value = static_cast(cost).value; return *this; } - + void Minimize() { value = 0;} - - bool operator==(const Cost& cost) const + + bool operator==(const Cost& cost) const { ASSERT(NULL != dynamic_cast(&cost)); return (value == static_cast(cost).value); } - - bool operator>(const Cost& cost) const + + bool operator>(const Cost& cost) const { ASSERT(NULL != dynamic_cast(&cost)); return (value > static_cast(cost).value); } - + void operator+=(const Cost& cost) { ASSERT(NULL != dynamic_cast(&cost)); value += static_cast(cost).value; } - + protected: - SIMPLE_TYPE value; - + SIMPLE_TYPE value; + }; // end class NetGraph::SimpleCostTemplate - + /** * @class NetGraph::SimpleCostDouble * - * @brief This SimpleCost variant holds a "double" floating point cost value. - * We assume an IEEE754 format for the "value" member (I do have - * code for converting native machine floating point values to/from + * @brief This SimpleCost variant holds a "double" floating point cost value. + * We assume an IEEE754 format for the "value" member (I do have + * code for converting native machine floating point values to/from * IEEE754 if needed) */ class SimpleCostDouble : public SimpleCostTemplate @@ -194,7 +194,7 @@ class NetGraph : public ProtoGraph SimpleCostDouble() {} SimpleCostDouble(double theValue) : SimpleCostTemplate(theValue) {} }; // end class NetGraph::SimpleCostDouble - + class SimpleCostUINT32 : public SimpleCostTemplate { public: @@ -204,7 +204,7 @@ class NetGraph : public ProtoGraph bool GetCostKeySigned() const {return false;} }; // end class NetGraph::SimpleCostUINT32 - + class SimpleCostUINT8 : public SimpleCostTemplate { public: @@ -214,10 +214,10 @@ class NetGraph : public ProtoGraph bool GetCostKeySigned() const {return false;} }; // end class NetGraph::SimpleCostUINT8 - + class Interface; class Link; - + // TBD - Should the AdjacentyIterator be declared inside the Interface declaration? // If we did this, the templated version could return the correct types class AdjacencyIterator : public ProtoGraph::AdjacencyIterator @@ -228,10 +228,10 @@ class NetGraph : public ProtoGraph Interface* GetNextAdjacency() {return static_cast(ProtoGraph::AdjacencyIterator::GetNextAdjacency());} - + Link* GetNextAdjacencyLink() {return static_cast(ProtoGraph::AdjacencyIterator::GetNextAdjacencyEdge());} - + Interface* GetNextConnector() {return static_cast(ProtoGraph::AdjacencyIterator::GetNextConnector());} @@ -240,24 +240,24 @@ class NetGraph : public ProtoGraph /** * @class NetGraph::Link * - * @brief adds "cost" attribute to ProtoGraph::Edge + * @brief adds "cost" attribute to ProtoGraph::Edge */ class Link : public Edge { public: virtual ~Link(); - + // Our template below will override this for us. virtual const Cost& GetCost() const = 0; - + void SetCost(const Cost& cost); - + Interface* GetSrc() const {return static_cast(Edge::GetSrc());} - + Interface* GetDst() const {return static_cast(Edge::GetDst());} - + // Required overrides virtual const char* GetKey() const {return GetCost().GetCostKey();} @@ -269,12 +269,12 @@ class NetGraph : public ProtoGraph {return GetCost().GetCostKeySigned();} virtual bool UseComplement2() const {return GetCost().GetCostKeyComplement2();} - + protected: Link(); // Our template below will override this for us. virtual Cost& AccessCost() = 0; - + }; // end class NetGraph::Link class Node; // a "Node" is a "super-vertice" in a NetGraph while an @@ -284,7 +284,7 @@ class NetGraph : public ProtoGraph * @class NetGraph::Interface * * @brief adds "address" identifier to ProtoGraph::Vertice and also - * ties "Interface" to NetGraph::Node + * ties "Interface" to NetGraph::Node * Note the "ProtoSortedTree::Item()" aspect is for its inclusion its * "node" iface_list only */ @@ -294,61 +294,61 @@ class NetGraph : public ProtoGraph public: Interface(Node& theNode, const ProtoAddress& addr); Interface(Node& theNode); - virtual ~Interface(); - - const ProtoAddress& GetAddress() const + virtual ~Interface(); + + const ProtoAddress& GetAddress() const {return default_addr_item.GetAddress();} const ProtoAddress& GetAnyAddress() const {return GetAddress();} ProtoAddressList& GetAddressList() {return addr_list;} - + bool SetName(const char* theName); const char* GetName() const {return name_ptr;} void ClearName(); // nullifies name - + // Use to add additional "extra" addresses - // Note: Any graphs currently containing this interface get be updated as well + // Note: Any graphs currently containing this interface get be updated as well bool AddAddress(const ProtoAddress& theAddress); bool RemoveAddress(const ProtoAddress& theAddress); - + bool Contains(const ProtoAddress& theAddress) const {return addr_list.Contains(theAddress);} - + const ProtoAddress& GetDefaultAddress() const {return default_addr_item.GetAddress();} - + //void SetAddress(const ProtoAddress& theAddress) // {address = theAddress;} Node& GetNode() const {return *node;} - + const Node* GetNodePtr() const {return node;} bool ChangeNode(Node& theNode); - + bool HasLinkTo(const Interface& dstIface) const {return ProtoGraph::Vertice::HasEdgeTo(dstIface);} - + Link* GetLinkTo(const Interface& dstIface) const {return static_cast(ProtoGraph::Vertice::GetEdgeTo(dstIface));} - + // This maintains a simple, unsorted (non-indexed) list of Interfaces class SimpleList : public Vertice::SimpleList { public: SimpleList(ItemPool* itemPool = NULL); virtual ~SimpleList(); - + Interface* GetHead() const {return static_cast(Vertice::SimpleList::GetHead());} - + Interface* RemoveHead() {return static_cast(Vertice::SimpleList::RemoveHead());} - + class Iterator : public Vertice::SimpleList::Iterator { public: @@ -359,25 +359,25 @@ class NetGraph : public ProtoGraph {return static_cast(GetNextVertice());} }; // end class NetGraph::Interface::SimpleList::Iterator - + }; // end class NetGraph::Interface::SimpleList - + // This maintains a list of Interfaces, sorted by their "key", etc class SortedList : public Vertice::SortedList { public: SortedList(ItemPool* itemPool = NULL); virtual ~SortedList(); - + Interface* FindInterface(const ProtoAddress& addr) const {return static_cast(FindVertice(addr.GetRawHostAddress(), addr.GetLength() << 3));} - + Interface* GetHead() const {return static_cast(Vertice::SortedList::GetHead());} - + Interface* RemoveHead() {return static_cast(Vertice::SortedList::RemoveHead());} - + class Iterator : public Vertice::SortedList::Iterator { public: @@ -388,86 +388,86 @@ class NetGraph : public ProtoGraph {return static_cast(GetNextVertice());} }; // end class NetGraph::Interface::SortedList::Iterator - + }; // end class NetGraph::Interface::SortedList - + // PriorityQueue class to use for traversal purposes // This sorts by "Cost" associated with the interface class PriorityQueue : public Vertice::SortedList { public: class ItemFactory; - + PriorityQueue(ItemFactory& itemFactory); virtual ~PriorityQueue(); - + bool Insert(Interface& iface, const Cost& cost); - + void Remove(Interface& iface) {SortedList::Remove(iface);} - + Interface* RemoveHead() {return static_cast(SortedList::RemoveHead());} - + bool IsEmpty() const {return iface_list.IsEmpty();} - + Interface* GetHead() const {return static_cast(SortedList::GetHead());} - + const Cost* GetCost(const Interface& iface) const { Item* item = static_cast(GetQueueState(iface)); return ((NULL != item) ? &(item->GetCost()) : NULL); } - + // Move vertice from this PriorityQueue to another void TransferInterface(Interface& iface, PriorityQueue& dstQueue) {SortedList::TransferVertice(iface, dstQueue);} - + void TransferItem(Item& item, PriorityQueue& dstQueue) {SortedList::TransferItem(item, dstQueue);} - + // These are used to query enqueued interfaces post-Dijkstra Interface* GetNextHop(const Interface& iface) const { - Item* item = static_cast(GetQueueState(iface)); + Item* item = static_cast(GetQueueState(iface)); return ((NULL != item) ? item->GetNextHop() : NULL); } Link* GetNextHopLink(const Interface& iface) const { - Item* item = static_cast(GetQueueState(iface)); + Item* item = static_cast(GetQueueState(iface)); return ((NULL != item) ? item->GetNextHopLink() : NULL); } Interface* GetPrevHop(const Interface& iface) const { - Item* item = static_cast(GetQueueState(iface)); + Item* item = static_cast(GetQueueState(iface)); return ((NULL != item) ? item->GetPrevHop() : NULL); } void SetRouteInfo(Interface& iface, Link* nextHopLink, Interface* prevHop) { - Item* item = static_cast(GetQueueState(iface)); + Item* item = static_cast(GetQueueState(iface)); ASSERT(NULL != item); item->SetNextHopLink(nextHopLink); item->SetPrevHop(prevHop); } - + void Adjust(Interface& iface, const Cost& newCost); bool AdjustDownward(Interface& iface, const Cost& newCost,const Interface* newPrevHop = NULL); bool AdjustUpward(Interface& iface, const Cost& newCost); - + // Note use of this method does not maintain priority queue sorting order! bool Append(Interface& iface); // used for Dijkstra "tree walking" only - + class Item : public SortedList::Item { public: virtual ~Item(); - + // Our subclass templates will override these virtual const Cost& GetCost() const = 0; virtual void SetCost(const Cost& cost) = 0; - + // "ProtoGraph::Vertice::SortedList::Item" overrides // (We sort our PriorityQueue items by "cost") const char* GetKey() const @@ -480,19 +480,19 @@ class NetGraph : public ProtoGraph {return GetCost().GetCostKeySigned();} virtual bool UseComplement2() const {return GetCost().GetCostKeyComplement2();} - + Interface* GetInterface() const {return static_cast(GetVertice());} - + // These are useful post-Djikstra completion void SetPrevHop(Interface* prevHop) {prev_hop = prevHop;} Interface* GetPrevHop() const {return prev_hop;} - void SetNextHopLink(Link* nextHopLink) + void SetNextHopLink(Link* nextHopLink) {next_hop_link = nextHopLink;} - Link* GetNextHopLink() const + Link* GetNextHopLink() const {return next_hop_link;} Interface* GetNextHop() const {return ((NULL != next_hop_link) ? next_hop_link->GetDst() : NULL);} @@ -501,18 +501,18 @@ class NetGraph : public ProtoGraph Item(); // Our subclass templates will override this virtual Cost& AccessCost() = 0; - + private: Interface* prev_hop; // reverse path towards srcIFace - Link* next_hop_link; // forward path from srcIface to here - + Link* next_hop_link; // forward path from srcIface to here + }; // end class NetGraph::Interface::PriorityQueue::Item - + class ItemFactory { public: virtual ~ItemFactory(); - + void Destroy() {item_pool.Destroy();} @@ -520,40 +520,40 @@ class NetGraph : public ProtoGraph void PutItem(Item& item) {item_pool.PutItem(item);} - + protected: ItemFactory(); virtual Item* CreateItem() const = 0; - + // Member variables SortedList::ItemPool item_pool; - + }; // end class NetGraph::Interface::PriorityQueue::ItemFactory - + class Iterator : public SortedList::Iterator { public: Iterator(PriorityQueue& priorityQueue); virtual ~Iterator(); - - Interface* GetNextInterface() + + Interface* GetNextInterface() {return static_cast(SortedList::Iterator::GetNextVertice());} - - Item* GetNextItem() + + Item* GetNextItem() {return static_cast(SortedList::Iterator::GetNextItem());} - + }; // end NetGraph::Interface::PriorityQueue::Iterator - + protected: // Member variables ProtoSortedTree iface_list; // sorted by "Cost" value ItemFactory& item_factory; - + private: using Vertice::SortedList::Remove; // gets rid of hidden overloaded virtual function warning - + }; // end NetGraph::Interface::PriorityQueue - + protected: // Overrides for interfaces with "key" based on address // ProtoGraph::Vertice parent class overrides @@ -564,29 +564,29 @@ class NetGraph : public ProtoGraph // class destructor _MUST_ call Vertice::Cleanup() so // that these _are_ not indirectly called in the Vertice // destructor!!! - + // These affect the Interface's sorting criteria // in the ProtoGraph::vertice_list and any Interface::SortedList // membership. virtual const char* GetVerticeKey() const; virtual unsigned int GetVerticeKeysize() const; - + private: // ProtoSortedTree::Item parent class overrides virtual const char* GetKey() const {return GetVerticeKey();} virtual unsigned int GetKeysize() const {return GetVerticeKeysize();} - + Node* node; NetGraph* graph; ProtoAddressList addr_list; ProtoAddressList::Item default_addr_item; - char* name_ptr; + char* name_ptr; }; // end class NetGraph::Interface - + // The "Node" class associates multiple interfaces together even if they - // are not connected in a ManetGraph. A "Node" reference is required in + // are not connected in a ManetGraph. A "Node" reference is required in // the "Interface" constructor. Note that when a "Node" is deleted, it // deletes any Interfaces contained in its "iface_list" class Node @@ -599,35 +599,35 @@ class NetGraph : public ProtoGraph Interface* FindInterface(const ProtoAddress& addr) const; // {return static_cast(iface_list.Find(addr.GetRawHostAddress(), addr.GetLength() << 3));} -// {return reinterpret_cast((void*)addr_list.GetUserData(addr));} +// {return reinterpret_cast((void*)addr_list.GetUserData(addr));} Interface* FindInterfaceByName(const char* theName); Interface* FindInterfaceByString(const char* theString); //looks for it as both a name and address bool AddInterface(Interface& iface, bool makeDefault = false); - - void RemoveInterface(Interface& iface); - + + void RemoveInterface(Interface& iface); + // Note "AppendInterface() should be deprecated bool AppendInterface(Interface& iface, bool makeDefault = false) - {return AddInterface(iface, makeDefault);} - + {return AddInterface(iface, makeDefault);} + bool Contains(const Interface& iface) const {return (iface.GetNodePtr() == this);} - + Interface* GetAnyInterface() const - {return static_cast(iface_list.GetRoot());} + {return static_cast(iface_list.GetHead());} Interface* GetDefaultInterface() const {return static_cast(default_interface_ptr);} - + bool IsSymmetricNeighbor(Node& node); - + class InterfaceIterator : public ProtoSortedTree::Iterator { public: InterfaceIterator(Node& theNode); virtual ~InterfaceIterator(); - + bool HasEmptyList() {return HasEmptyTree();} @@ -636,32 +636,32 @@ class NetGraph : public ProtoGraph Interface* GetNextInterface() {return static_cast(GetNextItem());} - + }; // end class NetGraph::Node::InterfaceIterator - + friend class InterfaceIterator; friend class NetGraph::Interface; - + // Iterate over all _neighboring_ interfaces class NeighborIterator { public: NeighborIterator(Node& theNode); virtual ~NeighborIterator(); - + void Reset(); - + Interface* GetNextNeighborInterface(); - + Link* GetNextNeighborLink(); - + private: InterfaceIterator iface_iterator; AdjacencyIterator adj_iterator; }; // end class NetGraph::Node::NeighborIterator - protected: - + protected: + ProtoSortedTree iface_list; ProtoAddressList extra_addr_list; // contains list of ifaces' "extra" addresses @@ -671,10 +671,10 @@ class NetGraph : public ProtoGraph void RemoveExtraInterfaceAddress(const ProtoAddress& addr) {extra_addr_list.Remove(addr);} bool SetDefaultInterface(Interface& iface); - + Interface* default_interface_ptr; }; // end class NetGraph::Node - + // NetGraph control/query methods bool InsertNode(Node& node, Interface* iface = NULL); //this function will be removed in upcoming releases bool InsertInterface(Interface& iface); // this function should be used instead of InsertNode() @@ -683,23 +683,23 @@ class NetGraph : public ProtoGraph Interface* FindInterface(const ProtoAddress& addr) const {return ((Interface*)addr_list.GetUserData(addr));} - + Node* FindNode(const ProtoAddress& theAddress) { Interface* iface = FindInterface(theAddress); return ((NULL != iface) ? &iface->GetNode() : NULL); } - - Interface* FindInterfaceByName(const char *theName); - + + Interface* FindInterfaceByName(const char *theName); + Interface* FindInterfaceByString(const char *theString); // finds the interface both by name and address - - Node* FindNodeByName(const char *theName) + + Node* FindNodeByName(const char *theName) { Interface* iface = FindInterfaceByName(theName); return ((NULL != iface) ? &iface->GetNode() : NULL); } - + Node* FindNodeByString(const char* theString) { Interface* iface = FindInterfaceByString(theString); @@ -714,106 +714,106 @@ class NetGraph : public ProtoGraph Interface* GetNextInterface() {return static_cast(GetNextVertice());} - + }; // end class NetGraph::InterfaceIterator - - + + class SimpleTraversal : protected ProtoGraph::SimpleTraversal { public: - SimpleTraversal(const NetGraph& theGraph, + SimpleTraversal(const NetGraph& theGraph, Interface& startIface, bool traverseNodes = true, bool collapseNodes = true, bool depthFirst = false); - + virtual ~SimpleTraversal(); - + bool Reset() {return Reset(false);} - + Interface* GetNextInterface(unsigned int* level = NULL); - - protected: + + protected: // Override this method to filter which edges are included in traversal // (return "false" to disallow specific edges) // Note "link" will be NULL is src/dst are on same node virtual bool AllowLink(const Interface& srcIface, const Interface& dstIface, Link* link) {return true;} - + bool Reset(bool constructor); // arg for internal-use only - + bool traverse_nodes; // traverse all node interfaces bool collapse_nodes; // treat node co-interfaces as a common vertice - + }; // end class NetGraph::SimpleTraversal - + class DijkstraTraversal : public Interface::PriorityQueue::ItemFactory { public: virtual ~DijkstraTraversal(); - + // Set to false by default; If set to true the traversal will iterate over nodes as well as interfaces. void TraverseNodes(bool traverse); - + bool Reset(Interface* startIface = NULL); - + Interface* GetNextInterface(); - + bool PrevHopIsValid(Interface& currentIface); - + void Update(Interface& startIface); - + void Update(Interface& ifaceA, Interface& ifaceB); - + // Override this method to filter which edges are included in traversal // (return "false" to disallow specific links) virtual bool AllowLink(const Interface& srcIface, const Link& link) {return true;} - + // (use these post-Dijkstra (after "GetNextInterface" returns NULL) Interface* GetNextHop(const Interface& dstIface) // from "startIface" towards "dstIface" {return (queue_visited.GetNextHop(dstIface));} - + Interface* GetPrevHop(const Interface& dstIface) // back towards "startIface" {return (queue_visited.GetPrevHop(dstIface));} - + const Cost* GetCost(const Interface& dstIface) const {return (queue_visited.GetCost(dstIface));} - + // BFS traversal of routing tree ("tree walk") bool TreeWalkReset(); Interface* TreeWalkNext(unsigned int* level = NULL); - + protected: - DijkstraTraversal(NetGraph& theGraph, + DijkstraTraversal(NetGraph& theGraph, Interface* startIface); - - DijkstraTraversal(NetGraph& theGraph, + + DijkstraTraversal(NetGraph& theGraph, Node& startNode, Interface* startIface = NULL); - + // Note: The template subclass provides the "ItemFactory::CreateItem()" method - + // Our templates below override this one virtual Cost& AccessCostTemp() = 0; - + NetGraph& manet_graph; Interface* start_iface; Interface::PriorityQueue queue_pending; Interface::PriorityQueue queue_visited; - + // These two members support the "tree walk" BFS Interface* trans_iface; unsigned int current_level; - + bool dijkstra_completed; bool in_update; bool traverse_nodes; bool reset_required; - }; // end class NetGraph::DijkstraTraversal - - + }; // end class NetGraph::DijkstraTraversal + + // These Link and Interface Template definitions may be used by developers along // with the NetGraphTemplate definition below to build custom link/interface/graph types. template @@ -822,28 +822,28 @@ class NetGraph : public ProtoGraph public: LinkTemplate() {} virtual ~LinkTemplate() {} - + // required override const COST_TYPE& GetCost() const - {return cost;} - + {return cost;} + void SetCost(COST_TYPE& theCost) {cost = theCost;} - + IFACE_TYPE* GetSrc() const {return static_cast(Edge::GetSrc());} - + IFACE_TYPE* GetDst() const {return static_cast(Edge::GetDst());} - + private: virtual Cost& AccessCost() {return static_cast(cost);} COST_TYPE cost; - + }; // end class NetGraph::LinkTemplate - - + + template class InterfaceTemplate : public Interface { @@ -851,40 +851,40 @@ class NetGraph : public ProtoGraph InterfaceTemplate(NODE_TYPE& theNode, const ProtoAddress& addr) : Interface(theNode, addr) {} InterfaceTemplate(NODE_TYPE& theNode) : Interface(theNode) {} virtual ~InterfaceTemplate() {} - + LINK_TYPE* GetLinkTo(const InterfaceTemplate& dst) const {return static_cast(Interface::GetLinkTo(dst));} NODE_TYPE& GetNode() const - {return static_cast(Interface::GetNode());} - + {return static_cast(Interface::GetNode());} + const NODE_TYPE* GetNodePtr() const - {return static_cast(Interface::GetNodePtr());} - + {return static_cast(Interface::GetNodePtr());} + const COST_TYPE* GetCostTo(const InterfaceTemplate& dst) const { LINK_TYPE* link = GetLinkTo(dst); return (NULL != link) ? static_cast(&(link->GetCost())) : (COST_TYPE*)NULL; } - + static MY_TYPE* GetSrc(Link& theLink) {return static_cast(theLink.GetSrc());} - + static MY_TYPE* GetDst(Link& theLink) {return static_cast(theLink.GetDst());} - + class SimpleList : public NetGraph::Interface::SimpleList { public: SimpleList(ItemPool* itemPool = NULL) : NetGraph::Interface::SimpleList(itemPool) {} virtual ~SimpleList() {} - + MY_TYPE* GetHead() const {return static_cast(NetGraph::Interface::SimpleList::GetHead());} - + MY_TYPE* RemoveHead() {return static_cast(NetGraph::Interface::SimpleList::RemoveHead());} - + class Iterator : public NetGraph::Interface::SimpleList::Iterator { public: @@ -895,16 +895,16 @@ class NetGraph : public ProtoGraph {return static_cast(NetGraph::Interface::SimpleList::Iterator::GetNextInterface());} }; // end class NetGraph::InterfaceTemplate::SimpleList::Iterator - + }; // end class NetGraph::InterfaceTemplate::SimpleList - + class SortedList : public NetGraph::Interface::SortedList { public: SortedList(ItemPool* itemPool = NULL) : NetGraph::Interface::SortedList(itemPool) {} virtual ~SortedList() {} - - + + MY_TYPE* FindInterface(const ProtoAddress& addr) const {return static_cast(FindVertice(addr.GetRawHostAddress(), addr.GetLength() << 3));} @@ -913,10 +913,10 @@ class NetGraph : public ProtoGraph MY_TYPE* GetHead() const {return static_cast(Vertice::SortedList::GetHead());} - + MY_TYPE* RemoveHead() {return static_cast(Vertice::SortedList::RemoveHead());} - + class Iterator : public NetGraph::Interface::SortedList::Iterator { public: @@ -927,16 +927,16 @@ class NetGraph : public ProtoGraph {return static_cast(NetGraph::Interface::SortedList::Iterator::GetNextInterface());} }; // end class NetGraph::InterfaceTemplate::SortedList::Iterator - + }; // end class NetGraph::InterfaceTemplate::SortedList - + class PriorityQueue : public NetGraph::Interface::PriorityQueue { public: PriorityQueue() : NetGraph::Interface::PriorityQueue(builtin_item_factory) {} PriorityQueue(ItemFactory& itemFactory) : NetGraph::Interface::PriorityQueue(itemFactory) {} virtual ~PriorityQueue() {} - + class Item : public NetGraph::Interface::PriorityQueue::Item { public: @@ -945,7 +945,7 @@ class NetGraph : public ProtoGraph const Cost& GetCost() const {return static_cast(cost);} - + void SetCost(const Cost& theCost) {cost = static_cast(theCost);} @@ -954,82 +954,82 @@ class NetGraph : public ProtoGraph {return static_cast(cost);} COST_TYPE cost; }; // end class NetGraph::PriorityQueue::Item - + class ItemFactory : public NetGraph::Interface::PriorityQueue::ItemFactory { public: ItemFactory() {} virtual ~ItemFactory() {} - + protected: NetGraph::Interface::PriorityQueue::Item* CreateItem() const {return static_cast(new Item);} // creates new templated "Item" - + }; // end class NetGraph::InterfaceTemplate::PriorityQueue::ItemFactory() - + private: ItemFactory builtin_item_factory; - + }; // end class NetGraph::InterfaceTemplate::PriorityQueue - + }; // end class NetGraph::InterfaceTemplate - + template class DefaultInterfaceTemplate : public InterfaceTemplate > { public: - DefaultInterfaceTemplate(NODE_TYPE& theNode, const ProtoAddress& addr) + DefaultInterfaceTemplate(NODE_TYPE& theNode, const ProtoAddress& addr) : InterfaceTemplate(theNode, addr) {} virtual ~DefaultInterfaceTemplate() {} }; // end class NetGraph::DefaultInterfaceTemplate - - + + template class NodeTemplate : public Node { public: NodeTemplate() {} virtual ~NodeTemplate() {} - + IFACE_TYPE* FindInterface(const ProtoAddress& addr) const {return static_cast(NetGraph::Node::FindInterface(addr));} - + IFACE_TYPE* FindInterfaceByName(const char* theName) {return static_cast(NetGraph::Node::FindInterfaceByName(theName));} IFACE_TYPE* GetDefaultInterface() const {return static_cast(NetGraph::Node::GetDefaultInterface());} - + class InterfaceIterator : public NetGraph::Node::InterfaceIterator { public: InterfaceIterator(Node& node) : NetGraph::Node::InterfaceIterator(node) {} virtual ~InterfaceIterator() {} - - IFACE_TYPE* GetNextInterface() + + IFACE_TYPE* GetNextInterface() {return static_cast(NetGraph::Node::InterfaceIterator::GetNextInterface());} - + }; // end class NetGraphTemplate::Node::InterfaceIterator class NeighborIterator : public NetGraph::Node::NeighborIterator { public: NeighborIterator(Node& node) : NetGraph::Node::NeighborIterator(node) {} virtual ~NeighborIterator() {} - + IFACE_TYPE* GetNextNeighborInterface() {return static_cast(NetGraph::Node::NeighborIterator::GetNextNeighborInterface());} - + LINK_TYPE* GetNextNeighborLink() {return static_cast(NetGraph::Node::NeighborIterator::GetNextNeighborLink());} }; // end class NetGraph::NodeTemplate::NeighborIterator }; // end class NetGraph::NodeTemplate - - + + protected: NetGraph(); - // Netgraph::Interface calls these when adding or removing addresses + // Netgraph::Interface calls these when adding or removing addresses bool AddInterfaceAddress(const Interface& iface, const ProtoAddress& addr) {return addr_list.Insert(addr, &iface);} void RemoveInterfaceAddress(const ProtoAddress& addr) @@ -1037,18 +1037,18 @@ class NetGraph : public ProtoGraph void SuspendInterface(Interface& iface) {vertice_list.Remove(iface);} bool ResumeInterface(Interface& iface) - {return vertice_list.Insert(iface);} - + {return vertice_list.Insert(iface);} + // Our template provides a type-safe "public" override of this Link* Connect(Interface& srcIface, Interface& dstIface, const Cost& cost); bool Connect(Interface& srcIface, Interface& dstIface, const Cost& cost, bool duplex); - + Link* Reconnect(Interface& srcIface, Interface& dstIface, const Cost& cost); bool Reconnect(Interface& srcIface, Interface& dstIface, const Cost& cost, bool duplex); - + private: ProtoAddressList addr_list; // list of _all_ addresses of all contained interfaces - + }; // end class NetGraph @@ -1061,72 +1061,72 @@ class NetGraph : public ProtoGraph // Note that further below we declare a "ManetGraph" subclass as an example // that uses the "NetGraph::SimpleCost" that was declared above. -template , - class LINK_TYPE = NetGraph::LinkTemplate, +template , + class LINK_TYPE = NetGraph::LinkTemplate, class NODE_TYPE = NetGraph::NodeTemplate > class NetGraphTemplate : public NetGraph { public: NetGraphTemplate() {} virtual ~NetGraphTemplate() {} - - // These typedefs let us use DerivedGraph::Interface and DerivedGraph::Link types that + + // These typedefs let us use DerivedGraph::Interface and DerivedGraph::Link types that // are synonomous with passed-in template interface/link types typedef COST_TYPE Cost; typedef IFACE_TYPE Interface; typedef LINK_TYPE Link; typedef NODE_TYPE Node; - + NODE_TYPE* FindNode(const ProtoAddress& theAddress) {return static_cast(NetGraph::FindNode(theAddress));} - + IFACE_TYPE* FindInterface(const ProtoAddress& addr) const {return static_cast(NetGraph::FindInterface(addr));} - + IFACE_TYPE* FindInterfaceByName(const char* name) {return static_cast(NetGraph::FindInterfaceByName(name));} IFACE_TYPE* FindInterfaceByString(const char* theString) {return static_cast(NetGraph::FindInterfaceByString(theString));} - + // Note for the "SimpleTypeTemplate" and its derivatives for "double", "int", etc // have casting/conversion operators defined that allow direct use of the // corresponding "simple" type (i.e. "double", etc) for the "cost" argument here. LINK_TYPE* Connect(IFACE_TYPE& srcIface, IFACE_TYPE& dstIface, const COST_TYPE& cost) {return static_cast(NetGraph::Connect(srcIface, dstIface, cost));} - + bool Connect(IFACE_TYPE& srcIface, IFACE_TYPE& dstIface, const COST_TYPE& cost, bool duplex) {return NetGraph::Connect(srcIface, dstIface, cost, duplex);} - + LINK_TYPE* Reconnect(Interface& srcIface, Interface& dstIface, const Cost& cost) {return static_cast(NetGraph::Reconnect(srcIface, dstIface, cost));} - + bool Reconnect(IFACE_TYPE& srcIface, IFACE_TYPE& dstIface, const COST_TYPE& cost, bool duplex) {return NetGraph::Reconnect(srcIface, dstIface, cost, duplex);} - + // TBD - provide a GetLinkList() to get list of links from "srcIface" to "dstIface" LINK_TYPE* GetLink(IFACE_TYPE& srcIface, IFACE_TYPE& dstIface) {return static_cast(srcIface.GetLinkTo(dstIface));} - - + + class AdjacencyIterator : public NetGraph::AdjacencyIterator { public: AdjacencyIterator(IFACE_TYPE& iface) : NetGraph::AdjacencyIterator(iface) {} virtual ~AdjacencyIterator() {} - + IFACE_TYPE* GetNextAdjacency() {return static_cast(NetGraph::AdjacencyIterator::GetNextAdjacency());} - + LINK_TYPE* GetNextAdjacencyLink() {return static_cast(NetGraph::AdjacencyIterator::GetNextAdjacencyLink());} - + IFACE_TYPE* GetNextConnector() {return static_cast(NetGraph::AdjacencyIterator::GetNextConnector());} - + }; // end class NetGraphTemplate::AdjacencyIterator - + class InterfaceIterator : public NetGraph::InterfaceIterator { public: @@ -1135,93 +1135,93 @@ class NetGraphTemplate : public NetGraph IFACE_TYPE* GetNextInterface() {return static_cast(NetGraph::InterfaceIterator::GetNextVertice());} - + }; // end class NetGraphTemplate::InterfaceIterator - + class SimpleTraversal : public NetGraph::SimpleTraversal { public: - SimpleTraversal(const NetGraphTemplate& theGraph, + SimpleTraversal(const NetGraphTemplate& theGraph, IFACE_TYPE& startIface, bool traverseNodes = true, bool collapseNodes = true, bool depthFirst = false) : NetGraph::SimpleTraversal(theGraph, startIface, traverseNodes, collapseNodes, depthFirst) {} virtual ~SimpleTraversal() {} - + IFACE_TYPE* GetNextInterface(unsigned int* level = NULL) {return static_cast(NetGraph::SimpleTraversal::GetNextInterface(level));} - + }; // end class NetGraphTemplate::SimpleTraversal - + class DijkstraTraversal : public NetGraph::DijkstraTraversal { public: - DijkstraTraversal(NetGraphTemplate& theGraph, + DijkstraTraversal(NetGraphTemplate& theGraph, Node& startNode, - IFACE_TYPE* startIface = NULL) + IFACE_TYPE* startIface = NULL) : NetGraph::DijkstraTraversal(theGraph, startNode, startIface) { Reset(); } - + virtual ~DijkstraTraversal() {} - + IFACE_TYPE* GetNextInterface() {return static_cast(NetGraph::DijkstraTraversal::GetNextInterface());} - + // (use these post-Dijkstra (i.e., after "GetNextInterface" returns NULL) - const COST_TYPE* GetCost(const IFACE_TYPE& iface) const + const COST_TYPE* GetCost(const IFACE_TYPE& iface) const {return static_cast(NetGraph::DijkstraTraversal::GetCost(iface));} - + IFACE_TYPE* GetNextHop(const IFACE_TYPE& dstIface) // from "startIface" towards "dstIface" {return static_cast(queue_visited.GetNextHop(dstIface));} - + IFACE_TYPE* GetPrevHop(const IFACE_TYPE& dstIface) // back towards "startIface" {return static_cast(queue_visited.GetPrevHop(dstIface));} - + // BFS traversal of routing tree ("tree walk") IFACE_TYPE* TreeWalkNext(unsigned int* level = NULL) {return static_cast(NetGraph::DijkstraTraversal::TreeWalkNext(level));} - + protected: - Cost& AccessCostTemp() - {return static_cast(cost_temp);} - + Cost& AccessCostTemp() + {return static_cast(cost_temp);} + // Required override of NetGraph::Interface::PriorityQueue::ItemFactory::CreateItem() - NetGraph::Interface::PriorityQueue::Item* CreateItem() const + NetGraph::Interface::PriorityQueue::Item* CreateItem() const {return static_cast(new typename IFACE_TYPE::PriorityQueue::Item);} - + COST_TYPE cost_temp; - + }; // end class NetGraphTemplate::DijkstraTraversal - + protected: // Override of ProtoGraph::CreateEdge() - virtual Edge* CreateEdge() const + virtual Edge* CreateEdge() const {return static_cast(new LINK_TYPE);} - + }; // end class NetGraphTemplate -// TBD - Rename the above "NetGraphTemplate" -> "NetGraphBase" and then declare +// TBD - Rename the above "NetGraphTemplate" -> "NetGraphBase" and then declare // a new "NetGraphTemplate" here (using NetGraphBase) that allows users to // provide their own Node (and Link?) derivatives as well as Cost type -// so that the proper return types are automatically provided from +// so that the proper return types are automatically provided from // Iterators, etc ... need to think about this a little ... i.e. the "Node" -// is not a problem, but the templating of the COST_TYPE member of Link +// is not a problem, but the templating of the COST_TYPE member of Link // is problematic ... A trick might be to have Dijkstra Traversal keep // a Link just for cost storage ... i.e. to contain the templating on // the COST_TYPE contained in the Link?? more thought needed! // And finally, here we use our "NetGraph" base class and "NetGraphTemplate" -// to generate an _example_ (but usable) "ManetGraph" class that uses the +// to generate an _example_ (but usable) "ManetGraph" class that uses the // "NetGraph::SimpleCostDouble" type as its "cost" metric for Dijkstra, etc /** * @class ManetGraph * * @brief Derived from NetGraphTemplate using "SimpleCostDouble" as its COST_TYPE. -* Hopefully a suitable graph structure for keeping and exploring multi-hop network state. +* Hopefully a suitable graph structure for keeping and exploring multi-hop network state. * Supports a notion of multiple interfaces per node, etc. */ @@ -1233,7 +1233,7 @@ class ManetNode; // predeclared so it can be passed to templated ManetInt class ManetLink : public NetGraph::LinkTemplate {}; // Define a ManetInterface type to help "wire up" our example templated ManetGraph below -class ManetInterface : public NetGraph::InterfaceTemplate +class ManetInterface : public NetGraph::InterfaceTemplate { public: ManetInterface(ManetNode& theNode, const ProtoAddress& addr) @@ -1246,7 +1246,7 @@ class ManetInterface : public NetGraph::InterfaceTemplate {}; // Finally, declare a ManetGraph from our NetGraphTemplate -// Note this also creates ManetGraph::Interface and ManetGraph::Link typedef +// Note this also creates ManetGraph::Interface and ManetGraph::Link typedef // equivalents to ManetInterface/ManetLink class ManetGraph : public NetGraphTemplate {}; @@ -1279,7 +1279,7 @@ class ManetGraph : public NetGraphTemplate(adj_iterator.GetNextItem());} - + // @brief Returns next vertice _from_ which there is connection // (note can use Vertice::GetEdgeTo(vertice) to get that edge if desired) Vertice* GetNextConnector(); - + void Reset() { adj_iterator.Reset(); con_iterator.Reset(); } - + private: ProtoSortedTree::Iterator adj_iterator; ProtoSortedTree::Iterator con_iterator; }; // end class ProtoGraph::Vertice::AdjacencyIterator - + /** * @class VerticeQueue * @@ -117,27 +117,27 @@ class ProtoGraph { public: virtual ~VerticeQueue(); - + virtual void Remove(Vertice& vertice) = 0; - + virtual void Empty() = 0; // MUST remove all items from queue - + bool Contains(const Vertice& vertice) {return (NULL != vertice.GetQueueState(*this));} - + class QueueStatePool; /** * @class QueueState * - * @brief The "ProtoGraph::VerticeQueue::QueueState" + * @brief The "ProtoGraph::VerticeQueue::QueueState" * class is a base class that enables - * the "Vertice" class to keep track of the - * VerticeQueues to which it belongs. Additionally, + * the "Vertice" class to keep track of the + * VerticeQueues to which it belongs. Additionally, * those VerticeQueue subclasses can extend - * the VerticeQueue::QueueState class to contain - * additional state that is associated with the + * the VerticeQueue::QueueState class to contain + * additional state that is associated with the * given vertice in the context of that VerticeQueue - */ + */ class QueueState { friend class VerticeQueue; @@ -152,9 +152,9 @@ class ProtoGraph VerticeQueue* GetQueue() const {return queue;} - protected: + protected: QueueState(); - + // IMPORTANT: Any derived QueueState classes MUST call // cleanup in their destructor to avoid possible indirect // calls to virtual functions in the ~QueueState() destructor @@ -164,20 +164,20 @@ class ProtoGraph { vertice = &theVertice; queue = &theQueue; - } + } void Disassociate() { vertice = NULL; queue = NULL; - } + } void SetQueue(VerticeQueue& theQueue) {queue = &theQueue;} - + /** * @class Entry * - * @brief Container used by Vertices to keep + * @brief Container used by Vertices to keep * their lists of VerticeQueueState */ class Entry : public ProtoTree::Item @@ -200,7 +200,7 @@ class ProtoGraph const VerticeQueue** GetQueueHandle() const {return ((const VerticeQueue**)&queue);} - + private: Vertice* vertice; VerticeQueue* queue; // "parent" VerticeQueue @@ -214,7 +214,7 @@ class ProtoGraph * should ony be used to cache a single (i.e. homogeneous) type * of QueueState (i.e. QueueState subclass) otherwise one * may not "Get()" what one expects from the pool! - */ + */ class QueueStatePool : public ProtoTree::ItemPool { public: @@ -236,7 +236,7 @@ class ProtoGraph protected: VerticeQueue(); - + void TransferQueueState(QueueState& queueState, VerticeQueue& dstQueue) { Vertice* vertice = queueState.GetVertice(); @@ -244,18 +244,18 @@ class ProtoGraph vertice->Dereference(queueState); queueState.SetQueue(dstQueue); vertice->Reference(queueState); - } - + } + QueueState* GetQueueState(const Vertice& vertice) const {return vertice.GetQueueState(*this);} - + void Associate(Vertice& vertice, QueueState& queueState); void Disassociate(Vertice& vertice, QueueState& queueState); - + }; // end class VerticeQueue - - - class EdgePool; + + + class EdgePool; /** * @class AdjacencyQueue * @@ -267,29 +267,29 @@ class ProtoGraph friend class Vertice; friend class Edge; friend class AdjacencyIterator; - + protected: AdjacencyQueue(Vertice& srcVertice); virtual ~AdjacencyQueue(); // Connect to "dstVertice" with "edge" - void Connect(Vertice& dstVertice, + void Connect(Vertice& dstVertice, Edge& edge); // Same as connect but doesn't call OnConnect - void Reconnect(Vertice& dstVertice, + void Reconnect(Vertice& dstVertice, Edge& edge); - + // Remove all edges to "dstVertice" - void Disconnect(Vertice& dstVertice, + void Disconnect(Vertice& dstVertice, EdgePool* edgePool = NULL); // Remove a specific edge (and pool or delete it) - void RemoveEdge(Vertice& dstVertice, - Edge& edge, + void RemoveEdge(Vertice& dstVertice, + Edge& edge, EdgePool* edgePool = NULL); - + // Remove a specific edge (but don't delete it) - void SuspendEdge(Vertice& dstVertice, + void SuspendEdge(Vertice& dstVertice, Edge& edge); Vertice& GetSrc() const @@ -297,30 +297,30 @@ class ProtoGraph // Note this count currently only reflects edges _to_ other Vertices unsigned int GetCount() const - {return adjacency_count;} - + {return adjacency_count;} + // Methods used to manage connector_tree // TBD - keep a "connector_count" ??? void AddConnector(Edge& edge); void RemoveConnector(Edge& edge); - + private: void Remove(Vertice& dstVertice) {Disconnect(dstVertice, NULL);} - + void Empty(); Vertice& src_vertice; ProtoSortedTree adjacency_tree; // list of dst vertices I am connected _to_ - unsigned int adjacency_count; + unsigned int adjacency_count; ProtoSortedTree connector_tree; // sorted list edges connected _to_ me }; // end class ProtoGraph::AdjacencyQueue - - - /** + + + /** * @class ProtoGraph::Edge - * + * * @brief The ProtoGraph::Edge inherits from "VerticeQueue::QueueState" so * for the Edge's src Vertice "adjacency_queue" that derives from VerticeQueue. * It inherits from ProtoSortedTree::Item since the AdjacencyQueue is implemented @@ -334,38 +334,38 @@ class ProtoGraph { friend class AdjacencyQueue; friend class AdjacencyIterator; - + public: Edge(); - + virtual ~Edge(); - + virtual void OnConnect(); virtual void OnDisconnect(); Vertice* GetDst() const {return GetVertice();} - + Vertice* GetSrc() const; - + // Subclasses should override these to provide - // a sorting criteria (if desired) for the + // a sorting criteria (if desired) for the // "AdjacencyQueue" defined above virtual const char* GetKey() const; - virtual unsigned int GetKeysize() const; + virtual unsigned int GetKeysize() const; virtual ProtoTree::Endian GetEndian() const; virtual bool UseSignBit() const; virtual bool UseComplement2() const; - + private: class Tracker : public ProtoSortedTree::Item { public: Tracker(const Edge& edge); - + const Edge& GetEdge() const {return edge;} - + private: virtual const char* GetKey() const {return edge.GetKey();} @@ -381,34 +381,34 @@ class ProtoGraph const Edge& edge; }; // end class ProtoGraph::Edge::Tracker - + // Only the AdjacencyQueue should invoke this method. - Tracker& AccessTracker() - {return tracker;} - + Tracker& AccessTracker() + {return tracker;} + Tracker tracker; // used by dst vertices to "track" edges _from_ src vertices // (Whenever an Edge is added to a src vertice "adjacency_queue", - // the Edge::tracker is added to the dst vertice + // the Edge::tracker is added to the dst vertice // "adjacency_queue::connector_tree" - + }; // end class ProtoGraph::Edge - + class EdgePool : public VerticeQueue::QueueStatePool { public: EdgePool(); virtual ~EdgePool(); - + Edge* GetEdge() - {return static_cast(VerticeQueue::QueueStatePool::Get());} - + {return static_cast(VerticeQueue::QueueStatePool::Get());} + void PutEdge(Edge& edge) - {VerticeQueue::QueueStatePool::Put(edge);} - + {VerticeQueue::QueueStatePool::Put(edge);} + }; // end class ProtoGraph::EdgePool - - - /** + + + /** * @class Vertice * */ @@ -416,10 +416,10 @@ class ProtoGraph { friend class ProtoGraph; friend class VerticeQueue; - + public: - virtual ~Vertice(); - + virtual ~Vertice(); + // Subclasses _may_ want to override these methods // (These are used for default sorting of // of the Vertice::SortedList if used) @@ -432,56 +432,56 @@ class ProtoGraph virtual ProtoTree::Endian GetVerticeKeyEndian() const; virtual bool GetVerticeKeySigned() const; virtual bool GetVerticeKeyComplement2() const; - + void Cleanup(); // see comment immediately above - + bool IsInQueue(const VerticeQueue& queue) const {return (NULL != GetQueueState(queue));} - + // This tests for "this" _to_ "dst" connection (unidirectional check) bool HasEdgeTo(const Vertice& dst) const {return dst.IsInQueue(adjacency_queue);} - + Edge* GetEdgeTo(const Vertice& dst) const {return static_cast(dst.GetQueueState(adjacency_queue));} - + unsigned int GetAdjacencyCount() const {return adjacency_queue.GetCount();} - - /** + + /** * @class ProtoGraph::Vertice::SimpleList * - * @brief Simple unsorted, doubly linked-list class used for + * @brief Simple unsorted, doubly linked-list class used for * traversals and other purposes */ class SimpleList : public VerticeQueue { public: class ItemPool; - + SimpleList(SimpleList::ItemPool* itemPool = NULL); virtual ~SimpleList(); - + // required override virtual void Remove(Vertice& vertice); - + bool Prepend(Vertice& vertice); bool Append(Vertice& vertice); - + bool IsEmpty() const {return (NULL == head);} - + // Note "Empty()" does not delete Vertices, but does // delete or pool the queue state "Items" void Empty(); - + Vertice* GetHead() const {return ((NULL != head) ? head->GetVertice() : NULL);} - + Vertice* RemoveHead(); - + class Iterator; - + /** * @class ProtoGraph::Vertice::SimpleList::Item * @@ -491,27 +491,27 @@ class ProtoGraph friend class SimpleList; friend class ItemPool; friend class Iterator; - + public: Item(); virtual ~Item(); - + protected: - void Prepend(Item* theItem) + void Prepend(Item* theItem) {prev = theItem;} - void Append(Item* theItem) + void Append(Item* theItem) {next = theItem;} - - Item* GetPrev() const + + Item* GetPrev() const {return prev;} Item* GetNext() const {return next;} private: - Item* prev; + Item* prev; Item* next; }; // end class ProtoGraph::Vertice::SimpleList::Item - + // Move vertice from this SimpleList to another void TransferVertice(Vertice& vertice, SimpleList& dstSimpleList) { @@ -519,7 +519,7 @@ class ProtoGraph ASSERT(NULL != item); TransferItem(*item, dstSimpleList); } - + void TransferItem(Item& item, SimpleList& dstSimpleList) { Vertice* vertice = item.GetVertice(); @@ -528,7 +528,7 @@ class ProtoGraph TransferQueueState(item, dstSimpleList); dstSimpleList.AppendItem(item); } - + /** * @class ProtoGraph::Vertice::SimpleList::ItemPool * @@ -539,14 +539,14 @@ class ProtoGraph public: ItemPool(); virtual ~ItemPool(); - + Item* GetItem(); - + void PutItem(Item& item) {VerticeQueue::QueueStatePool::Put(item);} - + }; // end class ProtoGraph::Vertice::SimpleList::ItemPool - + /** * @class ProtoGraph::Vertice::SimpleList::Iterator */ @@ -558,7 +558,7 @@ class ProtoGraph void Reset(); Vertice* GetNextVertice(); - + private: const SimpleList& list; Item* next_item; @@ -573,60 +573,60 @@ class ProtoGraph void AppendItem(Item& item); void PrependItem(Item& item); void RemoveItem(Item& item); - + Item* head; Item* tail; ItemPool* item_pool; - + }; // end class ProtoGraph::Vertice::SimpleList() - - + + /** * @class SortedList * - * @brief This maintains a list of Vertices, + * @brief This maintains a list of Vertices, * sorted by their "key", whatever that happens to be ... */ class SortedList : public VerticeQueue { public: class ItemPool; - + SortedList(ItemPool* itemPool = NULL); virtual ~SortedList(); - + // required override virtual void Remove(Vertice& vertice); - + bool Insert(Vertice& vertice); - + Vertice* FindVertice(const char* key, unsigned int keysize) const { Item* item = static_cast(sorted_item_tree.Find(key, keysize)); return (NULL != item) ? item->GetVertice() : NULL; } - + Vertice* GetHead() const { Item* headItem = static_cast(sorted_item_tree.GetHead()); return ((NULL != headItem) ? headItem->GetVertice() : NULL); } - + Vertice* RemoveHead(); - + // Only use when you don't want the list sorted! // (you should probably use simple list instead) bool Append(Vertice& vertice); - + bool IsEmpty() const {return sorted_item_tree.IsEmpty();} - + void Empty(); - + /** - * @class ProtoGraph::Vertice::SortedList::Item + * @class ProtoGraph::Vertice::SortedList::Item * - * @brief "Item" is our QueueState subclass + * @brief "Item" is our QueueState subclass * "container" for vertices in the list */ class Item : public VerticeQueue::QueueState, public ProtoSortedTree::Item @@ -634,7 +634,7 @@ class ProtoGraph public: Item(); virtual ~Item(); - + // required (and optional) overrides for ProtoSortedTree::Item // (these default implementations use Vertice::GetVerticeKey(), etc) virtual const char* GetKey() const; @@ -642,8 +642,8 @@ class ProtoGraph virtual ProtoTree::Endian GetEndian() const; virtual bool UseSignBit() const; virtual bool UseComplement2() const; - }; // end class ProtoGraph::Vertice::SortedList::Item - + }; // end class ProtoGraph::Vertice::SortedList::Item + // Move vertice from this SortedList to another void TransferVertice(Vertice& vertice, SortedList& dstList) { @@ -651,7 +651,7 @@ class ProtoGraph ASSERT(NULL != item); TransferItem(*item, dstList); } - + void TransferItem(Item& item, SortedList& dstList) { Vertice* vertice = item.GetVertice(); @@ -660,7 +660,7 @@ class ProtoGraph TransferQueueState(item, dstList); dstList.InsertItem(item); } - + /** * @class ProtoGraph::Vertice::SortedList::ItemPool * @@ -670,14 +670,14 @@ class ProtoGraph public: ItemPool(); virtual ~ItemPool(); - + Item* GetItem(); - + void PutItem(Item& item) {VerticeQueue::QueueStatePool::Put(item);} - - }; // end class ProtoGraph::Vertice::SortedList::ItemPool - + + }; // end class ProtoGraph::Vertice::SortedList::ItemPool + /** * @class ProtoGraph::Vertice::SortedList::Iterator */ @@ -689,7 +689,7 @@ class ProtoGraph Item* GetNextItem() {return static_cast(ProtoSortedTree::Iterator::GetNextItem());} - + Vertice* GetNextVertice() { Item* nextItem = GetNextItem(); @@ -697,7 +697,7 @@ class ProtoGraph } }; // end class ProtoGraph::Vertice::SortedList::Iterator friend class Iterator; - + protected: Item* GetNewItem() {return ((NULL != item_pool) ? item_pool->GetItem() : new Item);} @@ -709,78 +709,78 @@ class ProtoGraph void RemoveItem(Item& item) {sorted_item_tree.Remove(item);} void AppendItem(Item& item) - {sorted_item_tree.Append(item);} - + {sorted_item_tree.Insert(item);} + ProtoSortedTree sorted_item_tree; ItemPool* item_pool; - + }; // end class ProtoGraph::Vertice::SortedList - + friend class AdjacencyQueue; friend class AdjacencyIterator; - + protected: Vertice(); - + // These are used by the friend class ProtoGraph. We keep these // protected since the ProtoGraph instance in which the connections // are made (or removed) maintains the pools of Edge and Connector // instances and public access to these methods could result - // in mismanagement of the pooled items. I.e., the + // in mismanagement of the pooled items. I.e., the // "ProtoGraph::Connect()", "ProtoGraph::Disconnect()", etc // methods MUST be used instead of using these directly. - + // Note here the "edge" is the connection from src->dst while // the "connector" allows dst vertices to know who is connected - // to them. + // to them. void Connect(Vertice& dst, Edge& edge) {adjacency_queue.Connect(dst, edge);} - + void Reconnect(Vertice& dst, Edge& edge) {adjacency_queue.Reconnect(dst, edge);} - + void Disconnect(Vertice& dst, EdgePool* edgePool = NULL) {adjacency_queue.Disconnect(dst, edgePool);} - + void RemoveEdge(Vertice& dst, Edge& edge, EdgePool* edgePool = NULL) {adjacency_queue.RemoveEdge(dst, edge, edgePool);} - + void SuspendEdge(Vertice& dst, Edge& edge) {adjacency_queue.SuspendEdge(dst, edge);} - - private: + + private: // These are called by a connected src Vertice::adjacency_queue // so a dst Vertice can know of connections _to_ itself void AddConnector(Edge& edge) {adjacency_queue.AddConnector(edge);} void RemoveConnector(Edge& edge) {adjacency_queue.RemoveConnector(edge);} - + VerticeQueue::QueueState* GetQueueState(const VerticeQueue& queue) const { const VerticeQueue* ptr = &queue; - VerticeQueue::QueueState::Entry* entry = + VerticeQueue::QueueState::Entry* entry = static_cast(queue_state_tree.Find((const char*)&ptr, sizeof(VerticeQueue*) << 3)); return ((NULL != entry) ? &entry->GetQueueState() : NULL); - } + } void Reference(VerticeQueue::QueueState& queueState) {queue_state_tree.Insert(queueState.AccessEntry());} void Dereference(VerticeQueue::QueueState& queueState) { ASSERT(this == queueState.GetVertice()); queue_state_tree.Remove(queueState.AccessEntry()); - } + } - // Queue of adjacent vertices + // Queue of adjacent vertices // (uses "Edge" for queue state) AdjacencyQueue adjacency_queue; - - // These members are for use by traversals and + + // These members are for use by traversals and // other queue manipulations as needed ProtoTree queue_state_tree; - + }; // end class ProtoGraph::Vertice - + /** * @class ProtoGraph::VerticeIterator */ @@ -793,28 +793,28 @@ class ProtoGraph // Note: Inherits the following // void Reset(); // Vertice* GetNextVertice(); - + }; // end class ProtoGraph::VerticeIterator friend class VerticeIterator; - + /** * @class ProtoGraph::SimpleTraversal * * @brief (TBD) We may want to make a separate "Traversal" base class * that SimpleTraversal (and others) derive from so that a - * ProtoGraph can inform associated Traversals if the + * ProtoGraph can inform associated Traversals if the * graph state changes ??? */ class SimpleTraversal { public: - SimpleTraversal(const ProtoGraph& theGraph, + SimpleTraversal(const ProtoGraph& theGraph, Vertice& startVertice, bool depthFirst = false); virtual ~SimpleTraversal(); bool Reset(); Vertice* GetNextVertice(unsigned int* level = NULL); - + // Override this method to filter which edges are included in traversal // (return "false" to disallow specific edges) // (Note that "edge->GetDst()" can be used to get the dst vertice) @@ -828,11 +828,11 @@ class ProtoGraph bool depth_first; // false == breadth-first search unsigned int current_level; Vertice* trans_vertice; // level transition marker - Vertice::SimpleList queue_pending; - Vertice::SimpleList queue_visited; - + Vertice::SimpleList queue_pending; + Vertice::SimpleList queue_visited; + Vertice::SimpleList::ItemPool item_pool; - + }; // end class ProtoGraph::SimpleTraversal protected: @@ -844,24 +844,24 @@ class ProtoGraph Edge* GetEdge(); void PutEdge(Edge& edge) {edge_pool.Put(edge);} - + // These let ProtoGraph subclasses control Connect() a little more specifically if desired void Connect(Vertice& src, Vertice& dst, Edge& edge) {src.Connect(dst, edge);} - + void RemoveEdge(Vertice& src, Vertice& dst, Edge& edge) {src.RemoveEdge(dst, edge, &edge_pool);} - + void SuspendEdge(Vertice& src, Vertice& dst, Edge& edge) {src.SuspendEdge(dst, edge);} - + // Member variables Vertice::SortedList vertice_list; - + // Pools of vertice items and edges - Vertice::SortedList::ItemPool vertice_list_item_pool; + Vertice::SortedList::ItemPool vertice_list_item_pool; EdgePool edge_pool; - + }; // end class ProtoGraph #endif // _PROTO_GRAPH diff --git a/include/protoList.h b/include/protoList.h index c5f7aa3..cb51b14 100755 --- a/include/protoList.h +++ b/include/protoList.h @@ -6,9 +6,9 @@ * * @brief The ProtoList class provides a simple double linked-list * class with a "ProtoList::Item" base class to use for -* deriving your own classes you wish to store in a -* ProtoList. -* +* deriving your own classes you wish to store in a +* ProtoList. +* * Note the "ProtoQueue" classes provide some more sophisticated * options like items that can be listed in multiple lists and * automated removal from the multiple lists upon deletion, etc @@ -32,45 +32,45 @@ class ProtoIterable virtual ~ProtoIterable(); protected: ProtoIterable(); - + class Item {}; - + class Iterator { public: virtual ~Iterator(); enum Action {REMOVE, PREPEND, APPEND, INSERT, EMPTY}; - + bool IsValid() const {return (NULL != iterable);} - + protected: Iterator(ProtoIterable& theIterable); - + // Typical list, etc data structure operations virtual void Update(Item* theItem, Action theAction) = 0; - + friend class ProtoIterable; - + ProtoIterable* iterable; - + private: Iterator* ilist_prev; Iterator* ilist_next; }; // end class ProtoIterable::Iterator - + // Derived classes should call this method upon list, etc modification // actions (i.e. REMOVE, PREPEND, APPEND, INSERT). The associated // iterators' "Update()" methods will be invoked accordingly. - void UpdateIterators(Item* theItem, Iterator::Action theAction) const; - + void UpdateIterators(Item* theItem, Iterator::Action theAction) const; + private: friend class Iterator; void AddIterator(Iterator& iterator); void RemoveIterator(Iterator& iterator); - - Iterator* iterator_list_head; - + + Iterator* iterator_list_head; + }; // end class ProtoIterable /** @@ -87,60 +87,60 @@ class ProtoList : private ProtoIterable public: ProtoList(); ~ProtoList(); - + class Item; void Prepend(Item& item); void Append(Item& item); - + // This inserts "theItem" _before_ the "nextItem" void Insert(Item& theItem, Item& nextItem); - + // This inserts "theItem" _before_ the "nextItem" void InsertAfter(Item& theItem, Item& prevItem); - + void Remove(Item& item); - + void Empty(); // empties list without deleting items - + void Destroy(); // deletes contents - + bool IsEmpty() const {return (NULL == head);} - + Item* GetHead() const {return head;} Item* GetTail() const - {return tail;} - + {return tail;} + Item* RemoveHead(); Item* RemoveTail(); - + class Iterator; friend class Iterator; class ItemPool; /** * @class ProtoList::Item * - * @brief Base class to use for deriving your own classes you wish to store in a - * ProtoList. + * @brief Base class to use for deriving your own classes you wish to store in a + * ProtoList. */ class Item : public ProtoIterable::Item { public: virtual ~Item(); - + const Item* GetNext() const {return plist_next;} const Item* GetPrev() const {return plist_prev;} - + protected: Item(); - + private: Item* plist_prev; Item* plist_next; - + friend class ProtoList; friend class Iterator; friend class ItemPool; @@ -156,81 +156,81 @@ class ProtoList : private ProtoIterable public: Iterator(ProtoList& theList, bool reverse = false); ~Iterator(); - + bool IsValid() const {return ProtoIterable::Iterator::IsValid();} - + void Reset(bool reverse = false); Item* GetNextItem(); Item* PeekNextItem() const {return item;} Item* GetPrevItem(); Item* PeekPrevItem() const; - + bool SetCursor(Item* cursor) - { + { item = cursor; return true; // note list membership not validated } Item* GetCursor() const {return item;} - + void Reverse(); bool IsReversed() const {return reversed;} - + private: // Required override for ProtoIterable to make sure any // iterators associated with a list are updated upon // Item addition or removal. void Update(ProtoIterable::Item* theItem, Action theAction); - + Item* item; bool reversed; - + }; // end class ProtoList::Iterator - + class ItemPool { friend class ProtoList; public: ItemPool(); ~ItemPool(); - + bool IsEmpty() const {return (NULL == head);} - + Item* Get(); void Put(Item& item); - + void Destroy(); - + private: Item* head; }; // end class ProtoList::ItemPool - + // Transfers list contents directly to pool // using existing linking void EmptyToPool(ItemPool& pool); - + // Generally, a ProtoList::Iterator should be // used instead of these Item* GetNextItem(Item& item) {return item.plist_next;} Item* GetPrevItem(Item& item) {return item.plist_prev;} - + private: Item* head; Item* tail; - + }; // end class ProtoList /** * @class ProtoListTemplate * * @brief The ProtoListTemplate definition lets you create new list variants that -* are type checked at compile time, etc. +* are type checked at compile time, etc. * * Note the "ITEM_TYPE" _must_ * be a class that is derived from "ProtoList::Item" @@ -241,8 +241,8 @@ class ProtoListTemplate : public ProtoList { public: ProtoListTemplate() {} - virtual ~ProtoListTemplate() {} - + virtual ~ProtoListTemplate() {} + ITEM_TYPE* GetHead() const {return static_cast(ProtoList::GetHead());} ITEM_TYPE* GetTail() const @@ -251,14 +251,19 @@ class ProtoListTemplate : public ProtoList {return static_cast(ProtoList::RemoveHead());} ITEM_TYPE* RemoveTail() {return static_cast(ProtoList::RemoveTail());} - + + ITEM_TYPE* GetNextItem(ITEM_TYPE& item) + {return static_cast(ProtoList::GetNextItem(item));} + ITEM_TYPE* GetPrevItem(ITEM_TYPE& item) + {return static_cast(ProtoList::GetNextItem(item));} + class Iterator : public ProtoList::Iterator { public: Iterator(ProtoListTemplate& theList, bool reverse = false) : ProtoList::Iterator(theList, reverse) {} ~Iterator() {} - + void Reset(bool reverse = false) {ProtoList::Iterator::Reset(reverse);} ITEM_TYPE* GetNextItem() @@ -271,32 +276,32 @@ class ProtoListTemplate : public ProtoList {return static_cast(ProtoList::Iterator::PeekPrevItem());} }; // end class ProtoListTemplate::Iterator - + class ItemPool : public ProtoList::ItemPool { public: ItemPool() {} ~ItemPool() {} - + void Put(ITEM_TYPE& item) {ProtoList::ItemPool::Put(item);} ITEM_TYPE* Get() {return static_cast(ProtoList::ItemPool::Get());} }; // end class ProtoListTemplate::ItemPool - + }; // end ProtoListTemplate /****** - * An example of how to use the ProtoListTemplate with + * An example of how to use the ProtoListTemplate with * your own type derived *from ProtoList::Item". * * Note that "ProtoList" itself may be used directly to do the same * thing, but using the template will save you some "static_casts", etc - * for item retrieval, list iteration, etc and may have some other + * for item retrieval, list iteration, etc and may have some other * benefits. - - + + class MyItem : public ProtoList::Item { public: @@ -317,12 +322,12 @@ itemList.Append(item2); MyItem* headItem = itemList.GetHead(); ... - + ************************************/ - + /** * @class ProtoStack -* +* * @brief The ProtoStack class is like the ProtoList and similarly provides a * ProtoStackTemplate that can be used for deriving easier-to- * use variants for custom items sub-classed from the ProtoStack::Item. @@ -339,20 +344,20 @@ class ProtoStack public: ProtoStack(); ~ProtoStack(); - + class Item; - + // These methods manipulate the ProtoStack as a "stack" void Push(Item& item); // prepend item to list head Item* Pop(); // removes/returns list head Item* Peek() const {return head;} - + // These methods manipulate the ProtoStack as a "FIFO" void Put(Item& item); // append item to list tail Item* Get() // remove/returns list head {return Pop();} - + bool IsEmpty() const {return (NULL == head);} Item* GetHead() const @@ -360,26 +365,26 @@ class ProtoStack Item* GetTail() const {return tail;} void Destroy(); - + class Iterator; friend class Iterator; - /** + /** * @class ProtoStack::Item * - * @brief Base class to use for deriving your own classes you wish to store in a + * @brief Base class to use for deriving your own classes you wish to store in a * ProtoStack. */ class Item { public: virtual ~Item(); - + protected: Item(); - + private: Item* pstack_next; - + friend class ProtoStack; friend class Iterator; }; // end class ProtoStack::Item() @@ -393,23 +398,23 @@ class ProtoStack public: Iterator(const ProtoStack& theStack); ~Iterator(); - + void Reset() {next = stack.head;} - + Item* GetNextItem(); Item* PeekNextItem() const {return next;} - + private: const ProtoStack& stack; Item* next; }; // end class ProtoStack::Iterator - + private: Item* head; Item* tail; - + }; // end class ProtoStack /** @@ -426,8 +431,8 @@ class ProtoStackTemplate : public ProtoStack { public: ProtoStackTemplate() {} - virtual ~ProtoStackTemplate() {} - + virtual ~ProtoStackTemplate() {} + void Push(ITEM_TYPE& item) {ProtoStack::Push(item);} ITEM_TYPE* Pop() @@ -440,14 +445,14 @@ class ProtoStackTemplate : public ProtoStack {return static_cast(ProtoStack::GetHead());} ITEM_TYPE* GetTail() const {return static_cast(ProtoStack::GetTail());} - + class Iterator : public ProtoStack::Iterator { public: Iterator(const ProtoStackTemplate& theList, bool reverse = false) : ProtoStack::Iterator(theList) {} ~Iterator() {} - + void Reset() {ProtoStack::Iterator::Reset();} ITEM_TYPE* GetNextItem() @@ -456,7 +461,7 @@ class ProtoStackTemplate : public ProtoStack {return static_cast(ProtoStack::Iterator::PeekNextItem());} }; // end class ProtoStackTemplate::Iterator - + }; // end ProtoStackTemplate #endif // _PROTO_LIST diff --git a/include/protoTree.h b/include/protoTree.h index eab5471..226b789 100755 --- a/include/protoTree.h +++ b/include/protoTree.h @@ -1,29 +1,29 @@ /********************************************************************* * * AUTHORIZATION TO USE AND DISTRIBUTE - * + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that: + * modification, are permitted provided that: + * + * (1) source code distributions retain this paragraph in its entirety, * - * (1) source code distributions retain this paragraph in its entirety, - * * (2) distributions including binary code include this paragraph in - * its entirety in the documentation or other materials provided - * with the distribution, and + * its entirety in the documentation or other materials provided + * with the distribution, and * - * (3) all advertising materials mentioning features or use of this + * (3) all advertising materials mentioning features or use of this * software display the following acknowledgment: - * - * "This product includes software written and developed - * by Brian Adamson of the Naval Research Laboratory (NRL)." - * - * The name of NRL, the name(s) of NRL employee(s), or any entity + * + * "This product includes software written and developed + * by Brian Adamson of the Naval Research Laboratory (NRL)." + * + * The name of NRL, the name(s) of NRL employee(s), or any entity * of the United States Government may not be used to endorse or - * promote products derived from this software, nor does the + * promote products derived from this software, nor does the * inclusion of the NRL written and developed software directly or * indirectly suggest NRL or United States Government endorsement * of this product. - * + * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. @@ -32,7 +32,7 @@ #ifndef _PROTO_TREE #define _PROTO_TREE -#include "protoList.h" // for ProtoIterable base class +#include "protoList.h" // for ProtoIterable base class #include #ifndef _WIN32_WCE @@ -44,9 +44,9 @@ /** * @class ProtoTree * - * @brief This is a general purpose prefix-based - * C++ Patricia tree. The code also provides - * an ability to iterate over items with a + * @brief This is a general purpose prefix-based + * C++ Patricia tree. The code also provides + * an ability to iterate over items with a * common prefix of arbitrary bit length. * * The class ProtoTree provides a relatively @@ -62,73 +62,76 @@ * unique. However, ProtoSortedTree (see below) * allows multiple items with the same key to be * inserted into it. Arbitrary length strings - * can be easily indexed. + * can be easily indexed. * * ProtoTree supports the notion of big * or little endian byte order of the Item * keys (Note however it is still a prefix * tree, regardless of the "endian"). This * is useful for "ProtoSortedTree::Item" - * subclasses that may wish to have the ordering + * subclasses that may wish to have the ordering * based on a key that is a data type ordered - * according to the machine endian (e.g., + * according to the machine endian (e.g., * integers, IEEE doubles, etc). * Big Endian is default. * */ - + class ProtoTree : public ProtoIterable { public: ProtoTree(); virtual ~ProtoTree(); - + bool IsEmpty() const {return (NULL == root);} - + // "Empty()" doesn't delete the items, just removes them all from the tree void Empty(); - + // "Destroy()" deletes any items in the tree void Destroy(); - + class Item; - + // Insert the "item" into the tree (will fail if item with equivalent key already in tree) - bool Insert(Item& item); - + bool Insert(Item& item, Item* match = NULL); + // Remove the "item" from the tree - void Remove(Item& item); - + void Remove(Item& item); + // This should be implemented as shown here. I commented it out - // to detect if anything was using its old, incorrect implementation + // to detect if anything was using its old, incorrect implementation //bool Contains(const Item& item) const // {return (&item == Find(item.GetKey(), item.GetKeysize()));} - + // Find item with exact match to "key" and "keysize" (keysize is in bits) ProtoTree::Item* Find(const char* key, unsigned int keysize) const; - + ProtoTree::Item* FindString(const char* keyString) const {return Find(keyString, (unsigned int)(8*strlen(keyString)));} - + // Find shortest item to which 'key' is a prefix, or secondly the item that // is the largest prefix of 'key' (i.e. the closet prefix match) - ProtoTree::Item* FindClosestMatch(const char* key, unsigned int keysize) const; - + Item* FindClosestMatch(const char* key, unsigned int keysize) const; + Item* FindBound(const char* key, unsigned int keysize, bool reverse) const; + Item* FindLexicalPredecessor(Item* item) const; + Item* FindLexicalSuccessor(Item* item) const; + // Find item which is largest prefix of the "key" (keysize is in bits) ProtoTree::Item* FindPrefix(const char* key, unsigned int keysize) const; - + ProtoTree::Item* GetRoot() const {return root;} ProtoTree::Item* GetFirstItem() const; ProtoTree::Item* GetLastItem() const; - + ProtoTree::Item* RemoveRoot(); - + class Iterator; class ItemPool; - + enum Endian {ENDIAN_BIG, ENDIAN_LITTLE}; - + // Helper static function to get "native" (hardware) endian static ProtoTree::Endian GetNativeEndian() { @@ -136,30 +139,30 @@ class ProtoTree : public ProtoIterable return ProtoTree::ENDIAN_LITTLE; #else return ProtoTree::ENDIAN_BIG; -#endif // end if/else (BYTE_ORDER == LITTLE_ENDIAN) +#endif // end if/else (BYTE_ORDER == LITTLE_ENDIAN) } // end ProtoTree::GetNativeEndian() - + /** * @class Item * - * @brief ProtoTree::Item provides a base class - * for items to be stored in the tree. + * @brief ProtoTree::Item provides a base class + * for items to be stored in the tree. */ class Item : public ProtoIterable::Item { friend class ProtoTree; friend class Iterator; friend class ItemPool; - - public: + + public: Item(); virtual ~Item(); - + // Required overrides virtual const char* GetKey() const = 0; virtual unsigned int GetKeysize() const = 0; - - // Optional overrides + + // Optional overrides // TBD - make the GetEndian() member of ProtoTree instead // i.e., just like UseSignBit() and UseComplementTwo() #ifdef WIN32 @@ -172,7 +175,7 @@ class ProtoTree : public ProtoIterable #endif // Returns how deep in its tree this Item lies unsigned int GetDepth() const; - + // Debug helper for keys that are strings const char* GetKeyText() const { @@ -187,28 +190,28 @@ class ProtoTree : public ProtoIterable text[tlen] = '\0'; return text; } - - protected: + + protected: Item* GetParent() const {return parent;} Item* GetLeft() const {return left;} Item* GetRight() const {return right;} unsigned int GetBit() {return bit;} - + // bitwise comparison of the two keys bool IsEqual(const char* theKey, unsigned int theKeysize) const; bool PrefixIsEqual(const char* prefix, unsigned int prefixSize) const; - + // Methods for item pooling (accessed by class ItemPool) void SetPoolNext(Item* poolNext) {right = poolNext;} Item* GetPoolNext() const {return right;} - + unsigned int bit; Item* parent; Item* left; Item* right; - + }; // end class ProtoTree::Item - + /** * @class ItemPool * @@ -224,14 +227,14 @@ class ProtoTree : public ProtoIterable void Destroy(); bool IsEmpty() const {return (NULL == head);} - + Item* Get(); - + void Put(Item& item); - + private: Item* head; - + }; // end class ProtoTree::ItemPool /** @@ -245,41 +248,39 @@ class ProtoTree : public ProtoIterable class Iterator : public ProtoIterable::Iterator { public: - Iterator(ProtoTree& tree, + Iterator(ProtoTree& tree, bool reverse = false, Item* cursor = NULL); virtual ~Iterator(); - + void Reset(bool reverse = false, const char* prefix = NULL, unsigned int prefixSize = 0); - + void SetCursor(Item& item); - + Item* GetPrevItem(); Item* PeekPrevItem(); - + Item* GetNextItem(); Item* PeekNextItem(); - - //private: + + protected: // Required override for ProtoIterable to make sure any // iterators associated with a list are updated upon // Item addition or removal. void Update(ProtoIterable::Item* theItem, Action theAction); - + bool reversed; // true if currently iterating backwards - unsigned int prefix_size; // if non-zero, iterating over items of certain prefix + unsigned int prefix_size; // if non-zero, iterating over items of certain prefix Item* prefix_item; // reference item with matching prefix for subtree iteration - Item* prev; + Item* prev; Item* next; Item* curr_hop; - - }; // end class ProtoTree::Iterator + + }; // end class ProtoTree::Iterator friend class Iterator; - - - + /** * @class SimpleIterator * @@ -294,133 +295,161 @@ class ProtoTree : public ProtoIterable public: SimpleIterator(ProtoTree& theTree); virtual ~SimpleIterator(); - + void Reset(); Item* GetNextItem(); - + private: // Required override for ProtoIterable to make sure any // iterators associated with a list are updated upon // Item addition or removal. void Update(ProtoIterable::Item* theItem, Action theAction); - + Item* next; - + }; // end class ProtoTree::SimpleIterator - + static bool Bit(const char* key, unsigned int keysize, unsigned int index, Endian keyEndian); - + static bool ItemIsEqual(const Item& item, const char* key, unsigned int keysize); static bool ItemsAreEqual(const Item& item1, const Item& item2); - + + static int CompareKeys(const char* key1, + unsigned int keysize1, + const char* key2, + unsigned int keysize2, + Endian keyEndian); + + static int CompareKeyToItem(const char* key, + unsigned int keysize, + Endian keyEndian, + const Item& item) + { + return CompareKeys(key, keysize, item.GetKey(), item.GetKeysize(), keyEndian); + } + protected: // This finds the closest matching item with backpointer to "item" ProtoTree::Item* FindPredecessor(ProtoTree::Item& item) const; - + // This finds the root of a subtree of Items matching the given prefix - ProtoTree::Item* FindPrefixSubtree(const char* prefix, + ProtoTree::Item* FindPrefixSubtree(const char* prefix, unsigned int prefixLen) const; - - static bool KeysAreEqual(const char* key1, - const char* key2, + + static bool KeysAreEqual(const char* key1, + const char* key2, unsigned int keysize, Endian keyEndian); - - static bool PrefixIsEqual(const char* key, + + static bool PrefixIsEqual(const char* key, unsigned int keysize, - const char* prefix, + const char* prefix, unsigned int prefixSize, Endian keyEndian); - + + + + private: + static const unsigned char MSB_INDEX[256]; + static unsigned int FindDiffByte(const char* p1, const char* p2, unsigned int len); + static void UpdateDiffBit(const char* p1, const char* p2, unsigned int len, unsigned int& dBit); + // Member variables - Item* root; - + Item* root; + }; // end class ProtoTree -// The ITEM_TYPE here _must_ be something +// The ITEM_TYPE here _must_ be something // subclassed from ProtoTree::Item template class ProtoTreeTemplate : public ProtoTree { public: ProtoTreeTemplate() {} - virtual ~ProtoTreeTemplate() {} - - bool Insert(ITEM_TYPE& item) - {return ProtoTree::Insert(item);} - + virtual ~ProtoTreeTemplate() {} + + bool Insert(ITEM_TYPE& item, ITEM_TYPE* match = NULL) + {return ProtoTree::Insert(item, match);} + void Remove(ITEM_TYPE& item) {ProtoTree::Remove(item);} - + // Find item with exact match to "key" and "keysize" (keysize is in bits) ITEM_TYPE* Find(const char* key, unsigned int keysize) const {return (static_cast(ProtoTree::Find(key, keysize)));} - + ITEM_TYPE* FindString(const char* keyString) const {return (static_cast(ProtoTree::FindString(keyString)));} - + ITEM_TYPE* FindClosestMatch(const char* key, unsigned int keysize) const {return (static_cast(ProtoTree::FindClosestMatch(key, keysize)));} - + // Find item which is largest prefix of the "key" (keysize is in bits) ITEM_TYPE* FindPrefix(const char* key, unsigned int keysize) const {return (static_cast(ProtoTree::FindPrefix(key, keysize)));} - + + ITEM_TYPE* FindBound(const char* key, unsigned int keysize, bool reverse) const + {return (static_cast(ProtoTree::FindBound(key, keysize, reverse)));} + ITEM_TYPE* FindLexicalPredecessor(ITEM_TYPE* item) const + {return (static_cast(ProtoTree::FindLexicalPredecessor(item)));} + ITEM_TYPE* FindLexicalSuccessor(ITEM_TYPE* item) const + {return (static_cast(ProtoTree::FindLexicalSuccessor(item)));} + void Destroy() {ProtoTree::Destroy();} - - + + class Iterator : public ProtoTree::Iterator { public: - Iterator(ProtoTreeTemplate& theTree, + Iterator(ProtoTreeTemplate& theTree, bool reverse = false, Item* cursor = NULL) : ProtoTree::Iterator(theTree, reverse, cursor) {} virtual ~Iterator() {} - + ITEM_TYPE* GetPrevItem() {return static_cast(ProtoTree::Iterator::GetPrevItem());} ITEM_TYPE* PeekPrevItem() {return static_cast(ProtoTree::Iterator::PeekPrevItem());} - + ITEM_TYPE* GetNextItem() {return static_cast(ProtoTree::Iterator::GetNextItem());} ITEM_TYPE* PeekNextItem() {return static_cast(ProtoTree::Iterator::PeekNextItem());} }; // end class ProtoTreeTemplate::Iterator - + class SimpleIterator : public ProtoTree::SimpleIterator { public: SimpleIterator(ProtoTreeTemplate& theTree) : ProtoTree::SimpleIterator(theTree) {} virtual ~SimpleIterator() {} - + ITEM_TYPE* GetNextItem() {return static_cast(ProtoTree::SimpleIterator::GetNextItem());} - + }; // end class ProtoTreeTemplate::SimpleIterator - + class ItemPool : public ProtoTree::ItemPool { public: ItemPool() {} virtual ~ItemPool() {} - + void Put(ITEM_TYPE& item) {ProtoTree::ItemPool::Put(item);} ITEM_TYPE* Get() {return static_cast(ProtoTree::ItemPool::Get());} }; // end class ProtoTreeTemplate::ItemPool - + }; // end class ProtoTreeTemplate -// Example: -/*class ExampleItem : public ProtoTree::Item +// Example: +/*class ExampleItem : public ProtoTree::Item { public: ExampleItem(char* theKey, unsigned int theKeysize, void* theValue): key(theKey), keysize(theKeysize), value(theValue) {} @@ -433,21 +462,23 @@ class ProtoTreeTemplate : public ProtoTree unsigned int keysize; const void * value; }; -class ExampleItemList : public ProtoTreeTemplate {}; +class ExampleItemList : public ProtoTreeTemplate {}; */ + + /** * @class ProtoSortedTree * * @brief This class extends ProtoTree::Item to provide a "threaded" tree * for rapid (linked-list) iteration. Also note that entries with - * duplicate key values are allowed. + * duplicate key values are allowed. * * By default, items are sorted lexically by their key. Optionally the tree may be configured * to treat the first bit of the key as a "sign" bit and order the * sorted list properly with a mix of positive and negative values * using two's complement (e.g. "int") rules or just signed ordering * (e.g. "double"). Note that the key Endian must be set properly - * according to what the key represents. + * according to what the key represents. */ class ProtoSortedTree { @@ -456,10 +487,10 @@ class ProtoSortedTree public: ProtoSortedTree(bool uniqueItemsOnly = false); virtual ~ProtoSortedTree(); - + bool IsEmpty() const {return item_tree.IsEmpty();} - + class Iterator; class ItemPool; class Item : public ProtoTree::Item, public ProtoList::Item @@ -467,15 +498,15 @@ class ProtoSortedTree friend class ProtoSortedTree; friend class Iterator; friend class ItemPool; - + public: Item(); virtual ~Item(); - + // Required overrides virtual const char* GetKey() const = 0; virtual unsigned int GetKeysize() const = 0; - + // TBD - move the Endian, UseComplement2, UseSignBit stuff // _out_ of the ProtoSortedTree::Item and make them // configurable properties of the tree class itself??? @@ -491,29 +522,29 @@ class ProtoSortedTree {return false;} virtual bool UseComplement2() const {return true;} - - private: + + private: // Linked list (threading) helper bool IsInTree() const {return (NULL != left);} }; // end class ProtoSortedTree::Item - + bool Insert(Item& item); - - Item* GetHead() const - {return item_list.GetHead();} + + Item* GetHead() const + {return item_list.GetHead();} Item* RemoveHead() { Item* item = GetHead(); if (NULL != item) Remove(*item); return item; } - Item* GetTail() const + Item* GetTail() const {return item_list.GetTail();} - + Item* GetRoot() const {return static_cast(item_tree.GetRoot());} - + // Random access methods (uses ProtoTree) // Note that since a ProtoSortedTree can have multiple items // with the same key, you should generally use the @@ -522,72 +553,72 @@ class ProtoSortedTree // (i.e., iterate until the next item key doesn't match) Item* Find(const char* key, unsigned int keysize) const {return item_tree.Find(key, keysize);} - + Item* FindString(const char* keyString) const {return Find(keyString, (unsigned int)(8*strlen(keyString)));} - + // Find item which _is_ largest prefix of the "key" (keysize is in bits) Item* FindPrefix(const char* key, unsigned int keysize) const {return item_tree.FindPrefix(key, keysize);} - + void Remove(Item& item); - + //bool Contains(const Item& item) const // {return item_tree.Contains(item);} - + void Empty(); // empties tree without deleting items contained - + void Destroy(); - + // _Unsorted_ Prepend()/Append() methods ("Find()" won't work if used) // Do _not_ mix use of "Insert()" method w/ Prepend()/Append() methods! void Prepend(Item& item); void Append(Item& item); - + protected: - class List : public ProtoListTemplate {}; - + class List : public ProtoListTemplate {}; + public: class Iterator { public: - Iterator(ProtoSortedTree& tree, - bool reverse = false, - const char* keyMin = NULL, + Iterator(ProtoSortedTree& tree, + bool reverse = false, + const char* keyMin = NULL, unsigned int keysize = 0); virtual ~Iterator(); - + bool HasEmptyTree() const {return tree.IsEmpty();} - + // These methods can be used to jog back and forth as desired // (i.e. reversals are automatically managed) Item* GetNextItem() {return list_iterator.GetNextItem();} Item* GetPrevItem() {return list_iterator.GetPrevItem();} - + Item* PeekNextItem() {return list_iterator.PeekNextItem();} Item* PeekPrevItem() {return list_iterator.PeekPrevItem();} - + /// Note if "reverse" is "true", then "keyMin" is really "keyMax" void Reset(bool reverse = false, const char* keyMin = NULL, unsigned int keysize = 0); - + void SetCursor(Item* item) {list_iterator.SetCursor(item);} Item* GetCursor() {return list_iterator.PeekNextItem();} - - // This flips the reversal state, moving + + // This flips the reversal state, moving // cursor forward or backward one item void Reverse() {list_iterator.Reverse();} - + bool IsReversed() const {return list_iterator.IsReversed();} - + private: /** * @class TempItem @@ -600,7 +631,7 @@ class ProtoSortedTree TempItem(const char* theKey, unsigned int theKeysize, ProtoTree::Endian keyEndian); virtual ~TempItem(); - const char* GetKey() const {return key;} + const char* GetKey() const {return key;} unsigned int GetKeysize() const {return keysize;} ProtoTree::Endian GetEndian() const {return key_endian;} @@ -608,25 +639,25 @@ class ProtoSortedTree const char* key; unsigned int keysize; ProtoTree::Endian key_endian; - }; // end class ProtoSortedTree::Iterator::TempItem - + }; // end class ProtoSortedTree::Iterator::TempItem + ProtoSortedTree& tree; - List::Iterator list_iterator; - + List::Iterator list_iterator; + }; // end class ProtoSortedTree::Iterator friend class Iterator; - + /** * @class ItemPool * @brief This is useful for managing a reserved "pool" of Items (containers) */ class ItemPool : public List::ItemPool {}; - + void EmptyToPool(ItemPool& itemPool); - + protected: - class Tree : public ProtoTreeTemplate {}; - + class Tree : public ProtoTreeTemplate {}; + bool unique_items_only; // "false" by default (i.e., allow duplicate keys) Item* positive_min; // Pointer to minimum non-negative entry when useSignBit Tree item_tree; @@ -634,76 +665,82 @@ class ProtoSortedTree }; // end class ProtoSortedTree -// The ITEM_TYPE here _must_ be something +// The ITEM_TYPE here _must_ be something // subclassed from ProtoSortedTree::Item template class ProtoSortedTreeTemplate : public ProtoSortedTree { public: ProtoSortedTreeTemplate() {} - virtual ~ProtoSortedTreeTemplate() {} - + virtual ~ProtoSortedTreeTemplate() {} + // Find item with exact match to "key" and "keysize" ITEM_TYPE* Find(const char* key, unsigned int keysize) const {return (static_cast(ProtoSortedTree::Find(key, keysize)));} - + // Find item which _is_ largest prefix of the "key" (keysize is in bits) ITEM_TYPE* FindPrefix(const char* key, unsigned int keysize) const {return (static_cast(ProtoSortedTree::FindPrefix(key, keysize)));} - + ITEM_TYPE* GetHead() const - {return (static_cast(ProtoSortedTree::GetHead()));} + {return (static_cast(ProtoSortedTree::GetHead()));} ITEM_TYPE* GetTail() const {return (static_cast(ProtoSortedTree::GetTail()));} - ITEM_TYPE* RemoveHead() - {return (static_cast(ProtoSortedTree::RemoveHead()));} - + ITEM_TYPE* RemoveHead() + {return (static_cast(ProtoSortedTree::RemoveHead()));} + class Iterator : public ProtoSortedTree::Iterator { public: - Iterator(ProtoSortedTreeTemplate& theTree, - bool reverse = false, - const char* keyMin = NULL, + Iterator(ProtoSortedTreeTemplate& theTree, + bool reverse = false, + const char* keyMin = NULL, unsigned int keysize = 0) : ProtoSortedTree::Iterator(theTree, reverse, keyMin, keysize) {} virtual ~Iterator() {} - + ITEM_TYPE* GetPrevItem() {return static_cast(ProtoSortedTree::Iterator::GetPrevItem());} ITEM_TYPE* PeekPrevItem() {return static_cast(ProtoSortedTree::Iterator::PeekPrevItem());} - + ITEM_TYPE* GetNextItem() {return static_cast(ProtoSortedTree::Iterator::GetNextItem());} ITEM_TYPE* PeekNextItem() {return static_cast(ProtoSortedTree::Iterator::PeekNextItem());} }; // end class ProtoSortedTreeTemplate::Iterator - + class ItemPool : public ProtoSortedTree::ItemPool { public: ItemPool() {} virtual ~ItemPool() {} - + void Put(ITEM_TYPE& item) {ProtoSortedTree::ItemPool::Put(item);} ITEM_TYPE* Get() {return static_cast(ProtoSortedTree::ItemPool::Get());} }; // end class ProtoSortedTreeTemplate::ItemPool - + }; // end class ProtoSortedTreeTemplate // Here's an example use of ProtoSortedTree configured to keep a table of items indexed -// by a "double" key. Note that multiple equal-valued items _can_ be included in a +// by a "double" key. Note that multiple equal-valued items _can_ be included in a // ProtoSortedTree (the basic ProtoTree only allows a single item with a given key). +// +// IMPORTANT: A special case is that the value of -0.0 isn't lexically compatible with +// some iteration cases. You MUST normalize -0.0 to 0.0 in your double +// floating point keys like shown in the ExampleItem here. + /* + class ExampleItem : public ProtoSortedTree::Item { public: - ExampleItem(double key); - + ExampleItem(double key) : item_key((0.0 == key) ? 0.0 : key) {} + private: const char* GetKey() const {return (char*)&item_key;} @@ -712,13 +749,13 @@ class ExampleItem : public ProtoSortedTree::Item // These configure the key interpretation to properly sort "double" type key values virtual bool UseSignBit() const {return true;} virtual bool UseComplement2() const {return false;} - virtual ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} - + virtual ProtoTree::Endian GetEndian() const {return ProtoTree::GetNativeEndian();} + double item_key; }; // end class ExampleItem class ExampleTree : public ProtoSortedTreeTemplate {}; */ - + #endif // PROTO_TREE diff --git a/src/bsd/bsdNet.cpp b/src/bsd/bsdNet.cpp index a8948e9..8693348 100755 --- a/src/bsd/bsdNet.cpp +++ b/src/bsd/bsdNet.cpp @@ -197,7 +197,7 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, if (0 != sysctl(mib, 6, nullptr, &needed, nullptr, 0) || needed == 0) return; - char* buf = (char*)std::malloc(needed); + void* buf = (char*)std::malloc(needed); if (!buf) return; if (0 != sysctl(mib, 6, buf, &needed, nullptr, 0)) @@ -206,9 +206,9 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, return; } - char* end = buf + needed; + void* end = ((char*)buf) + needed; - for (char* p = buf; p < end; ) + for (void* p = buf; p < end; ) { struct if_msghdr* ifm = (struct if_msghdr*)p; if (ifm->ifm_msglen == 0) break; @@ -216,7 +216,7 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, if (ifm->ifm_type == RTM_IFINFO) { // Followed by sockaddr_dl containing name - char* cp = p + sizeof(struct if_msghdr); + void* cp = ((char*)p) + sizeof(struct if_msghdr); struct sockaddr_dl* sdl = (struct sockaddr_dl*)cp; if (sdl->sdl_family == AF_LINK) @@ -232,7 +232,7 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, bool gotLocal = false; bool gotRemote = false; - char* q = p + ifm->ifm_msglen; + void* q = ((char*)p) + ifm->ifm_msglen; while (q < end) { struct if_msghdr* mh = (struct if_msghdr*)q; @@ -242,7 +242,7 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, if (mh->ifm_type == RTM_NEWADDR) { struct ifa_msghdr* ifam = (struct ifa_msghdr*)q; - char* sa_ptr = q + sizeof(struct ifa_msghdr); + void* sa_ptr = ((char*)q) + sizeof(struct ifa_msghdr); const struct sockaddr* rta[RTAX_MAX]; std::memset(rta, 0, sizeof(rta)); @@ -253,7 +253,7 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, { const struct sockaddr* sa = (const struct sockaddr*)sa_ptr; rta[i] = sa; - sa_ptr += sa_rounded_len(sa); + sa_ptr = ((char*)sa_ptr) + sa_rounded_len(sa); } } @@ -278,13 +278,13 @@ static void TryGetEndpointsBySysctlRoute(const char* ifname, } } - q += mh->ifm_msglen; + q = ((char*)q) + mh->ifm_msglen; } } } } - p += ifm->ifm_msglen; + p = ((char*)p) + ifm->ifm_msglen; } std::free(buf); diff --git a/src/common/protoGraph.cpp b/src/common/protoGraph.cpp index d202674..8f1e239 100755 --- a/src/common/protoGraph.cpp +++ b/src/common/protoGraph.cpp @@ -509,7 +509,7 @@ ProtoGraph::AdjacencyQueue::~AdjacencyQueue() void ProtoGraph::AdjacencyQueue::Empty() { Edge* edge; - while (NULL != (edge = static_cast(adjacency_tree.GetRoot()))) + while (NULL != (edge = static_cast(adjacency_tree.GetHead()))) { Vertice* dst = edge->GetDst(); ASSERT(NULL != dst); diff --git a/src/common/protoSpace.cpp b/src/common/protoSpace.cpp index 971efe5..b7def70 100755 --- a/src/common/protoSpace.cpp +++ b/src/common/protoSpace.cpp @@ -1,6 +1,6 @@ /** * @file protoSpace.cpp -* +* * @brief This maintains a set of "Nodes" in n-dimensional Euclidean space. */ // Uncomment this to have SDT display bounding box iteration @@ -9,7 +9,7 @@ #include "protoDebug.h" #include "protoSpace.h" -#include // for "fabs()" +#include // for "fabs()" #include // for "printf()" ProtoSpace::Node::Node() { @@ -96,7 +96,7 @@ bool ProtoSpace::InsertNode(Node& node) PLOG(PL_ERROR, "ProtoSpace::InsertNode() error: Node dimensions does not match space!\n"); return false; } - + // Get and Insert "Ordinate" entries for the node for each dimension for (unsigned int i = 0; i < num_dimensions; i++) { @@ -190,7 +190,7 @@ bool ProtoSpace::Iterator::Init(const double* originOrdinates) memcpy(orig, originOrdinates, dim*sizeof(double)); else memset(orig, 0, dim*sizeof(double)); - + // Allocate and init positive ordinate iterators if (NULL == (pos_it = new ProtoSortedTree::Iterator*[dim])) { @@ -204,8 +204,8 @@ bool ProtoSpace::Iterator::Init(const double* originOrdinates) for (unsigned int i = 0; i < dim; i++) { tempOrd.SetValue(orig[i]); - if (NULL == (pos_it[i] = new ProtoSortedTree::Iterator(space.ord_tree[i], - false, + if (NULL == (pos_it[i] = new ProtoSortedTree::Iterator(space.ord_tree[i], + false, tempOrd.GetKey(), Ordinate::KEYBITS))) { @@ -213,7 +213,7 @@ bool ProtoSpace::Iterator::Init(const double* originOrdinates) return false; } } - + // Allocate and init negative ordinate iterators if (NULL == (neg_it = new ProtoSortedTree::Iterator*[dim])) { @@ -226,8 +226,8 @@ bool ProtoSpace::Iterator::Init(const double* originOrdinates) for (unsigned int i = 0; i < dim; i++) { tempOrd.SetValue(orig[i]); - if (NULL == (neg_it[i] = new ProtoSortedTree::Iterator(space.ord_tree[i], - false, + if (NULL == (neg_it[i] = new ProtoSortedTree::Iterator(space.ord_tree[i], + false, tempOrd.GetKey(), Ordinate::KEYBITS))) { @@ -248,10 +248,10 @@ bool ProtoSpace::Iterator::Init(const double* originOrdinates) printf("link ur,lr,blue,2\n"); printf("link ll,lr,blue,2\n"); #endif // USE_SDT - + bbox_radius = 0.0; x_factor = sqrt((double)dim); - + return true; } // end ProtoSpace::Iterator::Init() @@ -298,9 +298,9 @@ void ProtoSpace::Iterator::Reset(const double* originOrdinates) for (unsigned int i = 0; i < dim; i++) { tempOrd.SetValue(orig[i]); - pos_it[i]->Reset(false, tempOrd.GetKey(), Ordinate::KEYBITS); - neg_it[i]->Reset(false, tempOrd.GetKey(), Ordinate::KEYBITS); - neg_it[i]->Reverse(); + pos_it[i]->Reset(false, tempOrd.GetKey(), Ordinate::KEYBITS); + neg_it[i]->Reset(false, tempOrd.GetKey(), Ordinate::KEYBITS); + neg_it[i]->Reverse(); } // empty our queue Ordinate* nextOrd; @@ -313,7 +313,7 @@ void ProtoSpace::Iterator::Reset(const double* originOrdinates) * bounding box that meets these criteria * 1) Closest location to , _and_ * 2) Falls within the current bounding box - */ + */ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) { unsigned int dim = space.GetDimensions(); @@ -327,7 +327,7 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) bool inBox = true; if (bbox_radius >= 0.0) { - + // Is the "nextNode" within the bbox*x_factor // (Note "x_factor = radius * sqrt(num_dimensions)) double xRadius = bbox_radius / x_factor; @@ -344,21 +344,21 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) if (inBox) { ord_tree.RemoveHead(); - if (NULL != distance) + if (NULL != distance) { *distance = sqrt(nextOrd->GetValue()); } space.ReturnOrdinateToPool(*nextOrd); return nextNode; } - + } else if (bbox_radius < 0.0) { return NULL; // finished } - - + + // A) Find the ordinate with smallest delta from origin // to set "radius" of current bounding space double deltaMin = -1.0; @@ -386,8 +386,8 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) } } bbox_radius = deltaMin; - if (deltaMin < 0.0) continue; - + if (deltaMin < 0.0) continue; + // Output new bounding box for SDT visualization #ifdef USE_SDT printf("node ul position %f,%f\n", orig[0] - deltaMin, orig[1] - deltaMin); @@ -395,7 +395,7 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) printf("node ll position %f,%f\n", orig[0] - deltaMin, orig[1] + deltaMin); printf("node lr position %f,%f\n", orig[0] + deltaMin, orig[1] + deltaMin); #endif // USE_SDT - + Node* node = neg ? static_cast(neg_it[index]->PeekPrevItem())->GetNode() : static_cast(pos_it[index]->PeekNextItem())->GetNode(); @@ -410,7 +410,7 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) break; } } - + // C) Enqueue any nodes that lie _within_ the current bounding space if (inBox) { @@ -421,8 +421,8 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) double delta = node->GetOrdinate(j) - orig[j]; distPartial += delta*delta; } - - // b) get and init Ordinate + + // b) get and init Ordinate Ordinate* ord = space.GetOrdinateFromPool(); if ((NULL == ord) && (NULL == (ord = new Ordinate))) { @@ -432,26 +432,25 @@ ProtoSpace::Node* ProtoSpace::Iterator::GetNextNode(double* distance) } ord->SetNode(node); ord->SetValue(distPartial); - + // c) if not already enqueued, enqueue it if (NULL == ord_tree.Find(ord->GetKey(), Ordinate::KEYBITS)) ord_tree.Insert(*ord); else space.ReturnOrdinateToPool(*ord); } - + // D) Consume the applicable ordinate, expanding our bounding box if (neg) neg_it[index]->GetPrevItem(); else pos_it[index]->GetNextItem(); -#ifdef USE_SDT +#ifdef USE_SDT printf("wait 1\n"); #endif // USE_SDT - + } // end while(1) - } // end ProtoSpace::Iterator::GetNextNode() diff --git a/src/common/protoTree.cpp b/src/common/protoTree.cpp index 3e6f3c0..261b638 100755 --- a/src/common/protoTree.cpp +++ b/src/common/protoTree.cpp @@ -2,56 +2,57 @@ /********************************************************************* * * AUTHORIZATION TO USE AND DISTRIBUTE - * + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that: + * modification, are permitted provided that: + * + * (1) source code distributions retain this paragraph in its entirety, * - * (1) source code distributions retain this paragraph in its entirety, - * * (2) distributions including binary code include this paragraph in - * its entirety in the documentation or other materials provided - * with the distribution, and + * its entirety in the documentation or other materials provided + * with the distribution, and * - * (3) all advertising materials mentioning features or use of this + * (3) all advertising materials mentioning features or use of this * software display the following acknowledgment: - * - * "This product includes software written and developed - * by Brian Adamson of the Naval Research Laboratory (NRL)." - * + * + * "This product includes software written and developed + * by Brian Adamson of the Naval Research Laboratory (NRL)." + * * The name of NRL, the name(s) of NRL employee(s), or any entity * of the United States Government may not be used to endorse or - * promote products derived from this software, nor does the + * promote products derived from this software, nor does the * inclusion of the NRL written and developed software directly or * indirectly suggest NRL or United States Government endorsement * of this product. - * + * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ********************************************************************/ /** * @file protoTree.cpp -* -* @brief This is a general purpose prefix-based C++ Patricia tree. -* The code also provides an ability to iterate over items with a +* +* @brief This is a general purpose prefix-based C++ Patricia tree. +* The code also provides an ability to iterate over items with a * common prefix of arbitrary bit length */ #include "protoTree.h" #include "protoDebug.h" // for PLOG() +#include "protoAddress.h" #include #include // for labs() ProtoTree::Item::Item() : bit(0), parent((Item*)NULL), left((Item*)NULL), right((Item*)NULL) -{ +{ } ProtoTree::Item::~Item() -{ +{ } -unsigned int ProtoTree::Item::GetDepth() const +unsigned int ProtoTree::Item::GetDepth() const { unsigned int depth = 0; const Item* p = this; @@ -109,13 +110,13 @@ void ProtoTree::Destroy() { Item* item = root; Remove(*item); - delete item; + delete item; } } // end ProtoTree::Destroy() -bool ProtoTree::PrefixIsEqual(const char* key, +bool ProtoTree::PrefixIsEqual(const char* key, unsigned int keysize, - const char* prefix, + const char* prefix, unsigned int prefixSize, Endian keyEndian) { @@ -123,9 +124,9 @@ bool ProtoTree::PrefixIsEqual(const char* key, unsigned int fullByteCount = (prefixSize >> 3); unsigned int remBitCount = prefixSize & 0x07; if (ENDIAN_BIG == keyEndian) - + { - // Compare any "remainder bits" of the "prefix" to the + // Compare any "remainder bits" of the "prefix" to the // corresponding bits of the "key" // (we do this first to possibly avoid call to "memcmp()" below) if (0 != remBitCount) @@ -142,7 +143,7 @@ bool ProtoTree::PrefixIsEqual(const char* key, key += (keysize >> 3); if (0 != (keysize &0x07)) key++; key -= fullByteCount; - // Compare any "remainder bits" of the "prefix" to the + // Compare any "remainder bits" of the "prefix" to the // corresponding bits of the "key" // (we do this first to possibly avoid call to "memcmp()" below) if (0 != remBitCount) @@ -151,7 +152,7 @@ bool ProtoTree::PrefixIsEqual(const char* key, // "remainder bits" are in first byte of little endian "prefix" if ((key[0] & remBitMask) != (prefix[0] & remBitMask)) return false; - + // Compare any full byte portion of the key / prefix if (0 != fullByteCount) return (0 == memcmp(key+1, prefix+1, fullByteCount)); @@ -159,16 +160,16 @@ bool ProtoTree::PrefixIsEqual(const char* key, return true; } } - // Compare any full byte portion of the "prefix" - // to the corresponding "key" bytes + // Compare any full byte portion of the "prefix" + // to the corresponding "key" bytes if (0 != fullByteCount) return (0 == memcmp(key, prefix, fullByteCount)); else return true; } // end ProtoTree::PrefixIsEqual() -bool ProtoTree::KeysAreEqual(const char* key1, - const char* key2, +bool ProtoTree::KeysAreEqual(const char* key1, + const char* key2, unsigned int keysize, Endian keyEndian) { @@ -209,7 +210,7 @@ bool ProtoTree::ItemsAreEqual(const Item& item1, const Item& item2) unsigned int keysize = item1.GetKeysize(); if (item2.GetKeysize() != keysize) return false; Endian keyEndian = item1.GetEndian(); - if (keyEndian != item2.GetEndian()) + if (keyEndian != item2.GetEndian()) { PLOG(PL_WARN, "ProtoTree::ItemsAreEqual() mis-matched key endian?!\n"); ASSERT(0); @@ -224,13 +225,14 @@ bool ProtoTree::ItemIsEqual(const Item& item, const char* key, unsigned int keys return KeysAreEqual(item.GetKey(), key, keysize, item.GetEndian()); } // end ProtoTree::ItemIsEqual() +/* bool ProtoTree::Bit(const char* key, unsigned int keysize, unsigned int index, Endian keyEndian) { if (index < keysize) { unsigned int byteIndex = index >> 3; byteIndex = (ENDIAN_BIG == keyEndian) ? byteIndex : ((keysize - 1) >> 3) - byteIndex; - return (0 != (key[byteIndex] & (0x80 >> (index & 0x07)))); + return (0 != (key[byteIndex] & (0x80 >> (index & 0x07)))); } else if (index < (keysize + (sizeof(keysize) << 3))) { @@ -242,7 +244,28 @@ bool ProtoTree::Bit(const char* key, unsigned int keysize, unsigned int index, E return false; } } // end ProtoTree::Bit() - +*/ + +bool ProtoTree::Bit(const char* key, unsigned int keysize, unsigned int index, Endian keyEndian) +{ + if (index < keysize) + { + unsigned int byteIndex = index >> 3; + byteIndex = (ENDIAN_BIG == keyEndian) ? byteIndex : ((keysize - 1) >> 3) - byteIndex; + return (0 != (key[byteIndex] & (0x80 >> (index & 0x07)))); + } + else if (index == keysize) + { + // explicit end-of-key marker + return true; + } + else + { + // zero padding beyond the terminator + return false; + } +} // end ProtoTree::Bit() + ProtoTree::Item* ProtoTree::GetFirstItem() const { if (NULL != root) @@ -251,11 +274,11 @@ ProtoTree::Item* ProtoTree::GetFirstItem() const { // 2-A) Only one node in this tree return root; - } + } else { // 2-B) Return left most node in this tree - Item* x = (root->left == root) ? root->right : root; + Item* x = (root->left == root) ? root->right : root; while (x->left->parent == x) x = x->left; return (x->left); } @@ -281,10 +304,11 @@ ProtoTree::Item* ProtoTree::GetLastItem() const return NULL; } // end ProtoTree::GetLastItem() -bool ProtoTree::Insert(ProtoTree::Item& item) +/* "legacy" in sertion method before new 32-bit and 64-bit, etc optimizations +bool ProtoTree::Insert(ProtoTree::Item& item) { - // TBD - we could allow for an optional optimization for the the - // "find fail / insert new" use pattern by having an + // TBD - we could allow for an optional optimization for the the + // "find fail / insert new" use pattern by having an // optional parameter to pass in the 'x' (closest match) // pointer here found from the prior ProtoTree::Find() attempt // which does the same "closet match" traversal @@ -302,13 +326,13 @@ bool ProtoTree::Insert(ProtoTree::Item& item) p = x; x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; } while (p == x->parent); - + // 2) Then, find index of first differing bit ("dBit") // (also look out for exact match!) unsigned int dBit = 0; // A) Do byte-wise comparison to extent possible unsigned int keysizeMin, indexMax; - if (keysize < x->GetKeysize()) + if (keysize < x->GetKeysize()) { keysizeMin = keysize; indexMax = x->GetKeysize() + (sizeof(unsigned int) << 3); @@ -350,8 +374,8 @@ bool ProtoTree::Insert(ProtoTree::Item& item) { ptr1--; ptr2--; - } - dBit += 8; + } + dBit += 8; } ASSERT(dBit <= fullByteBits); if (dBit == fullByteBits) @@ -377,7 +401,7 @@ bool ProtoTree::Insert(ProtoTree::Item& item) { p = x; x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; - } while ((x->bit < dBit) && (p == x->parent)); + } while ((x->bit < dBit) && (p == x->parent)); // 4) Insert "item" into tree @@ -390,14 +414,14 @@ bool ProtoTree::Insert(ProtoTree::Item& item) else { item.left = &item; - item.right = x; + item.right = x; } item.parent = p; if (Bit(key, keysize, p->bit, keyEndian)) p->right = &item; - else + else p->left = &item; - if (p == x->parent) + if (p == x->parent) x->parent = &item; } else @@ -410,6 +434,286 @@ bool ProtoTree::Insert(ProtoTree::Item& item) } // Note for ProtoTree, we call UpdateIterators() _after_ // insertion/removal since we just reset the iterators + UpdateIterators(&item, Iterator::INSERT); + return true; +} // end ProtoTree::Insert() [legacy] +*/ + +/* + * ProtoTree::Insert() wide-comparison optimization + * + * We compare equal leading key bytes in larger chunks before falling back + * to byte-at-a-time comparison. When a wide block differs, we resolve the + * differing byte _within that block_ immediately and then use the MSB lookup + * table to locate the differing bit within that byte. + * + * Why only for ENDIAN_BIG? + * ------------------------ + * For ENDIAN_BIG keys, the logical comparison order matches the in-memory + * byte order, so a contiguous 64-bit or 32-bit memcpy/load compares exactly + * the next bytes that the original byte loop would have examined. + * + * For ENDIAN_LITTLE keys, the logical comparison order runs backward through + * memory. The original code handles that cleanly by initializing the byte + * pointers at the end of the key and decrementing them. Wide contiguous + * block compares do _not_ map as directly onto that reverse traversal, so + * we keep the original byte loop for ENDIAN_LITTLE in order to preserve + * simple, obvious correctness. + * + * Why use memcpy()? + * ----------------- + * Small fixed-size memcpy() calls are typically optimized by the compiler + * into efficient loads, while avoiding alignment and aliasing issues that + * direct pointer casts could introduce. + * + * Why resolve the differing byte within the wide block? + * ----------------------------------------------------- + * When a 64-bit or 32-bit block differs, this avoids dropping back to the + * outer byte loop for the bytes in that block. That is a little more code + * than the simpler skip-ahead version, but it is still straightforward and + * keeps the original algorithm structure intact. + */ + +#if defined(UINT32_MAX) +#define PROTO_TREE_USE_32BIT_COMPARE +#endif +#if defined(UINT64_MAX) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || \ + defined(__ppc64__) || defined(__LP64__) || defined(_WIN64)) +#define PROTO_TREE_USE_64BIT_COMPARE +#endif + +// For a non-zero byte value, this gives the bit offset (0..7) +// of the first set bit scanning from MSB to LSB. +// Example: 0x80 -> 0, 0x40 -> 1, 0x20 -> 2, ..., 0x01 -> 7 +const unsigned char ProtoTree::MSB_INDEX[256] = +{ + 0,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +// Return the index of the first differing byte between two buffers. +// Assumes the buffers differ somewhere within the given length. +inline unsigned int ProtoTree::FindDiffByte(const char* p1, + const char* p2, + unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; ++i) + { + if (p1[i] != p2[i]) + break; + } + ASSERT(i < len); + return i; +} // end ProtoTree::FindDiffByte() + +// Update "dBit" given two buffers that differ somewhere within "len" bytes. +inline void ProtoTree::UpdateDiffBit(const char* p1, + const char* p2, + unsigned int len, + unsigned int& dBit) +{ + unsigned int i = FindDiffByte(p1, p2, len); + unsigned char delta = (unsigned char)(p1[i] ^ p2[i]); + ASSERT(0 != delta); + dBit += (i << 3); + dBit += MSB_INDEX[delta]; +} // end ProtoTree::UpdateDiffBit() + + +bool ProtoTree::Insert(ProtoTree::Item& item, Item* match) +{ + if (NULL != root) + { + const char* key = item.GetKey(); + unsigned int keysize = item.GetKeysize(); + Endian keyEndian = item.GetEndian(); + Item* x; + if (NULL == match) + { + // 1) Find closest match to "item" + x = root; + Item* p; + do + { + p = x; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + } while (p == x->parent); + } + else + { + x = match; + } + + // 2) Find index of first differing bit ("dBit") + unsigned int dBit = 0; + + unsigned int xKeysize = x->GetKeysize(); + unsigned int keysizeMin = + (keysize < xKeysize) ? keysize : xKeysize; + unsigned int indexMax = + ((keysize > xKeysize) ? keysize : xKeysize) + 1; // explicit terminator bit + + const char* ptr1 = key; + const char* ptr2 = x->GetKey(); + ASSERT(x->GetEndian() == keyEndian); + + if (ENDIAN_LITTLE == keyEndian) + { + ptr1 += ((keysize - 1) >> 3); + ptr2 += ((xKeysize - 1) >> 3); + } + + unsigned int fullByteBits = keysizeMin & ~0x07; + unsigned int fullByteCount = fullByteBits >> 3; + bool done = false; + + if (ENDIAN_BIG == keyEndian) + { +#ifdef PROTO_TREE_USE_64BIT_COMPARE + while ((!done) && (fullByteCount >= 8)) + { + uint64_t word1; + uint64_t word2; + memcpy(&word1, ptr1, 8); + memcpy(&word2, ptr2, 8); + if (word1 != word2) + { + UpdateDiffBit(ptr1, ptr2, 8, dBit); + done = true; + } + else + { + ptr1 += 8; + ptr2 += 8; + dBit += 64; + fullByteCount -= 8; + } + } +#endif // PROTO_TREE_USE_64BIT_COMPARE + +#ifdef PROTO_TREE_USE_32BIT_COMPARE + while ((!done) && (fullByteCount >= 4)) + { + uint32_t word1; + uint32_t word2; + memcpy(&word1, ptr1, 4); + memcpy(&word2, ptr2, 4); + if (word1 != word2) + { + UpdateDiffBit(ptr1, ptr2, 4, dBit); + done = true; + } + else + { + ptr1 += 4; + ptr2 += 4; + dBit += 32; + fullByteCount -= 4; + } + } +#endif // PROTO_TREE_USE_32BIT_COMPARE + } + + // Compare remaining full bytes one at a time + while ((!done) && (fullByteCount > 0)) + { + if (*ptr1 != *ptr2) + { + unsigned char delta = (unsigned char)(*ptr1 ^ *ptr2); + ASSERT(0 != delta); + dBit += MSB_INDEX[delta]; + done = true; + } + else + { + if (ENDIAN_BIG == keyEndian) + { + ptr1++; + ptr2++; + } + else + { + ptr1--; + ptr2--; + } + dBit += 8; + fullByteCount--; + } + } + + ASSERT(dBit <= fullByteBits); + if (!done) + { + // Compare any remainder bit-by-bit, including the + // explicit end-of-key marker bit at index == keysize. + for (; dBit < indexMax; dBit++) + { + if (Bit(key, keysize, dBit, keyEndian) != + Bit(x->GetKey(), x->GetKeysize(), dBit, keyEndian)) + break; + } + if (dBit == indexMax) + { + PLOG(PL_WARN, "ProtoTree::Insert() Equivalent item already in tree!\n"); + return false; + } + } + item.bit = dBit; + + // 3) Find "item" insertion point + x = root; + Item* p; + do + { + p = x; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + } while ((x->bit < dBit) && (p == x->parent)); + + // 4) Insert "item" into tree + if (Bit(key, keysize, dBit, keyEndian)) + { + ASSERT(NULL != x); + item.left = x; + item.right = &item; + } + else + { + item.left = &item; + item.right = x; + } + item.parent = p; + if (Bit(key, keysize, p->bit, keyEndian)) + p->right = &item; + else + p->left = &item; + if (p == x->parent) + x->parent = &item; + } + else + { + // tree is empty, so make "item" the tree root + root = &item; + item.parent = (Item*)NULL; + item.left = item.right = &item; + item.bit = 0; + } + UpdateIterators(&item, Iterator::INSERT); return true; } // end ProtoTree::Insert() @@ -417,7 +721,7 @@ bool ProtoTree::Insert(ProtoTree::Item& item) // Find node with backpointer to "item" ProtoTree::Item* ProtoTree::FindPredecessor(ProtoTree::Item& item) const { - // Find terminal "q" with backpointer to "item" + // Find terminal "q" with backpointer to "item" Item* x = &item; Item* q; const char* key = item.GetKey(); @@ -434,40 +738,254 @@ ProtoTree::Item* ProtoTree::FindPredecessor(ProtoTree::Item& item) const return q; } // end ProtoTree::FindPredecessor() +// "Unrolled", more efficient versions of above two methods. +// BUT - needs to be tested! +ProtoTree::Item* ProtoTree::FindLexicalPredecessor(Item* item) const +{ + ASSERT(NULL != item); + if (NULL == root) + return NULL; + + Endian keyEndian = item->GetEndian(); + + // Find node "q" with backpointer to "item" + Item* x; + if ((NULL == item->parent) && (item->right == item)) + x = item->left; + else + x = item; + + Item* q; + do + { + q = x; + if (Bit(item->GetKey(), item->GetKeysize(), x->bit, keyEndian)) + x = x->right; + else + x = x->left; + } while (x != item); + + if (q->right != item) + { + // Go up the tree + do + { + x = q; + q = q->parent; + } while ((NULL != q) && (x == q->left)); + + if ((NULL == q) || (NULL == q->parent)) + { + if ((NULL == q) || (q->left == q)) + { + // Bubbled completely up, or root has no left side + return NULL; + } + else + { + // Iterated to root from the right side and root has + // a left side we should check out. + Item* r = q; + x = q->left; + do + { + q = x; + if (Bit(r->GetKey(), r->GetKeysize(), x->bit, keyEndian)) + x = x->right; + else + x = x->left; + } while (x != r); + + if (q->left != q) + { + // Go as far right of q->left as possible + q = q->left; + do + { + x = q; + q = q->right; + } while (x == q->parent); + } + return q; + } + } + } + + if (q->left->parent != q) + { + if ((NULL == q->left->parent) && + (q->left->left != q->left) && + Bit(q->GetKey(), q->GetKeysize(), 0, keyEndian)) + { + // Came from the right and there is a left of root. + // Go as far right of the left of root as possible. + x = q->left->left; + do + { + q = x; + x = x->right; + } while (q == x->parent); + return x; + } + else + { + return q->left; + } + } + else + { + // Go as far right of q->left as possible + x = q->left; + do + { + q = x; + x = x->right; + } while (q == x->parent); + return x; + } +} // end ProtoTree::FindLexicalPredecessor() + + +ProtoTree::Item* ProtoTree::FindLexicalSuccessor(Item* item) const +{ + ASSERT(NULL != item); + if (NULL == root) + return NULL; + + Endian keyEndian = item->GetEndian(); + + // Find node "q" with backpointer to "item" + Item* x; + if ((NULL == item->parent) && (item->left == item)) + x = item->right; + else + x = item; + + Item* q; + do + { + q = x; + if (Bit(item->GetKey(), item->GetKeysize(), x->bit, keyEndian)) + x = x->right; + else + x = x->left; + } while (x != item); + + if (q->left != item) + { + // Go up the tree + do + { + x = q; + q = q->parent; + } while ((NULL != q) && (x == q->right)); + + if ((NULL == q) || (NULL == q->parent)) + { + if ((NULL == q) || (q->right == q)) + { + // Bubbled completely up, or root has no right side + return NULL; + } + else + { + // Iterated to root from the left side and root has + // a right side we should check out. + Item* r = q; + x = q->right; + do + { + q = x; + if (Bit(r->GetKey(), r->GetKeysize(), x->bit, keyEndian)) + x = x->right; + else + x = x->left; + } while (x != r); + + if (q->right != q) + { + // Go as far left of q->right as possible + q = q->right; + do + { + x = q; + q = q->left; + } while (x == q->parent); + } + return q; + } + } + } + + if (q->right->parent != q) + { + if ((NULL == q->right->parent) && + (q->right->right != q->right) && + !Bit(q->GetKey(), q->GetKeysize(), 0, keyEndian)) + { + // Came from the left and there is a right of root. + // Go as far left of the right of root as possible. + x = q->right->right; + do + { + q = x; + x = x->left; + } while (q == x->parent); + return x; + } + else + { + return q->right; + } + } + else + { + // Go as far left of q->right as possible + x = q->right; + do + { + q = x; + x = x->left; + } while (q == x->parent); + return x; + } +} // end ProtoTree::FindLexicalSuccessor() + + void ProtoTree::Remove(ProtoTree::Item& item) { ASSERT(0 != item.GetKeysize()); if (((&item == item.left) || (&item == item.right)) && (NULL != item.parent)) { - // non-root "item" that has at least one self-pointer + // non-root "item" that has at least one self-pointer // (a.k.a an "external entry"?) Item* orphan = (&item == item.left) ? item.right : item.left; if (item.parent->left == &item) item.parent->left = orphan; - else + else item.parent->right = orphan; if (orphan->bit > item.parent->bit) orphan->parent = item.parent; } else { - // Root or "item" with no self-pointers + // Root or "item" with no self-pointers // (a.k.a an "internal entry"?) - // 1) Find terminal "q" with backpointer to "item" + // 1) Find terminal "q" with backpointer to "item" const char* key = item.GetKey(); unsigned int keysize = item.GetKeysize(); Endian keyEndian = item.GetEndian(); Item* x = &item; Item* q; - do - { - q = x; + do + { + q = x; if (Bit(key, keysize, x->bit, keyEndian)) x = x->right; - else - x = x->left; + else + x = x->left; } while (x != &item); - + if (NULL != q->parent) { // Non-root "q", so "q" is moved into the place of "item" @@ -488,10 +1006,10 @@ void ProtoTree::Remove(ProtoTree::Item& item) x = x->left; } while (x != &item); } - + // A) Set bit index of "q" to that of "item" q->bit = item.bit; - + // B) Fix the parent, left, and right node pointers to "q" // (removes "q" from its current place in the tree) Item* parent = q->parent; @@ -503,7 +1021,7 @@ void ProtoTree::Remove(ProtoTree::Item& item) parent->right = child; if (child->bit > parent->bit) child->parent = parent; - + // C) Fix the item's left->parent and right->parent node pointers to "item" // (places "q" into the current place of the "item" in the tree) ASSERT(q != NULL); @@ -515,12 +1033,12 @@ void ProtoTree::Remove(ProtoTree::Item& item) { if (item.parent->left == &item) item.parent->left = q; - else + else item.parent->right = q; } else { - // "item" was root node, so update the "s" node + // "item" was root node, so update the "s" node // backpointer to "q" instead of "item" ASSERT(s != NULL); ASSERT(s != &item); @@ -530,7 +1048,7 @@ void ProtoTree::Remove(ProtoTree::Item& item) s->right = q; root = q; } - + // E) Finally, "q" gets the pointers of the "item" being removed // (which now _may_ include a pointer to itself) if (NULL != item.parent) @@ -546,20 +1064,20 @@ void ProtoTree::Remove(ProtoTree::Item& item) Item* orphan = (q == q->left) ? q->right : q->left; if (q == orphan) { - root = (Item*)NULL; + root = (Item*)NULL; } else { - root = orphan; + root = orphan; orphan->parent = NULL; - if (orphan->left == q) + if (orphan->left == q) orphan->left = orphan; - else + else orphan->right = orphan; orphan->bit = 0; } } - } + } item.parent = item.left = item.right = (Item*)NULL; UpdateIterators(&item, Iterator::REMOVE); } // end ProtoTree::Remove() @@ -575,7 +1093,7 @@ ProtoTree::Item* ProtoTree::RemoveRoot() /** * Find item with exact match to key and keysize */ -ProtoTree::Item* ProtoTree::Find(const char* key, +ProtoTree::Item* ProtoTree::Find(const char* key, unsigned int keysize) const { Item* x = root; @@ -583,13 +1101,13 @@ ProtoTree::Item* ProtoTree::Find(const char* key, { Endian keyEndian = x->GetEndian(); Item* p; - do - { + do + { p = x; - x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; } while (x->parent == p); return (ItemIsEqual(*x, key, keysize) ? x : NULL); - } + } else { return (Item*)NULL; @@ -599,7 +1117,8 @@ ProtoTree::Item* ProtoTree::Find(const char* key, /** * Find item with "closest" match to key and keysize (biggest prefix match?) */ -ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key, +/* +ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key, unsigned int keysize) const { Item* x = root; @@ -607,13 +1126,35 @@ ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key, { Endian keyEndian = x->GetEndian(); Item* p; - do - { + do + { p = x; - x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; } while ((x->parent == p) && (x->bit < keysize)); - return x; - } + return x; + } + else + { + return (Item*)NULL; + } +} // end ProtoTree::FindClosestMatch() +*/ + +ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key, + unsigned int keysize) const +{ + Item* x = root; + if (NULL != x) + { + Endian keyEndian = x->GetEndian(); + Item* p; + do + { + p = x; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + } while (x->parent == p); + return x; + } else { return (Item*)NULL; @@ -623,7 +1164,9 @@ ProtoTree::Item* ProtoTree::FindClosestMatch(const char* key, /** * Finds longest matching entry that is a prefix to "key" */ -ProtoTree::Item* ProtoTree::FindPrefix(const char* key, + +/* +ProtoTree::Item* ProtoTree::FindPrefix(const char* key, unsigned int keysize) const { // (TBD) Retest this code with new "size-agnostic" ProtoTree implementation @@ -632,24 +1175,60 @@ ProtoTree::Item* ProtoTree::FindPrefix(const char* key, { Endian keyEndian = x->GetEndian(); Item* p; - do - { + do + { p = x; - x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; } while ((x->parent == p) && (x->bit < keysize)); - if (PrefixIsEqual(key, keysize, x->GetKey(), x->GetKeysize(), keyEndian)) + if (PrefixIsEqual(key, keysize, x->GetKey(), x->GetKeysize(), keyEndian)) return x; } return NULL; } // end ProtoTree::FindPrefix() +*/ + +ProtoTree::Item* ProtoTree::FindPrefix(const char* key, + unsigned int keysize) const +{ + ProtoAddress addr; + // (TBD) Retest this code with new "size-agnostic" ProtoTree implementation + Item* prefixMatch = NULL; + Item* x = root; + if (NULL != x) + { + Endian keyEndian = x->GetEndian(); + Item* p; + do + { + addr.SetRawHostAddress(ProtoAddress::IPv4, x->GetKey(), 4); + //TRACE(" (FindPrefix iterated to %s) endian:%d\n", addr.GetHostString(), keyEndian); + if (PrefixIsEqual(key, keysize, x->GetKey(), x->GetKeysize(), keyEndian)) + { + if ((NULL == prefixMatch) || (x->GetKeysize() > prefixMatch->GetKeysize())) + prefixMatch = x; + } + p = x; + x = Bit(key, keysize, x->bit, keyEndian) ? x->right : x->left; + } while ((x->parent == p) && (x->bit < keysize)); + addr.SetRawHostAddress(ProtoAddress::IPv4, x->GetKey(), 4); + //TRACE(" (FindPrefix final iteration to %s) endian:%d\n", addr.GetHostString(), keyEndian); + if (PrefixIsEqual(key, keysize, x->GetKey(), x->GetKeysize(), keyEndian)) + { + if ((NULL == prefixMatch) || (x->GetKeysize() > prefixMatch->GetKeysize())) + prefixMatch = x; + } + } + return prefixMatch; +} // end ProtoTree::FindPrefix() /** - * This finds prefix subtree root, (TBD) add find prefix + * This finds prefix subtree root, (TBD) add find prefix * subtree min, and find prefix subtree max methods * (e.g. for "min", first find subtree root, and roll left ???) */ -ProtoTree::Item* ProtoTree::FindPrefixSubtree(const char* prefix, +/* +ProtoTree::Item* ProtoTree::FindPrefixSubtree(const char* prefix, unsigned int prefixSize) const { // (TBD) Retest this code more with new "size-agnostic" ProtoTree implementation @@ -658,17 +1237,187 @@ ProtoTree::Item* ProtoTree::FindPrefixSubtree(const char* prefix, { Endian keyEndian = x->GetEndian(); Item* p; - do - { + do + { p = x; - x = Bit(prefix, prefixSize, x->bit, keyEndian) ? x->right : x->left; + x = Bit(prefix, prefixSize, x->bit, keyEndian) ? x->right : x->left; } while ((x->parent == p) && (x->bit < prefixSize)); - if (PrefixIsEqual(x->GetKey(), x->GetKeysize(), prefix, prefixSize, keyEndian)) + if (PrefixIsEqual(x->GetKey(), x->GetKeysize(), prefix, prefixSize, keyEndian)) return x; } return (Item*)NULL; } // end ProtoTree::FindPrefixSubtree() - +*/ + +ProtoTree::Item* ProtoTree::FindPrefixSubtree(const char* prefix, + unsigned int prefixSize) const +{ + Item* prefixMatch = NULL; + Item* x = root; + if (NULL != x) + { + Endian keyEndian = x->GetEndian(); + Item* p; + do + { + if (PrefixIsEqual(x->GetKey(), x->GetKeysize(), prefix, prefixSize, keyEndian)) + prefixMatch = x; + p = x; + x = Bit(prefix, prefixSize, x->bit, keyEndian) ? x->right : x->left; + } while (x->parent == p); + } + return prefixMatch; +} // end ProtoTree::FindPrefixSubtree() + + + +int ProtoTree::CompareKeys(const char* key1, + unsigned int keysize1, + const char* key2, + unsigned int keysize2, + Endian keyEndian) +{ + unsigned int keysizeMin = + (keysize1 < keysize2) ? keysize1 : keysize2; + + const char* ptr1 = key1; + const char* ptr2 = key2; + + if (ENDIAN_LITTLE == keyEndian) + { + ptr1 += ((keysize1 - 1) >> 3); + ptr2 += ((keysize2 - 1) >> 3); + } + + unsigned int fullByteBits = keysizeMin & ~0x07; + unsigned int fullByteCount = fullByteBits >> 3; + + if (ENDIAN_BIG == keyEndian) + { +#ifdef PROTO_TREE_USE_64BIT_COMPARE + while (fullByteCount >= 8) + { + uint64_t word1; + uint64_t word2; + memcpy(&word1, ptr1, 8); + memcpy(&word2, ptr2, 8); + if (word1 != word2) + { + unsigned int i = FindDiffByte(ptr1, ptr2, 8); + unsigned char b1 = (unsigned char)ptr1[i]; + unsigned char b2 = (unsigned char)ptr2[i]; + return (b1 > b2) ? 1 : -1; + } + ptr1 += 8; + ptr2 += 8; + fullByteCount -= 8; + } +#endif // PROTO_TREE_USE_64BIT_COMPARE + +#ifdef PROTO_TREE_USE_32BIT_COMPARE + while (fullByteCount >= 4) + { + uint32_t word1; + uint32_t word2; + memcpy(&word1, ptr1, 4); + memcpy(&word2, ptr2, 4); + if (word1 != word2) + { + unsigned int i = FindDiffByte(ptr1, ptr2, 4); + unsigned char b1 = (unsigned char)ptr1[i]; + unsigned char b2 = (unsigned char)ptr2[i]; + return (b1 > b2) ? 1 : -1; + } + ptr1 += 4; + ptr2 += 4; + fullByteCount -= 4; + } +#endif // PROTO_TREE_USE_32BIT_COMPARE + } + + while (fullByteCount > 0) + { + unsigned char b1 = (unsigned char)*ptr1; + unsigned char b2 = (unsigned char)*ptr2; + if (b1 != b2) + return (b1 > b2) ? 1 : -1; + + if (ENDIAN_BIG == keyEndian) + { + ptr1++; + ptr2++; + } + else + { + ptr1--; + ptr2--; + } + fullByteCount--; + } + + // Compare any remaining partial-byte bits, then the explicit + // end-of-key marker bit at index == keysize. + unsigned int indexMax = + ((keysize1 > keysize2) ? keysize1 : keysize2) + 1; + + for (unsigned int i = fullByteBits; i < indexMax; i++) + { + bool bit1 = Bit(key1, keysize1, i, keyEndian); + bool bit2 = Bit(key2, keysize2, i, keyEndian); + if (bit1 != bit2) + return bit1 ? 1 : -1; + } + return 0; +} // end ProtoTree::CompareKeys() + +ProtoTree::Item* ProtoTree::FindBound(const char* key, + unsigned int keysize, + bool reverse) const +{ + if (NULL == root) + return NULL; + + Item* match = FindClosestMatch(key, keysize); + if (NULL == match) + return NULL; + + int cmp = CompareKeyToItem(key, keysize, match->GetEndian(), *match); + + if (0 == cmp) + { + // exact match is both lower and upper bound + return match; + } + else if (cmp < 0) + { + // key < match + if (reverse) + { + // want largest item <= key + return FindLexicalPredecessor(match); + } + else + { + // want smallest item >= key + return match; + } + } + else + { + // key > match + if (reverse) + { + // want largest item <= key + return match; + } + else + { + // want smallest item >= key + return FindLexicalSuccessor(match); + } + } +} // end ProtoTree::FindBound() + ProtoTree::Iterator::Iterator(ProtoTree& theTree, bool reverse, ProtoTree::Item* cursor) : ProtoIterable::Iterator(theTree), prefix_size(0), prefix_item(NULL) @@ -682,7 +1431,7 @@ ProtoTree::Iterator::Iterator(ProtoTree& theTree, bool reverse, ProtoTree::Item* { Reset(reverse); // Reset() sets all to defaults } -} +} ProtoTree::Iterator::~Iterator() { @@ -693,15 +1442,15 @@ void ProtoTree::Iterator::Reset(bool reverse, unsigned int prefixSize) { ProtoTree* tree = static_cast(iterable); - + prefix_size = 0; prefix_item = prev = next = curr_hop = (Item*)NULL; if ((NULL == tree) || (NULL == tree->root)) return; - + if (0 != prefixSize) { if (NULL == prefix) return; - // Find root of subtree with matching prefix + // Find root of subtree with matching prefix // (TBD - there's a better way to find the min/max prefix matches via prefix00000 or prefix11111 ProtoTree::Item* prefixItem = tree->FindPrefixSubtree(prefix, prefixSize); if (NULL == prefixItem) return; @@ -714,7 +1463,7 @@ void ProtoTree::Iterator::Reset(bool reverse, // Find the maximum value with matching prefix. ProtoTree::Item* lastItem; while (NULL != (lastItem = GetNextItem())) - { + { if (!tree->PrefixIsEqual(lastItem->GetKey(), lastItem->GetKeysize(), prefix, prefixSize, keyEndian)) break; // The "cursor" is set to after the last matching item } @@ -725,7 +1474,7 @@ void ProtoTree::Iterator::Reset(bool reverse, // Find the minimum value with matching prefix. ProtoTree::Item* firstItem; while (NULL != (firstItem = GetPrevItem())) - { + { if (!tree->PrefixIsEqual(firstItem->GetKey(), firstItem->GetKeysize(), prefix, prefixSize, keyEndian)) break; // The "cursor" is set to before the first matching item } @@ -735,7 +1484,7 @@ void ProtoTree::Iterator::Reset(bool reverse, prefix_item = prefixItem; return; } - + if (reverse) { // This code is basically the same as ProtoTree::GetLastItem() @@ -753,7 +1502,7 @@ void ProtoTree::Iterator::Reset(bool reverse, prev = x; } reversed = true; - } + } else { // This code is basically the same as ProtoTree::GetFirstItem() @@ -770,7 +1519,7 @@ void ProtoTree::Iterator::Reset(bool reverse, { // If root has a left side, go as far left as possible // to find the very first item (lexically) in the tree - Item* x = (tree->root->left == tree->root) ? tree->root->right : tree->root; + Item* x = (tree->root->left == tree->root) ? tree->root->right : tree->root; while (x->left->parent == x) x = x->left; next = x->left; if (x->right->parent == x) @@ -794,7 +1543,7 @@ void ProtoTree::Iterator::SetCursor(ProtoTree::Item& item) ProtoTree::Item* prefixItem = prefix_item; prefix_size = 0; prefix_item = NULL; - + if ((NULL== tree) || (NULL == tree->root)) { prev = next = curr_hop = NULL; @@ -818,13 +1567,13 @@ void ProtoTree::Iterator::SetCursor(ProtoTree::Item& item) { // Setting "cursor" for "reversed" iteration is easy. curr_hop = NULL; - prev = &item; + prev = &item; GetPrevItem(); // note this sets "next" } else { // Setting "cursor" for forward iteration is a little more complicated. - // Given an "item", we can find the "curr_hop" for the tree + // Given an "item", we can find the "curr_hop" for the tree // entry that lexically precedes the "item" // (We do a reverse iteration to find that preceding entry) reversed = true; @@ -842,7 +1591,7 @@ void ProtoTree::Iterator::SetCursor(ProtoTree::Item& item) // the entry previous of "item" ... if ((&item != tree->root) || (item.right != &item)) { - // Find the node's "predecessor" + // Find the node's "predecessor" // (has backpointer to "item" curr_hop = tree->FindPredecessor(item); } @@ -863,8 +1612,8 @@ void ProtoTree::Iterator::SetCursor(ProtoTree::Item& item) x = x->right; else x = x->left; - } while (x != &item); - curr_hop = s; + } while (x != &item); + curr_hop = s; } // Move forward two places so "cursor" is correct position reversed = false; @@ -902,14 +1651,14 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() if (0 != prefix_size) { // Test "item" against our reference "prefix_item" - if ((NULL == prefix_item) || + if ((NULL == prefix_item) || !tree->PrefixIsEqual(item->GetKey(), item->GetKeysize(), prefix_item->GetKey(), prefix_size, keyEndian)) { prev = NULL; return NULL; } } - + Item* x; // Find node "q" with backpointer to "item" if ((NULL == item->parent) && (item->right == item)) @@ -917,15 +1666,15 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() else x = item; Item* q; - do - { - q = x; + do + { + q = x; if (tree->Bit(item->GetKey(), item->GetKeysize(), x->bit, keyEndian)) x = x->right; - else - x = x->left; - } while (x != prev); - + else + x = x->left; + } while (x != prev); + if (q->right != item) { // Go up the tree @@ -943,21 +1692,21 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() // root has no left side, so we're done prev = NULL; } - else + else { // We've iterated to root from the right side // and root has a left side we should check out // So, find the left-side predecessor to root "q" Item* r = q; x = q->left; - do - { - q = x; + do + { + q = x; if (tree->Bit(r->GetKey(), r->GetKeysize(), x->bit, keyEndian)) x = x->right; - else - x = x->left; - } while (x != r); + else + x = x->left; + } while (x != r); if (q->left != q) { // Go as far right of "q->left" as possible @@ -965,7 +1714,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() do { x = q; - q = q->right; + q = q->right; } while (x == q->parent); } prev = q; @@ -974,7 +1723,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() return item; } } // end if (q->right != prev) - + if (q->left->parent != q) { if ((NULL == q->left->parent) && @@ -987,7 +1736,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() do { q = x; - x = x->right; + x = x->right; } while (q == x->parent); prev = x; } @@ -1004,7 +1753,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() do { q = x; - x = x->right; + x = x->right; } while (q == x->parent); prev = x; } @@ -1014,7 +1763,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetPrevItem() else { return NULL; - } + } } // end ProtoTree::Iterator::GetPrevItem() @@ -1043,7 +1792,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetNextItem() // so we need to turn it around reversed = false; SetCursor(*next); - if (NULL == next) return NULL; + if (NULL == next) return NULL; } Item* item = next; Endian keyEndian = next->GetEndian(); @@ -1066,7 +1815,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetNextItem() if (x->right == x) { next = x; - curr_hop = NULL; + curr_hop = NULL; } else { @@ -1100,7 +1849,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetNextItem() // First, check for root node visit if ((NULL == next->parent) && (next->right != next) && - (tree->Bit(x->GetKey(), x->GetKeysize(), 0, keyEndian) != tree->Bit(next->GetKey(), next->GetKeysize(), 0, keyEndian))) + (tree->Bit(x->GetKey(), x->GetKeysize(), 0, keyEndian) != tree->Bit(next->GetKey(), next->GetKeysize(), 0, keyEndian))) { // Branch right and go as far left as possible x = next->right; @@ -1144,7 +1893,7 @@ ProtoTree::Item* ProtoTree::Iterator::GetNextItem() if (0 != prefix_size) { // Test "item" against prefix of item last returned - if ((NULL == prefix_item) || + if ((NULL == prefix_item) || !tree->PrefixIsEqual(item->GetKey(), item->GetKeysize(), prefix_item->GetKey(), prefix_size, keyEndian)) return NULL; } @@ -1206,7 +1955,7 @@ void ProtoTree::Iterator::Update(ProtoIterable::Item* theItem, Action theAction) } case REMOVE: { - // NOTE - This doesn't work quite right for prefix iterators + // NOTE - This doesn't work quite right for prefix iterators // (mid-iteration removal of items can break comprehensive prefix iteration) // Save our current iterator state Item* oldPrev = prev; @@ -1234,14 +1983,14 @@ void ProtoTree::Iterator::Update(ProtoIterable::Item* theItem, Action theAction) Reset(reversed, prefix_item->GetKey(), prefix_size); } else - { + { SetCursor(*oldNext); } } else { // This puts the iteration to a ambiguous - // state that allows subsequent calls to + // state that allows subsequent calls to // either GetPrevItem() or GetNextItem() to // work properly even though the "cursor" is // wrong. (Note PeekNextItem() won't be correct) @@ -1275,7 +2024,7 @@ void ProtoTree::Iterator::Update(ProtoIterable::Item* theItem, Action theAction) { if (NULL == oldPrev) { - // tree is now empty? + // tree is now empty? //ASSERT(NULL == prefix_item); if (NULL == prefix_item) prev = next = NULL; @@ -1291,7 +2040,7 @@ void ProtoTree::Iterator::Update(ProtoIterable::Item* theItem, Action theAction) { if (NULL == oldNext) { - // tree is now empty? + // tree is now empty? //ASSERT(NULL == prefix_item); if (NULL == prefix_item) prev = next = NULL; @@ -1387,7 +2136,7 @@ void ProtoTree::SimpleIterator::Update(ProtoIterable::Item* /*theItem*/, Action { // For ProtoTree::SimpleIterator, really the only "sane" thing to do when the associated // tree is modified is to "Reset()" the iterator since the logical tree structure - // is potentially heavily affected by any change. This is heavy-handed so it's + // is potentially heavily affected by any change. This is heavy-handed so it's // actually more efficient to do a "GetRoot(), Remove()" loop until GetRoot() returns NULL // (see ProtoTree::Destroy()) instead of using this SimpleIterator. Where it _is_ // useful is in the ProtoIndexedQueue::Empty() method where it empties the tree without invoking @@ -1398,6 +2147,7 @@ void ProtoTree::SimpleIterator::Update(ProtoIterable::Item* /*theItem*/, Action } // end ProtoTree::SimpleIterator::Update() + ProtoSortedTree::ProtoSortedTree(bool uniqueItemsOnly) : unique_items_only(uniqueItemsOnly), positive_min(NULL) { @@ -1415,7 +2165,7 @@ bool ProtoSortedTree::Insert(Item& item) unsigned int keysize = item.GetKeysize(); ProtoTree::Endian keyEndian = item.GetEndian(); Item* match = Find(key, keysize); - + if (NULL == match) { // Insert the item into our "item_tree" @@ -1464,7 +2214,7 @@ bool ProtoSortedTree::Insert(Item& item) } // Note: (itemSign && !headSign) is impossible here } - else + else { Item* head = GetHead(); bool headSign = item_tree.Bit(head->GetKey(), head->GetKeysize(), 0, keyEndian); @@ -1523,10 +2273,10 @@ bool ProtoSortedTree::Insert(Item& item) item_list.Append(item); ASSERT(!item_tree.Bit(match->GetKey(), match->GetKeysize(), 0, keyEndian)); // Note (!itemSign && matchSign) can't happen - // here since signed "match" (negative value) + // here since signed "match" (negative value) // _must_ lexically succeed unsigned "item" } - else + else { bool useComplement2 = item.UseComplement2(); ASSERT(useComplement2 == match->UseComplement2()); @@ -1550,18 +2300,9 @@ bool ProtoSortedTree::Insert(Item& item) // Insert "item" before first equivalent "match" // note "prev" here lexically _succeeds_ this // "item" that was inserted into tree above, so: - - ProtoTree::Iterator iterator(item_tree, false, &item); - Item* prev = static_cast(iterator.PeekNextItem()); - - /* (Old "while()" loop approach to find prev, in-tree item) - Item* prev = match->GetPrev(); - while ((NULL != prev) && !prev->IsInTree()) - { - match = prev; - prev = prev->GetPrev(); - } - */ + + Item* prev = static_cast(item_tree.FindLexicalSuccessor(&item)); + if (NULL != prev) { Item* next = static_cast(item_list.GetNextItem(*prev)); @@ -1635,10 +2376,10 @@ void ProtoSortedTree::Remove(Item& item) { // 1) Save some state and remove from linked list Item* prev = static_cast(item_list.GetPrevItem(item)); - if (&item == positive_min) + if (&item == positive_min) positive_min = static_cast(item_list.GetNextItem(item)); item_list.Remove(item); - + // 2) Remove from ProtoTree, if applicable if (item.IsInTree()) { @@ -1657,8 +2398,8 @@ void ProtoSortedTree::Empty() { item_tree.Empty(); item_list.Empty(); - positive_min = NULL; - } + positive_min = NULL; + } } // end ProtoSortedTree::Empty() void ProtoSortedTree::EmptyToPool(ItemPool& itemPool) @@ -1667,8 +2408,8 @@ void ProtoSortedTree::EmptyToPool(ItemPool& itemPool) { item_tree.Empty(); item_list.EmptyToPool(itemPool); - positive_min = NULL; - } + positive_min = NULL; + } } // end ProtoSortedTree::EmptyToPool() void ProtoSortedTree::Destroy() @@ -1677,7 +2418,7 @@ void ProtoSortedTree::Destroy() { item_tree.Empty(); item_list.Destroy(); - positive_min = NULL; + positive_min = NULL; } } // end ProtoSortedTree::Destroy() @@ -1689,9 +2430,9 @@ ProtoSortedTree::Item::~Item() { } -ProtoSortedTree::Iterator::Iterator(ProtoSortedTree& theTree, - bool reverse, - const char* keyMin, +ProtoSortedTree::Iterator::Iterator(ProtoSortedTree& theTree, + bool reverse, + const char* keyMin, unsigned int keysize) : tree(theTree), list_iterator(theTree.item_list, reverse) { @@ -1702,6 +2443,7 @@ ProtoSortedTree::Iterator::~Iterator() { } +/* void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned int keysize) { list_iterator.Reset(reverse); // put the iterator in the right direction @@ -1709,14 +2451,14 @@ void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned { // refine if a "keyMin" start point was provided // (note for "reverse" == true, "keyMin" is really a "keyMax" - Item* match = tree.Find(keyMin, keysize); + Item* match = tree.Find(keyMin, keysize); if (NULL == match) { // There was no exact match to "keyMin", so look for next item (or prev if reverse == true) TempItem tmpItem(keyMin, keysize, tree.GetHead()->GetEndian()); tree.item_tree.Insert(tmpItem); ProtoTree::Iterator iterator(tree.item_tree, reverse, &tmpItem); - match = reverse ? static_cast(iterator.PeekPrevItem()) : + match = reverse ? static_cast(iterator.PeekPrevItem()) : static_cast(iterator.PeekNextItem()); tree.item_tree.Remove(tmpItem); // it's done its job, so bye-bye } @@ -1726,7 +2468,38 @@ void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned ProtoTree::Iterator iterator(tree.item_tree, true, match); Item* prev = static_cast(iterator.PeekPrevItem()); if (NULL == prev) - match = tree.item_list.GetHead(); + match = tree.item_list.GetHead(); + else + match = static_cast(tree.item_list.GetNextItem(*prev)); + } + list_iterator.SetCursor(match); + } +} // end ProtoSortedTree::Iterator::Reset() +*/ + +void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned int keysize) +{ + list_iterator.Reset(reverse); // put the iterator in the right direction + if ((NULL != keyMin) && list_iterator.IsValid() && !tree.IsEmpty()) + { + // refine if a "keyMin" start point was provided + // (note for "reverse" == true, "keyMin" is really a "keyMax" + Item* match = tree.Find(keyMin, keysize); + if (NULL == match) + { + // There was no exact match to "keyMin", so look for next item (or prev if reverse == true) + TempItem tmpItem(keyMin, keysize, tree.GetHead()->GetEndian()); + tree.item_tree.Insert(tmpItem); + match = reverse ? static_cast(tree.item_tree.FindLexicalPredecessor(&tmpItem)) : + static_cast(tree.item_tree.FindLexicalSuccessor(&tmpItem)); + tree.item_tree.Remove(tmpItem); // it's done its job, so bye-bye + } + if ((NULL != match) && !reverse) + { + // Make sure we are positioned on _first_ item of equal valued items + Item* prev = static_cast(tree.item_tree.FindLexicalPredecessor(match)); + if (NULL == prev) + match = tree.item_list.GetHead(); else match = static_cast(tree.item_list.GetNextItem(*prev)); } @@ -1734,7 +2507,6 @@ void ProtoSortedTree::Iterator::Reset(bool reverse, const char* keyMin, unsigned } } // end ProtoSortedTree::Iterator::Reset() - ProtoSortedTree::Iterator::TempItem::TempItem(const char* theKey, unsigned int theKeysize, ProtoTree::Endian keyEndian) : key(theKey), keysize(theKeysize), key_endian(keyEndian) { @@ -1743,3 +2515,4 @@ ProtoSortedTree::Iterator::TempItem::TempItem(const char* theKey, unsigned int t ProtoSortedTree::Iterator::TempItem::~TempItem() { } + diff --git a/src/manet/manetGraph.cpp b/src/manet/manetGraph.cpp index 022a10b..4706f65 100755 --- a/src/manet/manetGraph.cpp +++ b/src/manet/manetGraph.cpp @@ -544,7 +544,7 @@ void NetGraph::Node::RemoveInterface(Interface& iface) extra_addr_list.Remove(addr); //check to see if was the default and reassign a default if it was if (&iface == default_interface_ptr) - default_interface_ptr = (NetGraph::Interface*)(iface_list.GetRoot()); + default_interface_ptr = (NetGraph::Interface*)(iface_list.GetHead()); } // end NetGraph::Node::RemoveInterface() bool NetGraph::Node::IsSymmetricNeighbor(Node& node) diff --git a/src/manet/manetGraphML.cpp b/src/manet/manetGraphML.cpp index aaa256c..3259914 100755 --- a/src/manet/manetGraphML.cpp +++ b/src/manet/manetGraphML.cpp @@ -1,20 +1,20 @@ #include #include -ManetGraphMLParser::ManetGraphMLParser() : XMLName(NULL), indexes(0) +ManetGraphMLParser::ManetGraphMLParser() : XMLName(NULL), indexes(0) { xmlInitParser(); } -ManetGraphMLParser::~ManetGraphMLParser() +ManetGraphMLParser::~ManetGraphMLParser() { - xmlCleanupParser(); + xmlCleanupParser(); oldindexkeylist.Empty(); indexkeylist.Empty(); namedkeylist.Destroy(); - + attributelist.Destroy(); - if (NULL != XMLName) + if (NULL != XMLName) { delete[] XMLName; XMLName = NULL; @@ -48,7 +48,7 @@ bool ManetGraphMLParser::AttributeKey::Init(const char* theIndex,const char* the } index = new char[strlen(theIndex)+1]; name = new char[strlen(theName)+1]; - + if((NULL == index) || (NULL == name)) { PLOG(PL_ERROR,"ManetGraphMLParser::AttributeKey::Init: Error allocating space for index or name strings\n"); @@ -101,7 +101,7 @@ bool ManetGraphMLParser::AttributeKey::Set(const char* theIndex,const char* theN delete[] oldindex; index = new char[strlen(theIndex)+1]; name = new char[strlen(theName)+1]; - + if((NULL == index) || (NULL == name)) { PLOG(PL_ERROR,"ManetGraphMLParser::AttributeKey::Set: Error allocating space for index or name strings\n"); @@ -146,14 +146,14 @@ bool ManetGraphMLParser::AttributeKey::Set(const char* theIndex,const char* theN bool ManetGraphMLParser::AttributeKey::SetType(const char* theType) { - if((!strcmp(theType,"bool")) || + if((!strcmp(theType,"bool")) || (!strcmp(theType,"Bool")) || (!strcmp(theType,"BOOL")) || (!strcmp(theType,"boolean")) || (!strcmp(theType,"Boolean")) || (!strcmp(theType,"BOOLEAN"))) { type = Types::BOOL; - } else if + } else if ((!strcmp(theType,"int")) || (!strcmp(theType,"Int")) || (!strcmp(theType,"INT")) || @@ -161,22 +161,22 @@ bool ManetGraphMLParser::AttributeKey::SetType(const char* theType) (!strcmp(theType,"Integer")) || (!strcmp(theType,"INTEGER"))) { type = Types::INT; - } else if + } else if ((!strcmp(theType,"long")) || (!strcmp(theType,"Long")) || (!strcmp(theType,"LONG"))) { type = Types::LONG; - } else if + } else if ((!strcmp(theType,"float")) || (!strcmp(theType,"Float")) || (!strcmp(theType,"FLOAT"))) { type = Types::FLOAT; - } else if + } else if ((!strcmp(theType,"double")) || (!strcmp(theType,"Double")) || (!strcmp(theType,"DOUBLE"))) { type = Types::DOUBLE; - } else if + } else if ((!strcmp(theType,"string")) || (!strcmp(theType,"String")) || (!strcmp(theType,"STRING"))) { @@ -190,21 +190,21 @@ bool ManetGraphMLParser::AttributeKey::SetType(const char* theType) bool ManetGraphMLParser::AttributeKey::SetDomain(const char* theDomain) { - if((!strcmp(theDomain,"graph")) || + if((!strcmp(theDomain,"graph")) || (!strcmp(theDomain,"Graph")) || (!strcmp(theDomain,"GRAPH"))) { domain = Domains::GRAPH; - } else if + } else if ((!strcmp(theDomain,"node")) || (!strcmp(theDomain,"Node")) || (!strcmp(theDomain,"NODE"))) { domain = Domains::NODE; - } else if + } else if ((!strcmp(theDomain,"edge")) || (!strcmp(theDomain,"Edge")) || (!strcmp(theDomain,"EDGE"))) { domain = Domains::EDGE; - } else if + } else if ((!strcmp(theDomain,"all")) || (!strcmp(theDomain,"All")) || (!strcmp(theDomain,"ALL"))) { @@ -318,7 +318,7 @@ ManetGraphMLParser::SetAttributeKey(const char* theName,const char* theType, con return false; //shouldn't get here } -bool +bool ManetGraphMLParser::SetAttribute(const char* theName, const char* theValue) { PLOG(PL_DETAIL,"ManetGraphMLParser::SetAttribute(name=%s,theValue=%s)\n",theName,theValue); @@ -338,7 +338,7 @@ ManetGraphMLParser::SetAttribute(const char* theName, const char* theValue) { PLOG(PL_DETAIL,"ManetGraphMLParser::SetAttribute(name=%s,theValue=%s) making new one\n",theName,theValue); return AddAttribute(theName,theValue); - } + } else { char tempIndex[20]; @@ -354,7 +354,7 @@ ManetGraphMLParser::SetAttribute(const char* theName, const char* theValue) return false; //should never get here } -bool +bool ManetGraphMLParser::SetAttribute(NetGraph::Node& node, const char* theName, const char* theValue) { PLOG(PL_DETAIL,"ManetGraphMLParser::SetAttribute(Node,name=%s,theValue=%s)\n",theName,theValue); @@ -374,7 +374,7 @@ ManetGraphMLParser::SetAttribute(NetGraph::Node& node, const char* theName, cons { PLOG(PL_DETAIL,"ManetGraphMLParser::SetAttribute(Node,name=%s,theValue=%s) making new one\n",theName,theValue); return AddAttribute(node,theName,theValue); - } + } else { char tempIndex[20]; @@ -400,7 +400,7 @@ bool ManetGraphMLParser::SetAttribute(NetGraph::Link& link, const char* theName, } char theLookup[250]; GetLookup(theLookup,250,link); - + ManetGraphMLParser::Attribute* theAttribute = attributelist.FindAttribute(theLookup,theIndex); if(NULL == theAttribute) { @@ -477,7 +477,7 @@ ManetGraphMLParser::AddAttributeKey(const char* theName,const char* theType, con return false; } char theIndex[20];//this will work as we are only using d%d as our indexes. - sprintf(theIndex,"d%d",indexes++); + snprintf(theIndex,20, "d%d",indexes++); PLOG(PL_DETAIL,"ManetGraphMLParser::AddAttributeKey() made key initing with \"%s\"\n",theIndex); if(!newKey->Init(theIndex,theName,theType,theDomain,theOldKey,theDefault)) { @@ -508,7 +508,7 @@ bool ManetGraphMLParser::AddAttribute(const char* theName, const char* theValue) PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(): Error allocating attribute\n"); return false; } - + char theLookup[250]; //TBD GetLookup(theLookup,250); if(!newAttribute->Init(theLookup,theIndex,theValue)) @@ -521,7 +521,7 @@ bool ManetGraphMLParser::AddAttribute(const char* theName, const char* theValue) PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(): Error inserting the attribute\n"); return false; } - DMSG(7,"ManetGraphMLParser::AddAttribute(%s,%s) added successfully\n",theName,theValue); + DMSG(7,"ManetGraphMLParser::AddAttribute(%s,%s) added successfully\n",theName,theValue); return true; } @@ -539,7 +539,7 @@ bool ManetGraphMLParser::AddAttribute(NetGraph::Node& node, const char* theName, PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(Node): Error allocating attribute\n"); return false; } - + char theLookup[250]; //TBD GetLookup(theLookup,250,node); if(!newAttribute->Init(theLookup,theIndex,theValue)) @@ -552,7 +552,7 @@ bool ManetGraphMLParser::AddAttribute(NetGraph::Node& node, const char* theName, PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(Node): Error inserting the attribute\n"); return false; } - DMSG(7,"ManetGraphMLParser::AddAttribute(node,%s,%s) added successfully\n",theName,theValue); + DMSG(7,"ManetGraphMLParser::AddAttribute(node,%s,%s) added successfully\n",theName,theValue); return true; } bool ManetGraphMLParser::AddAttribute(NetGraph::Link& link, const char* theName, const char* theValue) @@ -582,7 +582,7 @@ bool ManetGraphMLParser::AddAttribute(NetGraph::Link& link, const char* theName, PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(Link): Error inserting the attribute\n"); return false; } - return true; + return true; } bool ManetGraphMLParser::AddAttribute(NetGraph::Interface& interface, const char* theName, const char* theValue) { @@ -600,7 +600,7 @@ bool ManetGraphMLParser::AddAttribute(NetGraph::Interface& interface, const char } char theLookup[250]; - GetLookup(theLookup,250,interface); + GetLookup(theLookup,250,interface); if(!newAttribute->Init(theLookup,theIndex,theValue)) { PLOG(PL_ERROR,"ManetGraphMLParser::AddAttribute(Interface): Error init the attribute\n"); @@ -616,7 +616,7 @@ bool ManetGraphMLParser::AddAttribute(NetGraph::Interface& interface, const char bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen) { - sprintf(theLookup,"thisGraph");//don't name interfaces/links/nodes thisGraph! + snprintf(theLookup, maxlen, "thisGraph");//don't name interfaces/links/nodes thisGraph! return true; } @@ -627,7 +627,7 @@ bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen,NetGraph: PLOG(PL_ERROR,"ManetGraphMLParser::GetLookup(node) node string is longer than max leng\n"); return false; } - sprintf(theLookup,"node:%s",GetString(node)); + snprintf(theLookup, maxlen, "node:%s",GetString(node)); return true; } bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen,NetGraph::Link& link) @@ -653,13 +653,13 @@ bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen,NetGraph: delete[] targetPortName; return false; } - sprintf(theLookup,"edge:source:%s:%s:dest:%s:%s",sourceName,sourcePortName,targetName,targetPortName); + snprintf(theLookup,maxlen, "edge:source:%s:%s:dest:%s:%s",sourceName,sourcePortName,targetName,targetPortName); delete[] sourceName; delete[] sourcePortName; delete[] targetName; delete[] targetPortName; - + return true; } bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen,NetGraph::Interface& interface) @@ -673,7 +673,7 @@ bool ManetGraphMLParser::GetLookup(char* theLookup,unsigned int maxlen,NetGraph: delete[] portName; return false; } - sprintf(theLookup,"node:%s:port:%s",GetString(interface.GetNode()),portName); + snprintf(theLookup,maxlen, "node:%s:port:%s",GetString(interface.GetNode()),portName); delete[] portName; return true; } @@ -694,7 +694,7 @@ const char* ManetGraphMLParser::FindAttributeIndex(const char* theName) ManetGraphMLParser::AttributeKey* ManetGraphMLParser::FindAttributeKey(const char* theName) { return namedkeylist.Find(theName,strlen(theName)*8); -} +} ManetGraphMLParser::AttributeKey* ManetGraphMLParser::FindAttributeKeyByOldIndex(const char* theOldIndex) { return oldindexkeylist.Find(theOldIndex,strlen(theOldIndex)*8); @@ -715,7 +715,7 @@ ManetGraphMLParser::Attribute::Set(const char* theLookupvalue, const char* theIn } if(NULL != index) { - delete[] index; + delete[] index; index = NULL; } if(NULL != value) @@ -759,9 +759,9 @@ ManetGraphMLParser::Attribute::~Attribute() delete[] index; delete[] value; } -bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, - NetGraph& graph, - char* parentXMLNodeID, +bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, + NetGraph& graph, + char* parentXMLNodeID, bool& isDuplex) { //const xmlChar *name, *value; @@ -777,7 +777,7 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, name = BAD_CAST "--"; //value = xmlTextReaderConstValue(readerPtr); //depth = xmlTextReaderDepth(readerPtr); - //isempty = xmlTextReaderIsEmptyElement(readerPtr); + //isempty = xmlTextReaderIsEmptyElement(readerPtr); //count = xmlTextReaderAttributeCount(readerPtr); //printf("processsing depth=%d, type=%d, name=%s, isempty=%d, value=%s, attributes=%d\n",depth,type,name,isempty,value,count); if(!strcmp("graph",(const char*)name)) @@ -826,17 +826,17 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, PLOG(PL_ERROR,"ManetGraphMLParser::ReadXMLNode: Error the node id value of \"%s\" is too large\n",nodeId); return false; } - memset(parentXMLNodeID, 0, MAXXMLIDLENGTH+1); + memset(parentXMLNodeID, 0, MAXXMLIDLENGTH+1); strcpy(parentXMLNodeID,(const char*)nodeId); - + NetGraph::Interface* interface; ProtoAddress addr; addr.ConvertFromString((const char*)nodeId); if(addr.IsValid()) { interface = graph.FindInterface(addr); - } - else + } + else { interface = graph.FindInterfaceByName((const char*)nodeId); } @@ -844,17 +844,17 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, { //Create new node and associated interface NetGraph::Node* node = CreateNode(); - + if(NULL == node) { PLOG(PL_ERROR, "NetGraph::ProcessXMLNode: error Creating new node!\n"); return -1; - } + } if(addr.IsValid()) { interface = CreateInterface(*node,addr); - } - else + } + else { interface = CreateInterface(*node); interface->SetName((const char*)nodeId); @@ -894,14 +894,14 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, PLOG(PL_ERROR,"ManetGraphMLParser::ReadXMLNode: Error finding the parent \"%s\" interface in the graph for port \"%s\"!\n",parentXMLNodeID,portname); return false; } - + NetGraph::Node& node = interface->GetNode(); //NetGraph::Node *node = &interface->GetNode(); if(portAddr.IsValid()) { portinterface = new NetGraph::Interface(node,portAddr); - } - else + } + else { portinterface = CreateInterface(node); portinterface->SetName((const char*)portname); @@ -1027,30 +1027,34 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, if(!strcmp((const char*)myxmlnode->parent->name,"node")) { - sprintf(newlookup,"node:%s",parentXMLNodeID); - } else if(!strcmp((const char*)myxmlnode->parent->name,"port")) { + snprintf(newlookup,250, "node:%s",parentXMLNodeID); + } + else if(!strcmp((const char*)myxmlnode->parent->name,"port")) + { xmlAttr* tempattribute = myxmlnode->parent->properties; const xmlChar *portName = NULL; - while(NULL != tempattribute) + while(NULL != tempattribute) { - if(!strcmp((const char*)tempattribute->name,"name")) + if(!strcmp((const char*)tempattribute->name,"name")) portName = tempattribute->children->content; tempattribute= tempattribute->next; } - sprintf(newlookup,"node:%s:port:%s",parentXMLNodeID,portName); - - } else if(!strcmp((const char*)myxmlnode->parent->name,"edge")) { + snprintf(newlookup,250, "node:%s:port:%s",parentXMLNodeID,portName); + + } + else if(!strcmp((const char*)myxmlnode->parent->name,"edge")) + { xmlAttr* tempattribute = myxmlnode->parent->properties; const xmlChar *targetPortName(NULL), *sourcePortName(NULL), *targetName(NULL), *sourceName(NULL); while(NULL != tempattribute) { - if(!strcmp((const char*)tempattribute->name,"sourceport")) + if(!strcmp((const char*)tempattribute->name,"sourceport")) sourcePortName = tempattribute->children->content; - if(!strcmp((const char*)tempattribute->name,"targetport")) + if(!strcmp((const char*)tempattribute->name,"targetport")) targetPortName = tempattribute->children->content; - if(!strcmp((const char*)tempattribute->name,"source")) + if(!strcmp((const char*)tempattribute->name,"source")) sourceName = tempattribute->children->content; - if(!strcmp((const char*)tempattribute->name,"target")) + if(!strcmp((const char*)tempattribute->name,"target")) targetName = tempattribute->children->content; tempattribute= tempattribute->next; } @@ -1067,8 +1071,10 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, { targetPortName = targetName; } - sprintf(newlookup,"edge:source:%s:%s:dest:%s:%s",sourceName,sourcePortName,targetName,targetPortName); - } else { + snprintf(newlookup,250, "edge:source:%s:%s:dest:%s:%s",sourceName,sourcePortName,targetName,targetPortName); + } + else + { PLOG(PL_WARN,"ManetGraphMLParser::ReadXMLNode(): Ignoring data for unknown node type\n"); } oldIndex = xmlTextReaderGetAttribute(readerPtr,(xmlChar*)"key"); @@ -1077,7 +1083,9 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, { PLOG(PL_ERROR,"ManetGraphMLParser::ReadXMLNode(): found data with key type %s but it wasn't listed at one of the keys\n",oldIndex); return false; - } else { + } + else + { newIndex = tempakey->GetIndex(); //printf("newIndex =%s\n",newIndex); } @@ -1085,7 +1093,7 @@ bool ManetGraphMLParser::ReadXMLNode(xmlTextReader* readerPtr, return false; newValue = xmlTextReaderValue(readerPtr); //printf("found data for \"%s\" with key %s with value %s\n",newlookup,oldIndex,newValue); - + Attribute* newAttribute = new Attribute(); newAttribute->Init(newlookup,(const char*)newIndex,(const char*)newValue); //newAttribute->Init(newlookup,newIndex,(const char*)newValue); @@ -1114,10 +1122,10 @@ bool ManetGraphMLParser::Read(const char* path, NetGraph& graph) PLOG(PL_ERROR,"ManetGraphMLParser::Read() xmlReaderForFile(%s) error: %s\n",path, GetErrorString()); return false; } - + bool isDuplex = true; char parentXMLNodeID[MAXXMLIDLENGTH+1]; - memset(parentXMLNodeID, 0, MAXXMLIDLENGTH+1); + memset(parentXMLNodeID, 0, MAXXMLIDLENGTH+1); int result = xmlTextReaderRead(readerPtr); while (1 == result) { @@ -1127,7 +1135,7 @@ bool ManetGraphMLParser::Read(const char* path, NetGraph& graph) break; } result = xmlTextReaderRead(readerPtr); - } + } xmlFreeTextReader(readerPtr); if (0 != result) PLOG(PL_ERROR,"ManetGraphMLParser::Read() error: invalid XML file %s\n", path); @@ -1170,7 +1178,7 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, if (returnvalue < 0) { PLOG(PL_ERROR,"ManetGraphMLParser::Write::testXmlWriterDoc: Error at xmlTextWriterWriteAttribute\n"); return false; - } + } if(!UpdateKeys(graph)) { PLOG(PL_ERROR,"ManetGraphMLParser::Write::testXmlWriterDoc: Error updating key elements in the header\n"); @@ -1186,19 +1194,19 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, PLOG(PL_ERROR,"ManetGraphMLParser::Write::testXmlWriterDoc: Error at writing graph attributes in header\n"); return false; } - + /* We are done with the header so now we go through the actual graph and add each node and edge */ /* We are adding each node */ returnvalue = xmlTextWriterStartElement(writerPtr, BAD_CAST "graph"); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error starting XML graph element\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error starting XML graph element\n"); return false; } returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "id",BAD_CAST XMLName); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error setting XML graph attribute id\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error setting XML graph attribute id\n"); return false; } returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "edgedefault",BAD_CAST "directed"); @@ -1215,9 +1223,9 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, { //Node& node = static_cast(iface->GetNode()); returnvalue = xmlTextWriterStartElement(writerPtr, BAD_CAST "node"); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding XML node\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding XML node\n"); return false; } if(iface->GetAddress().IsValid()) @@ -1225,19 +1233,19 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "id", BAD_CAST iface->GetAddress().GetHostString()); //printf("writing node %s\n",iface->GetAddress().GetHostString()); } - else + else { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "id", BAD_CAST iface->GetName()); //printf("writing node %s\n",iface->GetName()); } if (returnvalue < 0) { PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding setting node id\n"); return false;} - + //update the node attributes using the virtual function if(!UpdateNodeAttributes(iface->GetNode())) { PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error updating the node attributes\n"); return false; - } + } //call the local function write the attributes out if(!WriteLocalNodeAttributes(writerPtr,iface->GetNode())) { @@ -1262,24 +1270,24 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, // if(portIface->IsPort()) { returnvalue = xmlTextWriterStartElement(writerPtr, BAD_CAST "port"); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding XML node\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding XML node\n"); return false; } if(portIface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "name", BAD_CAST portIface->GetAddress().GetHostString()); //printf("writing interface %s\n",iface->GetAddress().GetHostString()); - } - else + } + else { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "name", BAD_CAST portIface->GetName()); //printf("writing node %s\n",iface->GetName()); - } - if (returnvalue < 0) + } + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding setting node id\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error adding setting node id\n"); return false; } //update attributes to the port/interface using the virutal function @@ -1287,7 +1295,7 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, { PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error updating the interface attributes\n"); return false; - } + } //write the attributes to the port/interface if(!WriteLocalInterfaceAttributes(writerPtr,*portIface)) { @@ -1301,18 +1309,18 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, return false; }*/ returnvalue = xmlTextWriterEndElement(writerPtr); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error ending node element\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error ending node element\n"); return false; } } } //close up the node node element returnvalue = xmlTextWriterEndElement(writerPtr); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error ending node element\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error ending node element\n"); return false; } } @@ -1329,36 +1337,36 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, while (NULL != (nbrIface = iteratorN1.GetNextAdjacency())) { returnvalue = xmlTextWriterStartElement(writerPtr, BAD_CAST "edge"); - if (returnvalue < 0) + if (returnvalue < 0) { PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding edge\n"); return false; } - if(iface->GetAddress().IsValid()) + if(iface->GetAddress().IsValid()) { //printf("writing connection %s ->",iface->GetAddress().GetHostString()); returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "source", BAD_CAST iface->GetAddress().GetHostString()); - }else - { + }else + { //printf("writing connection %s ->",iface->GetName()); returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "source", BAD_CAST iface->GetName()); } - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } if(nbrIface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "target", BAD_CAST nbrIface->GetAddress().GetHostString()); ////printf("%s\n",nbrIface->GetAddress().GetHostString()); - } - else + } + else { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "target", BAD_CAST nbrIface->GetName()); ////printf("%s\n",nbrIface->GetName()); } - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } NetGraph::Link* link = iface->GetLinkTo(*nbrIface); @@ -1372,7 +1380,7 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, { PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error updating the link attributes\n"); return false; - } + } //actually write the attributes out if(!WriteLocalLinkAttributes(writerPtr,*link)) { @@ -1380,12 +1388,12 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, return false; } returnvalue = xmlTextWriterEndElement(writerPtr); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error ending node element\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error ending node element\n"); return false; } - } + } } else //it is a port interface so we need to find the "node" interface { @@ -1397,7 +1405,7 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, PLOG(PL_ERROR,"ManetGraphMLParser::Write Error the default interface was not the \"node\" interface for the src. You should iterate over them all and find the right one\n"); return false; } - + NetGraph::AdjacencyIterator iteratorN1(*iface); NetGraph::Interface* nbrIface, *nbrNodeIface; while (NULL != (nbrIface = iteratorN1.GetNextAdjacency())) @@ -1411,61 +1419,61 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, return false; } returnvalue = xmlTextWriterStartElement(writerPtr, BAD_CAST "edge"); - if (returnvalue < 0) - { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding edge\n"); + if (returnvalue < 0) + { + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding edge\n"); return false; } - if(nodeIface->GetAddress().IsValid()) + if(nodeIface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "source", BAD_CAST nodeIface->GetAddress().GetHostString()); - } - else - { + } + else + { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "source", BAD_CAST nodeIface->GetName()); } - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } - if(nbrNodeIface->GetAddress().IsValid()) + if(nbrNodeIface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "target", BAD_CAST nbrNodeIface->GetAddress().GetHostString()); - } - else + } + else { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "target", BAD_CAST nbrNodeIface->GetName()); } - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } - if(iface->GetAddress().IsValid()) + if(iface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "sourceport", BAD_CAST iface->GetAddress().GetHostString()); - } - else - { + } + else + { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "sourceport", BAD_CAST iface->GetName()); } if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } if(nbrIface->GetAddress().IsValid()) { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "targetport", BAD_CAST nbrIface->GetAddress().GetHostString()); } - else + else { returnvalue = xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "targetport", BAD_CAST nbrIface->GetName()); } - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error adding setting source attribute\n"); return false; } @@ -1481,22 +1489,22 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error updating the link attributes\n"); return false; } - //actually write the attributes out + //actually write the attributes out if(!WriteLocalLinkAttributes(writerPtr,*link)) { PLOG(PL_ERROR,"ManetGraphMLParser::Write: Error writing link attributes\n"); return false; } returnvalue = xmlTextWriterEndElement(writerPtr); - if (returnvalue < 0) + if (returnvalue < 0) { - PLOG(PL_ERROR,"ManetGraphMLParser::Write Error ending node element\n"); + PLOG(PL_ERROR,"ManetGraphMLParser::Write Error ending node element\n"); return false; } - } + } } } - + returnvalue = xmlTextWriterEndDocument(writerPtr); if (returnvalue < 0) { PLOG(PL_ERROR,"ManetGraphMLParser::Write:testXmlwriterPtrDoc: Error at xmlTextWriterEndDocument\n"); return false;} @@ -1512,7 +1520,7 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, //xmlSaveFormatFileTo(&xmlbuff,docPtr,MY_GRAPHML_ENCODING,1); //if (xmlbuff.written > (int)*len_ptr){ // DMSG(0,"bunny in buffer section\n"); - + xmlChar* tempout; int size; xmlDocDumpFormatMemoryEnc(docPtr,&tempout,&size,MY_GRAPHML_ENCODING,1); @@ -1527,11 +1535,11 @@ bool ManetGraphMLParser::Write(NetGraph& graph, const char* path, char* buffer, xmlCleanupParser(); } xmlFreeDoc(docPtr); - + return true; } // end ManetGraphMLParser::Write() -ManetGraphMLParser::Attribute* +ManetGraphMLParser::Attribute* ManetGraphMLParser::AttributeList::FindAttribute(const char *theLookup,const char* theIndex) { AttributeList::Iterator it(*this,false,theLookup,strlen(theLookup)*8); @@ -1543,8 +1551,8 @@ ManetGraphMLParser::AttributeList::FindAttribute(const char *theLookup,const cha { attr = NULL; //we didn't find the entry - } - else + } + else { if(strcmp(attr->GetIndex(),theIndex)) { @@ -1626,7 +1634,7 @@ bool ManetGraphMLParser::WriteLocalNodeAttributes(xmlTextWriter* writerPtr,NetG PLOG(PL_DETAIL,"ManetGraphMLParser::WriteLocalNodeAttributes: Enter\n"); bool rv = true; char key[255];//this should be dynamic or checks added TBD - sprintf(key,"node:%s",GetString(theNode)); + snprintf(key,255, "node:%s",GetString(theNode)); AttributeList::Iterator it(attributelist,false,key,strlen(key)*8); Attribute* attr(NULL); //iterate over items which have the matching keys @@ -1638,8 +1646,8 @@ bool ManetGraphMLParser::WriteLocalNodeAttributes(xmlTextWriter* writerPtr,NetG //PLOG(PL_DETAIL,"ManetGraphMLParser::WriteLocalNodeAttributes():mykey=\"%s\",lookup=\"%s\",key=\"%s\",value=\"%s\"\n",key,attr->GetLookup(),attr->GetIndex(),attr->GetValue()); attr = NULL; //attr = it.GetNextItem(); - } - else + } + else { rv += xmlTextWriterStartElement(writerPtr, BAD_CAST "data"); rv += xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "key",BAD_CAST attr->GetIndex()); @@ -1657,12 +1665,12 @@ bool ManetGraphMLParser::WriteLocalAttributes(xmlTextWriter* writerPtr) PLOG(PL_DETAIL,"ManetGraphMLParser::WriteLocalAttributes: Enter\n"); bool rv = true; char key[255];//this should be dynamic or checks added TBD - sprintf(key,"thisGraph"); + snprintf(key,255, "thisGraph"); AttributeList::Iterator it(attributelist,false,key,strlen(key)*8); //AttributeList::Iterator it(attributelist); - + Attribute* attr(NULL); - + //iterate over items which have the matching keys attr = it.GetNextItem(); while(NULL != attr) @@ -1672,8 +1680,8 @@ bool ManetGraphMLParser::WriteLocalAttributes(xmlTextWriter* writerPtr) //PLOG(PL_DETAIL,"ManetGraphMLParser::WriteLocalAttributes():mykey=\"%s\",lookup=\"%s\",key=\"%s\",value=\"%s\"\n",key,attr->GetLookup(),attr->GetIndex(),attr->GetValue()); attr = NULL; //attr = it.GetNextItem(); - } - else + } + else { rv += xmlTextWriterStartElement(writerPtr, BAD_CAST "data"); rv += xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "key",BAD_CAST attr->GetIndex()); @@ -1690,8 +1698,8 @@ bool ManetGraphMLParser::WriteLocalInterfaceAttributes(xmlTextWriter* writerPtr, { bool rv = true; char key[255];//this should be dynamic or checks added TBD - sprintf(key,"node:%s",GetString(theInterface.GetNode())); - sprintf(key,"%s:port:%s",key,GetString(theInterface)); + snprintf(key,255, "node:%s",GetString(theInterface.GetNode())); + snprintf(key,255, "%s:port:%s",key,GetString(theInterface)); AttributeList::Iterator it(attributelist,false,key,strlen(key)*8); Attribute* attr(NULL); attr = it.GetNextItem(); @@ -1700,8 +1708,8 @@ bool ManetGraphMLParser::WriteLocalInterfaceAttributes(xmlTextWriter* writerPtr, if(strcmp(attr->GetLookup(),key)) { attr = NULL; - } - else + } + else { rv += xmlTextWriterStartElement(writerPtr, BAD_CAST "data"); rv += xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "key",BAD_CAST attr->GetIndex()); @@ -1718,11 +1726,11 @@ bool ManetGraphMLParser::WriteLocalLinkAttributes(xmlTextWriter* writerPtr,NetGr PLOG(PL_DETAIL,"ManetGraphMLParser::WriteLocalLinkAttributes()\n"); bool rv = true; char key[255];//this should be dynamic or checkes added TBD - sprintf(key,"edge:source:%s",GetString(theLink.GetSrc()->GetNode())); - sprintf(key,"%s:%s",key,GetString(*theLink.GetSrc())); - sprintf(key,"%s:dest:%s",key,GetString(theLink.GetDst()->GetNode())); - sprintf(key,"%s:%s",key,GetString(*theLink.GetDst())); - + snprintf(key,255, "edge:source:%s",GetString(theLink.GetSrc()->GetNode())); + snprintf(key,255, "%s:%s",key,GetString(*theLink.GetSrc())); + snprintf(key,255, "%s:dest:%s",key,GetString(theLink.GetDst()->GetNode())); + snprintf(key,255, "%s:%s",key,GetString(*theLink.GetDst())); + AttributeList::Iterator it(attributelist,false,key,strlen(key)*8); Attribute* attr(NULL); attr = it.GetNextItem(); @@ -1731,8 +1739,8 @@ bool ManetGraphMLParser::WriteLocalLinkAttributes(xmlTextWriter* writerPtr,NetGr if(strcmp(attr->GetLookup(),key)) { attr = NULL; - } - else + } + else { rv += xmlTextWriterStartElement(writerPtr, BAD_CAST "data"); rv += xmlTextWriterWriteAttribute(writerPtr, BAD_CAST "key",BAD_CAST attr->GetIndex()); diff --git a/src/python/protospace.cpp b/src/python/protospace.cpp index 2d35960..cb32575 100644 --- a/src/python/protospace.cpp +++ b/src/python/protospace.cpp @@ -5,7 +5,7 @@ #include "protopy.h" #include "protoSpace.h" -// This subclass of ProtoSpace::Node is used store reference +// This subclass of ProtoSpace::Node is used store reference // to a Python object (and its ordinates within the space) class SpaceNode : public ProtoSpace::Node { @@ -18,11 +18,11 @@ class SpaceNode : public ProtoSpace::Node ordinate_list = NULL; num_dimensions = 0; } - + PyObject* GetObject() {return py_node;} - + bool Init(unsigned int numDimensions) - { + { if (NULL != ordinate_list) delete[] ordinate_list; if (NULL == (ordinate_list = new double[numDimensions])) { @@ -32,7 +32,7 @@ class SpaceNode : public ProtoSpace::Node num_dimensions = numDimensions; return true; } - + void SetOrdinate(unsigned int dim, double value) {ordinate_list[dim] = value;} @@ -40,12 +40,12 @@ class SpaceNode : public ProtoSpace::Node {return num_dimensions;} double GetOrdinate(unsigned int dim) const {return dim < num_dimensions ? ordinate_list[dim] : 0.0;} - + private: PyObject* py_node; unsigned int num_dimensions; double* ordinate_list; - + }; // end class SpaceNode // Use ProtoTree to main map of Python object to SpaceNode entries @@ -54,25 +54,25 @@ class SpaceNode : public ProtoSpace::Node class SpaceItem : public ProtoTree::Item { public: - SpaceItem(PyObject* pyObj, SpaceNode& spaceNode) + SpaceItem(PyObject* pyObj, SpaceNode& spaceNode) : py_object(pyObj), space_node(spaceNode) { Py_INCREF(pyObj); } virtual ~SpaceItem() {Py_DECREF(py_object);} - + SpaceNode& GetNode() {return space_node;} - + const char* GetKey() const {return (const char*)&py_object;} unsigned int GetKeysize() const {return (unsigned int)sizeof(PyObject*) << 3;} - + private: PyObject* py_object; SpaceNode& space_node; - + }; // end class SpaceItem class SpaceItemTree : public ProtoTreeTemplate @@ -89,21 +89,21 @@ extern "C" { ProtoSpace* thisptr; SpaceItemTree item_tree; } Space; - + typedef struct { PyObject_HEAD ProtoSpace::Iterator* thisptr; PyObject* py_space; } SpaceIterator; - static void Space_dealloc(Space *self) + static void Space_dealloc(Space *self) { self->thisptr->Destroy(); // deletes all SpaceNodes held self->item_tree.Destroy(); Py_TYPE(self)->tp_free((PyObject*)self); } // end Space_dealloc() - static PyObject* Space_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + static PyObject* Space_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { Space *self = (Space*)type->tp_alloc(type, 0); if (self == NULL) @@ -111,8 +111,8 @@ extern "C" { self->thisptr = NULL; return (PyObject*)self; } // end Space_new() - - static int Space_init(Space *self, PyObject *args, PyObject *kwargs) + + static int Space_init(Space *self, PyObject *args, PyObject *kwargs) { if (NULL == (self->thisptr = new ProtoSpace())) { @@ -123,7 +123,7 @@ extern "C" { } // end Space_init() // Space_insert args (object, ordinate tuple - static PyObject* Space_insert(Space* self, PyObject* args) + static PyObject* Space_insert(Space* self, PyObject* args) { PyObject* pNode; PyObject* pList; @@ -133,7 +133,7 @@ extern "C" { PyErr_SetString(ProtoError, "Space ordinates must be provided as a list."); return NULL; } - + // Create SpaceNode that references Python object being inserted SpaceNode* spaceNode = new SpaceNode(pNode); if (NULL == spaceNode) @@ -143,7 +143,7 @@ extern "C" { return NULL; } // Init spaceNode with number of dimensions inferrred from list length - unsigned int numDimensions = PyList_Size(pList); + unsigned int numDimensions = PyList_Size(pList); if (!spaceNode->Init(numDimensions)) { // TBD - do I need to dereference pNode and plist here? @@ -151,10 +151,10 @@ extern "C" { delete spaceNode; return NULL; } - + // Iterate through list of provided ordinates PyObject* pItem; - for (unsigned int i=0; ipy_space) { @@ -293,7 +293,7 @@ extern "C" { Py_TYPE(self)->tp_free((PyObject*)self); } // end SpaceIterator_dealloc() - static PyObject* SpaceIterator_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) + static PyObject* SpaceIterator_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { SpaceIterator *self = (SpaceIterator*)type->tp_alloc(type, 0); if (self == NULL) @@ -303,11 +303,11 @@ extern "C" { return (PyObject*)self; } // end SpaceIterator_new() - static int SpaceIterator_init(SpaceIterator *self, PyObject *args) + static int SpaceIterator_init(SpaceIterator *self, PyObject *args) { PyObject* pSpace; PyObject* pList; // for iterator origin ordinate list - if (!PyArg_ParseTuple(args, "O!|O!", &SpaceType, &pSpace, &PyList_Type, &pList)) + if (!PyArg_ParseTuple(args, "O!|O!", &SpaceType, &pSpace, &PyList_Type, &pList)) { PyErr_SetString(ProtoError, "invalid argument"); return -1; @@ -317,20 +317,20 @@ extern "C" { PyErr_SetString(ProtoError, "new ProtoSpace::Iterator error"); return -1; } - + // Init space with number of dimensions inferrred from list length - unsigned int numDimensions = PyList_Size(pList); - + unsigned int numDimensions = PyList_Size(pList); + double* originOrdinates = (double*)malloc(numDimensions); if (NULL == originOrdinates) { PyErr_SetString(ProtoError, "new origin ordinates error"); return -1; } - + // Iterate through list of provided ordinates PyObject* pItem; - for (unsigned int i=0; ipy_space = pSpace; return 0; } // end SpaceIterator_init() - - static PyObject* SpaceIterator_next(PyObject* self) + + static PyObject* SpaceIterator_next(PyObject* self) { SpaceNode* next = (SpaceNode*)( ((SpaceIterator*)self)->thisptr->GetNextNode()); if (NULL == next) @@ -373,19 +373,19 @@ extern "C" { Py_INCREF(obj); return obj; } // end SpaceIterator_next() - - static PyObject* SpaceIterator_iter(PyObject* self) + + static PyObject* SpaceIterator_iter(PyObject* self) { Py_INCREF(self); return self; } // end SpaceIterator_iter() - - - static PyMethodDef SpaceIterator_methods[] = + + + static PyMethodDef SpaceIterator_methods[] = { {NULL} }; - + static PyTypeObject SpaceIteratorType = { PyVarObject_HEAD_INIT(NULL,0) /*ob_size*/ "protokit.Space.Iterator", /*tp_name*/ @@ -426,14 +426,14 @@ extern "C" { 0, /* tp_alloc */ SpaceIterator_new, /* tp_new */ }; - + static PyObject* Space_iterate(Space* self, PyObject* args) { // Allocate a new iterator SpaceIterator* iterator = PyObject_New(SpaceIterator, &SpaceIteratorType); if (iterator == NULL) return NULL; - + // Initialize it (using optional origin ordinates list, if provided) iterator->thisptr = new ProtoSpace::Iterator(*self->thisptr); if (NULL == iterator->thisptr) @@ -445,17 +445,17 @@ extern "C" { // SpaceIterator maintains reference to Space until destroyed iterator->py_space = (PyObject*)self; Py_INCREF((PyObject*)self); - + // Parse origin ordinate list, if provided PyObject* pList = NULL; - if (!PyArg_ParseTuple(args, "|O!", &PyList_Type, &pList)) + if (!PyArg_ParseTuple(args, "|O!", &PyList_Type, &pList)) { delete iterator->thisptr; Py_TYPE(iterator)->tp_free((PyObject*)iterator); PyErr_SetString(ProtoError, "Space.Iterator origin ordinates must be provided as a list."); return NULL; } - unsigned int numDimensions = (NULL != pList) ? PyList_Size(pList) : 0; + unsigned int numDimensions = (NULL != pList) ? PyList_Size(pList) : 0; double* originOrdinates = numDimensions ? new double[numDimensions] : NULL; if ((0 != numDimensions) && (NULL == originOrdinates)) { @@ -464,10 +464,10 @@ extern "C" { PyErr_SetString(ProtoError, "new origin ordinates error"); return NULL; } - + // Iterate through list of provided ordinates PyObject* pItem; - for (unsigned int i=0; i