From: Stephen Morris Date: Thu, 15 Mar 2012 17:24:25 +0000 (+0000) Subject: [1688] Add AbstractRRset::lthan() X-Git-Tag: trac2351_base~226^2~116^2~66^2~10^2~18 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c71fd9915c82c618d865780815bfec5aaf6c19a0;p=thirdparty%2Fkea.git [1688] Add AbstractRRset::lthan() Provides ordering needed for adding RRsets into a multiset for duplicate RRset removal. --- diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc index 9a55f5f55c..c517feab2e 100644 --- a/src/lib/dns/rrset.cc +++ b/src/lib/dns/rrset.cc @@ -123,6 +123,35 @@ AbstractRRset::isSameKind(const AbstractRRset& other) const { getClass() == other.getClass()); } +bool +AbstractRRset::lthan(const AbstractRRset& other) const { + + // Check on type first... + const uint16_t my_type = getType().getCode(); + const uint16_t other_type = other.getType().getCode(); + if (my_type < other_type) { + return (true); + + } else if (my_type == other_type) { + // Types equal, so check class + const uint16_t my_class = getClass().getCode(); + const uint16_t other_class = other.getClass().getCode(); + if (my_class < other_class) { + return (true); + + } else if (my_class == other_class) { + // Class equal, so check name + return (getName().lthan(other.getName())); + + } else { + return (false); + } + + } else { + return (false); + } +} + ostream& operator<<(ostream& os, const AbstractRRset& rrset) { os << rrset.toText(); diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h index 7ad555ff74..082e17db11 100644 --- a/src/lib/dns/rrset.h +++ b/src/lib/dns/rrset.h @@ -483,7 +483,29 @@ public: /// against. virtual bool isSameKind(const AbstractRRset& other) const; + /// \brief Check if one RRset is "less" than another + /// + /// This method is needed for storing RRsets in STL containers such + /// as multisets. It applies an ordering based on + /// - Type + /// - Class + /// - Name + /// (Type and Class are ordered by the values associated with those + /// constants. Name is ordered according to case-insensitive comparison.) + /// + /// Note that unlike isSameKind, type and class are checked before name. + /// This is because with ordering based on A, B and C (in that order), the + /// algorithm needs to do two checks on A and B - a "less than" check and a + /// check for equality. It only needs to do a "less than" check on C. + /// equality. It only needs to do one check on C, + /// + /// \param other The other AbstractRRset to compare against. + /// + /// \return true if "this" is less than the given RRset according to + /// the criteria given. + virtual bool lthan(const AbstractRRset& other) const; //@} + }; /// \brief The \c RdataIterator class is an abstract base class that diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc index a10b515339..9e0d5e91c6 100644 --- a/src/lib/dns/tests/rrset_unittest.cc +++ b/src/lib/dns/tests/rrset_unittest.cc @@ -13,6 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include #include @@ -126,6 +127,66 @@ TEST_F(RRsetTest, isSameKind) { EXPECT_FALSE(rrset_w.isSameKind(rrset_p)); } +// Utility function to create an add an RRset to a vector of RRsets for the +// "less" test. It's only purpose is to allow the RRset creation to be +// written with arguments in an order that reflects the RRset ordering. +void +addRRset(std::vector& vec, const RRType& rrtype, + const RRClass& rrclass, const char* rrname) +{ + vec.push_back(ConstRRsetPtr(new RRset(Name(rrname), rrclass, rrtype, + RRTTL(3600)))); +} + +TEST_F(RRsetTest, lthan) { + // Check values of type codes: this effectively documents the expected + // order of the rrsets created. + ASSERT_EQ(1, RRType::A().getCode()); + ASSERT_EQ(2, RRType::NS().getCode()); + + ASSERT_EQ(1, RRClass::IN().getCode()); + ASSERT_EQ(3, RRClass::CH().getCode()); + + // Create a vector of RRsets in ascending sort order. + std::vector rrsets; + addRRset(rrsets, RRType::A(), RRClass::IN(), "alpha.com"); + addRRset(rrsets, RRType::A(), RRClass::IN(), "beta.com"); + addRRset(rrsets, RRType::A(), RRClass::CH(), "alpha.com"); + addRRset(rrsets, RRType::A(), RRClass::CH(), "beta.com"); + addRRset(rrsets, RRType::NS(), RRClass::IN(), "alpha.com"); + addRRset(rrsets, RRType::NS(), RRClass::IN(), "beta.com"); + addRRset(rrsets, RRType::NS(), RRClass::CH(), "alpha.com"); + addRRset(rrsets, RRType::NS(), RRClass::CH(), "beta.com"); + + // ... and do the checks. The ASSERT_ form is used to avoid a plethora + // of messages if there is an error. And if there is an error, supply + // a more informative message. + for (int i = 0; i < rrsets.size(); ++i) { + // Check that an RRset is not less than itself + ostringstream ossi; + ossi << "i = (" + << rrsets[i]->getType().toText() << ", " + << rrsets[i]->getClass().toText() << ", " + << rrsets[i]->getName().toText() + << ")"; + ASSERT_FALSE(rrsets[i]->lthan(*rrsets[i])) << ossi.str(); + for (int j = i + 1; j < rrsets.size(); ++j) { + // Check it against the remaining RRsets. + ostringstream ossj; + ossj << ", j = (" + << rrsets[j]->getType().toText() << ", " + << rrsets[j]->getClass().toText() << ", " + << rrsets[j]->getName().toText() + << ")"; + ASSERT_TRUE(rrsets[i]->lthan(*rrsets[j])) + << ossi.str() << ossj.str(); + ASSERT_FALSE(rrsets[j]->lthan(*rrsets[i])) + << ossi.str() << ossj.str(); + } + } +} + + void addRdataTestCommon(const RRset& rrset) { EXPECT_EQ(2, rrset.getRdataCount());