This is an automated email from the ASF dual-hosted git repository.

maplefu pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 1e23484f Optimize the implementation of IntervalSet intersection 
(#2300)
1e23484f is described below

commit 1e23484fbd88a7169859e66f398dd695fdf36128
Author: detached <[email protected]>
AuthorDate: Sat May 11 15:58:26 2024 +0800

    Optimize the implementation of IntervalSet intersection (#2300)
    
    Co-authored-by: mwish <[email protected]>
    Co-authored-by: Twice <[email protected]>
---
 src/cluster/redis_slot.cc      |  2 --
 src/search/interval.h          | 27 ++++++++++++++++++++++++---
 tests/cppunit/interval_test.cc | 26 +++++++++++++++++++++++---
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/src/cluster/redis_slot.cc b/src/cluster/redis_slot.cc
index 5934fd2d..991b5d86 100644
--- a/src/cluster/redis_slot.cc
+++ b/src/cluster/redis_slot.cc
@@ -20,8 +20,6 @@
 
 #include "redis_slot.h"
 
-#include <stdlib.h>
-
 #include <algorithm>
 #include <cstdlib>
 #include <string>
diff --git a/src/search/interval.h b/src/search/interval.h
index 5ce90a45..efe462b4 100644
--- a/src/search/interval.h
+++ b/src/search/interval.h
@@ -128,11 +128,32 @@ struct IntervalSet {
   }
 
   friend IntervalSet operator&(const IntervalSet &l, const IntervalSet &r) {
-    if (l.IsEmpty() || r.IsEmpty()) {
-      return IntervalSet();
+    IntervalSet result;
+
+    if (l.intervals.empty() || r.intervals.empty()) {
+      return result;
+    }
+
+    auto it_l = l.intervals.begin();
+    auto it_r = r.intervals.begin();
+
+    while (it_l != l.intervals.end() && it_r != r.intervals.end()) {
+      // Find overlap between current intervals
+      double start = std::max(it_l->first, it_r->first);
+      double end = std::min(it_l->second, it_r->second);
+
+      if (start <= end) {
+        result.intervals.emplace_back(start, end);
+      }
+
+      if (it_l->second < it_r->second) {
+        ++it_l;
+      } else {
+        ++it_r;
+      }
     }
 
-    return ~(~l | ~r);
+    return result;
   }
 
   friend IntervalSet operator|(const IntervalSet &l, const IntervalSet &r) {
diff --git a/tests/cppunit/interval_test.cc b/tests/cppunit/interval_test.cc
index 5090c4c8..bffd5d63 100644
--- a/tests/cppunit/interval_test.cc
+++ b/tests/cppunit/interval_test.cc
@@ -48,6 +48,14 @@ TEST(IntervalSet, Simple) {
             (IntervalSet::DataType{{IntervalSet::minf, 1}, {4, 
IntervalSet::inf}}));
   ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 4) | 
IntervalSet(NumericCompareExpr::NE, 1)).intervals,
             (IntervalSet::DataType{{IntervalSet::minf, 1}, 
{IntervalSet::NextNum(1), IntervalSet::inf}}));
+
+  ASSERT_TRUE((IntervalSet(Interval(1, 2)) & IntervalSet(Interval(3, 
4))).IsEmpty());
+  ASSERT_EQ((IntervalSet(Interval(1, 2)) & IntervalSet(Interval(2, 
4))).intervals, (IntervalSet::DataType{{2, 2}}));
+  ASSERT_EQ((IntervalSet(Interval(1, 3)) & IntervalSet(Interval(2, 
4))).intervals, (IntervalSet::DataType{{2, 3}}));
+  ASSERT_EQ((IntervalSet(Interval(3, 8)) & (IntervalSet(Interval(1, 4)) | 
IntervalSet(Interval(5, 7)))).intervals,
+            (IntervalSet::DataType{{3, 4}, {5, 7}}));
+  ASSERT_EQ((IntervalSet(Interval(3, 8)) & (IntervalSet(Interval(1, 4)) | 
IntervalSet(Interval(9, 11)))).intervals,
+            (IntervalSet::DataType{{3, 4}}));
   ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 1) & 
IntervalSet(NumericCompareExpr::LT, 4)).intervals,
             (IntervalSet::DataType{{1, 4}}));
   ASSERT_EQ((IntervalSet(NumericCompareExpr::GET, 1) & 
IntervalSet(NumericCompareExpr::NE, 4)).intervals,
@@ -60,9 +68,21 @@ TEST(IntervalSet, Simple) {
             IntervalSet({2, 5}) | IntervalSet({7, 8}));
   ASSERT_EQ(~IntervalSet({2, 8}), IntervalSet({IntervalSet::minf, 2}) | 
IntervalSet({8, IntervalSet::inf}));
 
-  for (auto i = 0; i < 1000; ++i) {
-    auto gen = [] { return static_cast<double>(rand()) / 100; };
-    auto geni = [&gen] { return IntervalSet({gen(), gen()}); };
+  for (auto i = 0; i < 2000; ++i) {
+    auto gen = [] { return static_cast<double>(std::rand()) / 100; };
+    auto geni = [&gen] {
+      auto r = std::rand() % 50;
+      if (r == 0) {
+        return IntervalSet(NumericCompareExpr::GET, gen());
+      } else if (r == 1) {
+        return IntervalSet(NumericCompareExpr::LT, gen());
+      } else if (r == 2) {
+        return IntervalSet(NumericCompareExpr::NE, gen());
+      } else {
+        return IntervalSet({gen(), gen()});
+      }
+    };
+
     auto l = geni(), r = geni();
     for (int j = 0; j < i % 10; ++j) {
       l = l | geni();

Reply via email to