]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3770] Add hashing to CfgOption
authorThomas Markwalder <tmark@isc.org>
Wed, 23 Jul 2025 17:29:27 +0000 (13:29 -0400)
committerThomas Markwalder <tmark@isc.org>
Wed, 23 Jul 2025 17:29:27 +0000 (13:29 -0400)
modified:   src/lib/dhcp/classify.cc
modified:   src/lib/dhcp/classify.h
modified:   src/lib/dhcp/tests/classify_unittest.cc
modified:   src/lib/dhcpsrv/cfg_option.h

src/lib/dhcp/classify.cc
src/lib/dhcp/classify.h
src/lib/dhcp/tests/classify_unittest.cc
src/lib/dhcpsrv/cfg_option.h

index 5021ef1005c328b7925a1bfad0f7225099f649eb..543b81d99f38284ab1f25411a81c04ebb7e18aa7 100644 (file)
@@ -121,7 +121,7 @@ ClientClasses::fromElement(isc::data::ConstElementPtr cc_list) {
 
 bool
 ClientClasses::equals(const ClientClasses& other) const {
- return ((size() == other.size()) && std::equal(cbegin(), cend(), other.cbegin()));
   return ((size() == other.size()) && std::equal(cbegin(), cend(), other.cbegin()));
 }
 
 ClientClasses&
@@ -134,5 +134,14 @@ ClientClasses::operator=(const ClientClasses& other) {
     return (*this);
 }
 
-} // end of namespace isc::dhcp
-} // end of namespace isc
+size_t
+ClientClasses::Hash::operator()(const ClientClasses &client_classes) {
+    return (hash_value(client_classes));
+}
+
+size_t hash_value(const ClientClasses& client_classes) {
+    boost::hash<std::string> hasher;
+    return (hasher(client_classes.toText("")));
+}
+
+}} // end of namespace isc
index 9e60e24393c684c18998632dfc83f26cfe06a818..645a65eab019567e6467f598eb92cb20f6f22c48 100644 (file)
@@ -18,6 +18,7 @@
 #include <boost/multi_index/sequenced_index.hpp>
 
 #include <string>
+#include <functional>
 
 /// @file   classify.h
 ///
@@ -250,11 +251,32 @@ public:
     /// are invalid
     void fromElement(isc::data::ConstElementPtr list);
 
+    /// @brief Hash enabling use in the unordered containers.
+    struct Hash {
+        /// @brief A hashing operator.
+        ///
+        /// @param client_classes ClientClasses instance to be hashed.
+        /// \return a hashing result.
+        size_t operator()(const ClientClasses& client_classes);
+    };
+
 private:
     /// @brief container part
     ClientClassContainer container_;
 };
 
+/// @brief Hash a ClientClasses instance.
+///
+/// This method allows boost multi-index hashed indexes on ClientClasses.
+/// It follows the requirement with equality: if two class lists are equal
+/// their hashes are equal, if two class lists are not equal their hashes
+/// are almost surely not equal.
+///
+/// @param address A @c ClientClasses to hash.
+/// @return The hash of the ClientClasses.
+
+size_t hash_value(const ClientClasses& client_classes);
+
 /// @brief Smart pointer to ClientClasses object.
 typedef boost::shared_ptr<ClientClasses> ClientClassesPtr;
 
index f635817e637014fcb4e3cd9bb5b6d2674af1afd8..64c68064fe694c57a1dbd1aaff6e2782e3ba64eb 100644 (file)
@@ -11,6 +11,7 @@
 #include <testutils/gtest_utils.h>
 
 #include <gtest/gtest.h>
+#include <unordered_set>
 
 using namespace isc;
 using namespace isc::dhcp;
@@ -291,3 +292,40 @@ TEST(ClassifyTest, ClientClassesIntersects) {
     EXPECT_TRUE(classes1.intersects(classes2));
     EXPECT_TRUE(classes2.intersects(classes1));
 }
+
+TEST(ClassifyTest, ClientClassesHash) {
+    // Add hashes for different contents to a set.
+    ClientClasses::Hash hash;
+    std::unordered_set<size_t> results;
+
+    ClientClasses cclasses;
+    results.insert(hash(cclasses));
+
+    cclasses.insert("one");
+    results.insert(hash(cclasses));
+
+    cclasses.insert("two");
+    results.insert(hash(cclasses));
+
+    cclasses.insert("three");
+    results.insert(hash(cclasses));
+
+    // Should have all four entries.
+    EXPECT_EQ(4, results.size());
+
+    // Check that empty containers make equal hashes.
+    ClientClasses empty1;
+    ClientClasses empty2;
+    EXPECT_EQ(hash(empty1), hash(empty2));
+
+    // Check that equal containers make equal hashes.
+    ClientClasses cclasses2(cclasses);
+    EXPECT_EQ(hash(cclasses2), hash(cclasses));
+
+    // Check that different ordering make not equal hashes.
+    ClientClasses cclasses3;
+    cclasses3.insert("three");
+    cclasses3.insert("two");
+    cclasses3.insert("one");
+    EXPECT_NE(hash(cclasses3), hash(cclasses));
+}
index 9c8ef0f75a6c69bf6954fe226a9394cca5664e92..aefef982ece106fc0b3bad7f8e17c8f6e8183a71 100644 (file)
@@ -342,6 +342,7 @@ typedef boost::multi_index_container<
                                            ClientClasses,
                                            &OptionDescriptor::client_classes_>
             >
+
         >
     >
 > OptionContainer;