Commit 6972f999 authored by Kirill Smelkov's avatar Kirill Smelkov

X xbtree/blib: RangedMap, RangedSet += IntersectsRange, Intersection

IntersectsRange is needed for one assert in concurrenct ΔBtail rebuild.
parent c4366b14
......@@ -359,6 +359,40 @@ func (M *RangedMap) HasRange(r KeyRange) (yes bool) {
}
}
// IntersectsRange returns whether some keys from range r belong to the map.
func (M *RangedMap) IntersectsRange(r KeyRange) (yes bool) {
if traceRangeMap {
fmt.Printf("\n\nIntersectsRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
M.verify()
if r.Empty() {
return false
}
// find first ilo: r.lo < [ilo].hi
l := len(M.entryv)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_
})
debugfRMap("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// [ilo].hi may be either inside r (≤ r.hi), or > r.hi
// - if it is inside -> overlap is there,
// - if it is > r.hi -> overlap is there if [ilo].lo < r.hi
// => in any case overlap is there if [ilo].lo < r.hi
return M.entryv[ilo].Lo <= r.Hi_
}
// --------
......
......@@ -38,14 +38,15 @@ const (
func TestRangedMap(t *testing.T) {
type testEntry struct {
M *RangedMap
X RangedMapEntry
Set *RangedMap // M.SetRange(X.keycov, X.value)
Del *RangedMap // M.DelRange(X.keycov)
Has bool // M.HasRange(X.keycov)
M *RangedMap
X RangedMapEntry
Set *RangedMap // M.SetRange(X.keycov, X.value)
Del *RangedMap // M.DelRange(X.keycov)
Has bool // M.HasRange(X.keycov)
Intersects bool // M.IntersectsRange(X.Keycov)
}
E := func(M *RangedMap, X RangedMapEntry, S, D *RangedMap, H bool) testEntry {
return testEntry{M, X, S, D, H}
E := func(M *RangedMap, X RangedMapEntry, S, D *RangedMap, H, I bool) testEntry {
return testEntry{M, X, S, D, H, I}
}
// M is shorthand to create RangedMap, e.g. M(1,2,a, 3,4,b) will return {[1,2):a [3,4):b}.
......@@ -101,7 +102,8 @@ func TestRangedMap(t *testing.T) {
X(0,0,x), // X
M(), // Set
M(), // Del
y), // Has
y, // Has
n), // Intersects
// empty vs !empty
E(
......@@ -109,7 +111,8 @@ func TestRangedMap(t *testing.T) {
X(1,2,x), // X
M(1,2,x), // Set
M(), // Del
n), // Has
n, // Has
n), // Intersects
// !empty vs empty
E(
......@@ -117,7 +120,8 @@ func TestRangedMap(t *testing.T) {
X(0,0,x), // X
M(1,2,a), // Set
M(1,2,a), // Del
y), // Has
y, // Has
n), // Intersects
// basic change
E(
......@@ -125,7 +129,8 @@ func TestRangedMap(t *testing.T) {
X(1,2,x), // X
M(1,2,x), // Set
M(), // Del
y), // Has
y, // Has
y), // Intersects
// adjacent [1,3) [3,5)
E(
......@@ -133,7 +138,8 @@ func TestRangedMap(t *testing.T) {
X(3,5,x), // X
M(1,3,a, 3,5,x), // Set
M(1,3,a), // Del
n), // Has
n, // Has
n), // Intersects
// overlapping [1,3) [2,4)
E(
......@@ -141,7 +147,8 @@ func TestRangedMap(t *testing.T) {
X(2,4,x), // X
M(1,2,a, 2,4,x), // Set
M(1,2,a), // Del
n), // Has
n, // Has
y), // Intersects
// [1,7) vs [3,5) -> split
E(
......@@ -149,7 +156,8 @@ func TestRangedMap(t *testing.T) {
X(3,5,x), // X
M(1,3,a, 3,5,x, 5,7,a), // Set
M(1,3,a, 5,7,a), // Del
y), // Has
y, // Has
y), // Intersects
// several ranges vs [-∞,∞)
E(
......@@ -157,14 +165,16 @@ func TestRangedMap(t *testing.T) {
X(noo,oo,x), // X
M(noo,oo,x), // Set
M(), // Del
n), // Has
n, // Has
y), // Intersects
E(
M(1,2,a, 2,3,b), // M
X(1,3,x), // X
M(1,3,x), // Set
M(), // Del
y), // Has
y, // Has
y), // Intersects
// coalesce (same value, no overlap)
E(
......@@ -172,7 +182,8 @@ func TestRangedMap(t *testing.T) {
X(2,4,a), // X
M(1,5,a), // Set
M(1,2,a, 4,5,a), // Del
n), // Has
n, // Has
n), // Intersects
// coalesce (same value, overlap)
E(
......@@ -180,7 +191,8 @@ func TestRangedMap(t *testing.T) {
X(2,6,a), // X
M(1,8,a), // Set
M(1,2,a, 6,8,a), // Del
n), // Has
n, // Has
y), // Intersects
// - shrink left/right (value !same) + new entry
E(
......@@ -188,19 +200,22 @@ func TestRangedMap(t *testing.T) {
X(2,6,x), // X
M(1,2,a, 2,6,x), // Set
M(1,2,a), // Del
n), // Has
n, // Has
y), // Intersects
E(
M(5,8,b), // M
X(2,6,x), // X
M(2,6,x, 6,8,b), // Set
M( 6,8,b), // Del
n), // Has
n, // Has
y), // Intersects
E(
M(1,4,a, 5,8,b), // M
X(2,6,x), // X
M(1,2,a, 2,6,x, 6,8,b), // Set
M(1,2,a, 6,8,b), // Del
n), // Has
M(1,2,a, 6,8,b), // Del
n, // Has
y), // Intersects
}
for _, tt := range testv {
......@@ -210,6 +225,7 @@ func TestRangedMap(t *testing.T) {
v := X.Value
assertMapHasRange(t, M, r, tt.Has)
assertMapIntersectsRange(t, M, r, tt.Intersects)
Mset := M.Clone()
Mdel := M.Clone()
Mset.SetRange(r, v)
......@@ -226,11 +242,9 @@ func TestRangedMap(t *testing.T) {
}
assertMapHasRange(t, Mset, r, true)
rInMdel := false
if r.Empty() {
rInMdel = true
}
assertMapHasRange(t, Mdel, r, rInMdel)
assertMapHasRange(t, Mdel, r, r.Empty())
assertMapIntersectsRange(t, Mset, r, !r.Empty())
assertMapIntersectsRange(t, Mdel, r, false)
verifyGet(t, M)
verifyGet(t, Mset)
......@@ -238,7 +252,7 @@ func TestRangedMap(t *testing.T) {
}
}
// assertMapHasRange asserts that RangeMap M.HasRange(r) == hasOK.
// assertMapHasRange asserts that RangedMap M.HasRange(r) == hasOK.
func assertMapHasRange(t *testing.T, M *RangedMap, r KeyRange, hasOK bool) {
t.Helper()
has := M.HasRange(r)
......@@ -247,6 +261,15 @@ func assertMapHasRange(t *testing.T, M *RangedMap, r KeyRange, hasOK bool) {
}
}
// assertMapIntersectsRange asserts that RangedMap M.IntersectsRange(r) == intersectsOK.
func assertMapIntersectsRange(t *testing.T, M *RangedMap, r KeyRange, intersectsOK bool) {
t.Helper()
intersects := M.IntersectsRange(r)
if !(intersects == intersectsOK) {
t.Errorf("IntersectsRange:\n M: %s\n r: %s\n ->·: %t\n ok·: %t\n", M, r, intersects, intersectsOK)
}
}
// verifyGet verifies RangedMap.Get .
func verifyGet(t *testing.T, M *RangedMap) {
t.Helper()
......
......@@ -63,10 +63,15 @@ func (S *RangedKeySet) DelRange(r KeyRange) {
}
// HasRange returns whether all keys from range r belong to the set.
func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) {
func (S *RangedKeySet) HasRange(r KeyRange) bool {
return S.m.HasRange(r)
}
// IntersectsRange returns whether some keys from range r belong to the set.
func (S *RangedKeySet) IntersectsRange(r KeyRange) bool {
return S.m.IntersectsRange(r)
}
// Union returns RangedKeySet(A.keys | B.keys).
func (A *RangedKeySet) Union(B *RangedKeySet) *RangedKeySet {
......@@ -82,7 +87,12 @@ func (A *RangedKeySet) Difference(B *RangedKeySet) *RangedKeySet {
return D
}
// TODO Intersection
// Intersection returns RangedKeySet(A.keys ^ B.keys).
func (A *RangedKeySet) Intersection(B *RangedKeySet) *RangedKeySet {
I := A.Clone()
I.IntersectionInplace(B)
return I
}
func (A *RangedKeySet) UnionInplace(B *RangedKeySet) {
A.verify()
......@@ -109,6 +119,21 @@ func (A *RangedKeySet) DifferenceInplace(B *RangedKeySet) {
}
}
func (A *RangedKeySet) IntersectionInplace(B *RangedKeySet) {
A.verify()
B.verify()
defer A.verify()
// XXX very dumb
// A^B = (A∪B) \ (A\B ∪ B\A)
AdB := A.Difference(B)
BdA := B.Difference(A)
ddd := AdB
ddd.UnionInplace(BdA)
A.UnionInplace(B)
A.DifferenceInplace(ddd)
}
// --------
......@@ -152,6 +177,6 @@ func (S *RangedKeySet) AllRanges() /*readonly*/[]KeyRange {
}
func (S RangedKeySet) String() string {
// RangeMap<void> supports formatting for set out of the box
// RangedMap<void> supports formatting for set out of the box
return S.m.String()
}
......@@ -44,12 +44,13 @@ func TestRangedKeySetTypes(t *testing.T) {
func TestRangedKeySet(t *testing.T) {
type testEntry struct {
A, B *RangedKeySet
Union *RangedKeySet
Difference *RangedKeySet
A, B *RangedKeySet
Union *RangedKeySet
Difference *RangedKeySet
Intersection *RangedKeySet
}
E := func(A, B, U, D *RangedKeySet) testEntry {
return testEntry{A, B, U, D}
E := func(A, B, U, D, I *RangedKeySet) testEntry {
return testEntry{A, B, U, D, I}
}
// S is shorthand to create RangedKeySet, e.g. S(1,2, 4,5) will return {[1,2) [4,5)}
......@@ -81,68 +82,78 @@ func TestRangedKeySet(t *testing.T) {
S(), // A
S(), // B
S(), // U
S()), // D
S(), // D
S()), // I
E(
S(), // A
S(1,2), // B
S(1,2), // U
S()), // D
S(), // D
S()), // I
E(
S(1,2), // A
S(), // B
S(1,2), // U
S(1,2)),// D
S(1,2), // D
S()), // I
E(
S(1,2), // A
S(1,2), // B
S(1,2), // U
S()), // D
S(), // D
S(1,2)),// I
// adjacent [1,3) [3,5)
E(
S(1,3), // A
S(3,5), // B
S(1,5), // U
S(1,3)), // D
S(1,5), // U
S(1,3), // D
S()), // I
// overlapping [1,3) [2,4)
E(
S(1,3), // A
S(2,4), // B
S(1,4), // U
S(1,2)), // D
S(1,4), // U
S(1,2), // D
S(2,3)),// I
// [1,7) \ [3,5) -> [1,3) [5,7)
E(
S(1,7), // A
S(3,5), // B
S(1,7),
S(1,3, 5,7)),
S(1,7), // U
S(1,3, 5,7), // D
S(3,5)), // I
// several ranges \ [-∞,∞) -> ø
E(
S(1,3, 5,7, 11,100), // A
S(noo, oo), // B
S(noo, oo), // U
S()), // D
S(noo, oo), // U
S(), // D
S(1,3, 5,7, 11,100)), // I
// [1,3) [5,7) + insert [3,5) -> [1,7)
E(
S(1,3, 5,7), // A
S(3,5), // B
S(1,7), // U
S(1,3, 5,7)), // D
S(1,3, 5,7), // D
S()), // I
// delete covering several ranges
// [-1,0) [1,3) [5,7) [9,11) [15,20) [100,200) \ [2,17)
E(
S(-1,0, 1,3, 5,7, 9,11, 15,20, 100,200), // A
S(2,17), // B
S(-1,0, 1,3, 5,7, 9,11, 15,20, 100,200),// A
S(2,17), // B
S(-1,0, 1,20, 100,200), // U
S(-1,0, 1,2, 17,20, 100,200)), // D
S(-1,0, 1,2, 17,20, 100,200), // D
S(2,3, 5,7, 9,11, 15,17)), // I
}
for _, tt := range testv {
......@@ -150,6 +161,7 @@ func TestRangedKeySet(t *testing.T) {
B := tt.B
U := A.Union(B)
D := A.Difference(B)
I := A.Intersection(B)
if !U.Equal(tt.Union) {
t.Errorf("Union:\n A: %s\n B: %s\n ->u: %s\n okU: %s\n", A, B, U, tt.Union)
......@@ -157,12 +169,18 @@ func TestRangedKeySet(t *testing.T) {
if !D.Equal(tt.Difference) {
t.Errorf("Difference:\n A: %s\n B: %s\n ->d: %s\n okD: %s\n", A, B, D, tt.Difference)
}
if !I.Equal(tt.Intersection) {
t.Errorf("Intersection:\n A: %s\n B: %s\n ->i: %s\n okI: %s\n", A, B, I, tt.Intersection)
}
// HasRange
assertSetHasRanges(t, A, A.AllRanges(), true)
assertSetHasRanges(t, B, B.AllRanges(), true)
assertSetHasRanges(t, U, A.AllRanges(), true)
assertSetHasRanges(t, U, B.AllRanges(), true)
assertSetHasRanges(t, A, I.AllRanges(), true)
assertSetHasRanges(t, B, I.AllRanges(), true)
assertSetHasRanges(t, U, I.AllRanges(), true)
Dab := D
Dba := B.Difference(A)
......@@ -170,6 +188,20 @@ func TestRangedKeySet(t *testing.T) {
assertSetHasRanges(t, B, Dab.AllRanges(), false)
assertSetHasRanges(t, B, Dba.AllRanges(), true)
assertSetHasRanges(t, A, Dba.AllRanges(), false)
assertSetHasRanges(t, Dab, I.AllRanges(), false)
assertSetHasRanges(t, Dba, I.AllRanges(), false)
assertSetHasRanges(t, I, Dab.AllRanges(), false)
assertSetHasRanges(t, I, Dba.AllRanges(), false)
// IntersectsRange (= (A^B)!=ø)
assertSetIntersectsRanges(t, A, I.AllRanges(), !I.Empty())
assertSetIntersectsRanges(t, B, I.AllRanges(), !I.Empty())
assertSetIntersectsRanges(t, Dab, B.AllRanges(), false)
assertSetIntersectsRanges(t, Dba, A.AllRanges(), false)
assertSetIntersectsRanges(t, Dab, I.AllRanges(), false)
assertSetIntersectsRanges(t, Dba, I.AllRanges(), false)
assertSetIntersectsRanges(t, I, Dab.AllRanges(), false)
assertSetIntersectsRanges(t, I, Dba.AllRanges(), false)
}
}
......@@ -183,3 +215,14 @@ func assertSetHasRanges(t *testing.T, S *RangedKeySet, rangev []KeyRange, hasOK
}
}
}
// assertSetIntersectsRanges asserts for all ranges from rangev that RangedSet S.IntersectsRange(r) == intersectsOK.
func assertSetIntersectsRanges(t *testing.T, S *RangedKeySet, rangev []KeyRange, intersectsOK bool) {
t.Helper()
for _, r := range rangev {
intersects := S.IntersectsRange(r)
if intersects != intersectsOK {
t.Errorf("IntersectsRange:\n S: %s\n r: %s\n ->: %v\n ok: %v\n", S, r, intersects, intersectsOK)
}
}
}
......@@ -361,6 +361,40 @@ func (M *_RangedMap_str) HasRange(r KeyRange) (yes bool) {
}
}
// IntersectsRange returns whether some keys from range r belong to the map.
func (M *_RangedMap_str) IntersectsRange(r KeyRange) (yes bool) {
if trace_RangedMap_str {
fmt.Printf("\n\nIntersectsRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
M.verify()
if r.Empty() {
return false
}
// find first ilo: r.lo < [ilo].hi
l := len(M.entryv)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_
})
debugf_RangedMap_str("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// [ilo].hi may be either inside r (≤ r.hi), or > r.hi
// - if it is inside -> overlap is there,
// - if it is > r.hi -> overlap is there if [ilo].lo < r.hi
// => in any case overlap is there if [ilo].lo < r.hi
return M.entryv[ilo].Lo <= r.Hi_
}
// --------
......
......@@ -361,6 +361,40 @@ func (M *_RangedMap_void) HasRange(r KeyRange) (yes bool) {
}
}
// IntersectsRange returns whether some keys from range r belong to the map.
func (M *_RangedMap_void) IntersectsRange(r KeyRange) (yes bool) {
if trace_RangedMap_void {
fmt.Printf("\n\nIntersectsRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
M.verify()
if r.Empty() {
return false
}
// find first ilo: r.lo < [ilo].hi
l := len(M.entryv)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_
})
debugf_RangedMap_void("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// [ilo].hi may be either inside r (≤ r.hi), or > r.hi
// - if it is inside -> overlap is there,
// - if it is > r.hi -> overlap is there if [ilo].lo < r.hi
// => in any case overlap is there if [ilo].lo < r.hi
return M.entryv[ilo].Lo <= r.Hi_
}
// --------
......
......@@ -364,6 +364,40 @@ func (M *_RangedMap_RebuildJob) HasRange(r blib.KeyRange) (yes bool) {
}
}
// IntersectsRange returns whether some keys from range r belong to the map.
func (M *_RangedMap_RebuildJob) IntersectsRange(r blib.KeyRange) (yes bool) {
if trace_RangedMap_RebuildJob {
fmt.Printf("\n\nIntersectsRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
M.verify()
if r.Empty() {
return false
}
// find first ilo: r.lo < [ilo].hi
l := len(M.entryv)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_
})
debugf_RangedMap_RebuildJob("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// [ilo].hi may be either inside r (≤ r.hi), or > r.hi
// - if it is inside -> overlap is there,
// - if it is > r.hi -> overlap is there if [ilo].lo < r.hi
// => in any case overlap is there if [ilo].lo < r.hi
return M.entryv[ilo].Lo <= r.Hi_
}
// --------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment