Commit cf3511fb authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 41045c0b
...@@ -37,6 +37,17 @@ func (r *KeyRange) Has(k Key) bool { ...@@ -37,6 +37,17 @@ func (r *KeyRange) Has(k Key) bool {
return (r.Lo <= k && k <= r.Hi_) return (r.Lo <= k && k <= r.Hi_)
} }
// Empty returns whether key range is empty.
func (r *KeyRange) Empty() bool {
hi := r.Hi_
if hi == KeyMax {
// [x,∞] cannot be empty because max x is ∞ and [∞,∞] has one element: ∞
return false
}
hi++ // no overflow
return r.Lo >= hi
}
func (r KeyRange) String() string { func (r KeyRange) String() string {
var shi string var shi string
......
...@@ -25,8 +25,8 @@ import ( ...@@ -25,8 +25,8 @@ import (
"sort" "sort"
) )
const traceRangeMap = false const traceRangeMap = true
const debugRangeMap = false const debugRangeMap = true
// RangedMap is Key->VALUE map with adjacent keys mapped to the same value coalesced into Ranges. // RangedMap is Key->VALUE map with adjacent keys mapped to the same value coalesced into Ranges.
// //
...@@ -115,6 +115,10 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) { ...@@ -115,6 +115,10 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) {
M.verify() M.verify()
defer M.verify() defer M.verify()
if r.Empty() {
return // XXX or panic?
}
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for same-value/set case (just merge all covered // TODO optimize for same-value/set case (just merge all covered
// entries into one - - see commented AddRange from set vvv) // entries into one - - see commented AddRange from set vvv)
...@@ -367,7 +371,7 @@ func (M *RangedMap) verify() { ...@@ -367,7 +371,7 @@ func (M *RangedMap) verify() {
for _, bad := range badv { for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad) emsg += fmt.Sprintf("- %s\n", bad)
} }
emsg += fmt.Sprintf("\nS: %s\n", M) emsg += fmt.Sprintf("\nM: %s\n", M)
panic(emsg) panic(emsg)
} }
}() }()
......
...@@ -38,14 +38,14 @@ const ( ...@@ -38,14 +38,14 @@ const (
func TestRangedMap(t *testing.T) { func TestRangedMap(t *testing.T) {
type testEntry struct { type testEntry struct {
A *RangedMap M *RangedMap
B RangedMapEntry X RangedMapEntry
Set *RangedMap // A.SetRange(B.keycov, B.value) Set *RangedMap // M.SetRange(X.keycov, X.value)
Del *RangedMap // A.DelRange(B.keycov) Del *RangedMap // M.DelRange(X.keycov)
Has bool // A.HasRange(B.keycov) Has bool // M.HasRange(X.keycov)
} }
E := func(A *RangedMap, B RangedMapEntry, S, D *RangedMap, H bool) testEntry { E := func(M *RangedMap, X RangedMapEntry, S, D *RangedMap, H bool) testEntry {
return testEntry{A, B, S, D, H} return testEntry{M, X, S, D, H}
} }
// M is shorthand to create RangedMap, e.g. M(1,2,a, 3,4,b) will return {[1,2):a [3,4):b}. // M is shorthand to create RangedMap, e.g. M(1,2,a, 3,4,b) will return {[1,2):a [3,4):b}.
...@@ -54,7 +54,7 @@ func TestRangedMap(t *testing.T) { ...@@ -54,7 +54,7 @@ func TestRangedMap(t *testing.T) {
if l % 3 != 0 { if l % 3 != 0 {
panic("non 3x number of arguments") panic("non 3x number of arguments")
} }
// askey converts arg to Key // asKey converts arg to Key
asKey := func(arg interface{}) Key { asKey := func(arg interface{}) Key {
// go through reflect to accept all int, int64, Key, ... // go through reflect to accept all int, int64, Key, ...
return Key(reflect.ValueOf(arg).Int()) return Key(reflect.ValueOf(arg).Int())
...@@ -78,8 +78,8 @@ func TestRangedMap(t *testing.T) { ...@@ -78,8 +78,8 @@ func TestRangedMap(t *testing.T) {
return M return M
} }
// K creates RangedMapEntry{v, [lo,hi)} // X creates RangedMapEntry{v, [lo,hi)}
K := func(lo,hi Key, v string) RangedMapEntry { X := func(lo,hi Key, v string) RangedMapEntry {
hi_ := hi hi_ := hi
if hi_ != noo { if hi_ != noo {
hi_-- hi_--
...@@ -95,78 +95,142 @@ func TestRangedMap(t *testing.T) { ...@@ -95,78 +95,142 @@ func TestRangedMap(t *testing.T) {
testv := []testEntry{ testv := []testEntry{
// empty vs empty
E( E(
M(1,2,a, 2,3,b), // A M(), // M
K(1,3,x), // B X(0,0,x), // X
M(), // Set
M(), // Del
n), // Has
// empty vs !empty
E(
M(), // M
X(1,2,x), // X
M(1,2,x), // Set
M(), // Del
n), // Has
// !empty vs empty
E(
M(1,2,a), // M
X(0,0,x), // X
M(1,2,a), // Set
M(1,2,a), // Del
y), // Has XXX ok
// basic change
E(
M(1,2,a), // M
X(1,2,x), // X
M(1,2,x), // Set
M(), // Del
y), // Has
// adjacent [1,3) [3,5)
E(
M(1,3,a), // M
X(3,5,x), // X
M(1,3,a, 3,5,x), // Set
M(1,3,a), // Del
n), // Has
// overlappin [1,3) [2,4)
E(
M(1,3,a), // M
X(2,4,x), // X
M(1,2,a, 2,4,x), // Set
M(1,2,a), // Del
n), // Has
// [1,7) vs [3,5) -> split
E(
M(1,7,a), // M
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
// several ranges vs [-∞,∞)
E(
M(1,3,a, 5,7,b, 8,9,c), // M
X(noo,oo,x), // X
M(noo,oo,x), // Set
M(), // Del
n), // Has
E(
M(1,2,a, 2,3,b), // M
X(1,3,x), // X
M(1,3,x), // Set M(1,3,x), // Set
M(), // Del M(), // Del
y), // Has y), // Has
// coalesce (same value, no overlap) // coalesce (same value, no overlap)
E( E(
M(1,2,a, 4,5,a), // A M(1,2,a, 4,5,a), // M
K(2,4,a), // B X(2,4,a), // X
M(1,5,a), // Set M(1,5,a), // Set
M(1,2,a, 4,5,a), // Del M(1,2,a, 4,5,a), // Del
n), // Has n), // Has
// coalesce (same value, overlap) // coalesce (same value, overlap)
E( E(
M(1,4,a, 5,8,a), // A M(1,4,a, 5,8,a), // M
K(2,6,a), // B X(2,6,a), // X
M(1,8,a), // Set M(1,8,a), // Set
M(1,2,a, 6,8,a), // Del M(1,2,a, 6,8,a), // Del
n), // Has n), // Has
// - shrink left/right (value !same) + new entry // - shrink left/right (value !same) + new entry
E( E(
M(1,4,a), // A M(1,4,a), // M
K(2,6,x), // B X(2,6,x), // X
M(1,2,a, 2,6,x), // Set M(1,2,a, 2,6,x), // Set
M(1,2,a), // Del M(1,2,a), // Del
n), // Has n), // Has
E( E(
M(5,8,b), // A M(5,8,b), // M
K(2,6,x), // B X(2,6,x), // X
M(2,6,x, 6,8,b), // Set M(2,6,x, 6,8,b), // Set
M( 6,8,b), // Del M( 6,8,b), // Del
n), // Has n), // Has
E( E(
M(1,4,a, 5,8,b), // A M(1,4,a, 5,8,b), // M
K(2,6,x), // B X(2,6,x), // X
M(1,2,a, 2,6,x, 6,8,b), // Set M(1,2,a, 2,6,x, 6,8,b), // Set
M(1,2,a, 6,8,b), // Del M(1,2,a, 6,8,b), // Del
n), // Has n), // Has
} }
for _, tt := range testv { for _, tt := range testv {
A := tt.A M := tt.M
B := tt.B X := tt.X
r := B.KeyRange r := X.KeyRange
v := B.Value v := X.Value
assertMapHasRange(t, A, r, tt.Has) assertMapHasRange(t, M, r, tt.Has)
Aset := A.Clone() Mset := M.Clone()
Adel := A.Clone() Mdel := M.Clone()
Aset.SetRange(r, v) Mset.SetRange(r, v)
Adel.DelRange(r) Mdel.DelRange(r)
if !Aset.Equal(tt.Set) { if !Mset.Equal(tt.Set) {
t.Errorf("SetRange:\n A: %s\n e: %s\n ->·: %s\n ok·: %s\n", A, B, Aset, tt.Set) t.Errorf("SetRange:\n M: %s\n e: %s\n ->·: %s\n ok·: %s\n", M, X, Mset, tt.Set)
} }
if !Adel.Equal(tt.Del) { if !Mdel.Equal(tt.Del) {
t.Errorf("DelRange:\n A: %s\n r: %s\n ->·: %s\n ok·: %s\n", A, r, Adel, tt.Del) t.Errorf("DelRange:\n M: %s\n r: %s\n ->·: %s\n ok·: %s\n", M, r, Mdel, tt.Del)
} }
assertMapHasRange(t, Aset, r, true) assertMapHasRange(t, Mset, r, true)
assertMapHasRange(t, Adel, r, false) assertMapHasRange(t, Mdel, r, false)
verifyGet(t, A) verifyGet(t, M)
verifyGet(t, Aset) verifyGet(t, Mset)
verifyGet(t, Adel) verifyGet(t, Mdel)
} }
} }
...@@ -187,8 +251,11 @@ func verifyGet(t *testing.T, M *RangedMap) { ...@@ -187,8 +251,11 @@ func verifyGet(t *testing.T, M *RangedMap) {
Mranges = append(Mranges, M.AllRanges()...) // copy just in case it changes on Get Mranges = append(Mranges, M.AllRanges()...) // copy just in case it changes on Get
// verify "has-data" // verify "has-data"
Z := KeyRange{-100,+100} // models [-∞,∞)
for _, e := range Mranges { for _, e := range Mranges {
for k := e.Lo; k <= e.Hi_; k++ { lo := kmax(e.Lo, Z.Lo)
hi_ := kmin(e.Hi_, Z.Hi_)
for k := lo; k <= hi_; k++ {
v, ok := M.Get_(k) v, ok := M.Get_(k)
if !(v == e.Value && ok) { if !(v == e.Value && ok) {
t.Errorf("%s\tGet(%s):\nhave: %q, %t\nwant: %q, true", t.Errorf("%s\tGet(%s):\nhave: %q, %t\nwant: %q, true",
...@@ -200,13 +267,15 @@ func verifyGet(t *testing.T, M *RangedMap) { ...@@ -200,13 +267,15 @@ func verifyGet(t *testing.T, M *RangedMap) {
// verify "no-data" // verify "no-data"
// NA = [-∞,∞) \ M // NA = [-∞,∞) \ M
na := RangedKeySet{} na := RangedKeySet{}
na.AddRange(KeyRange{-10,+10}) // models -∞,∞ na.AddRange(Z)
for _, e := range Mranges { for _, e := range Mranges {
na.DelRange(e.KeyRange) na.DelRange(e.KeyRange)
} }
for _, r := range na.AllRanges() { for _, r := range na.AllRanges() {
for k := r.Lo; k <= r.Hi_; k++ { lo := kmax(r.Lo, Z.Lo)
hi_ := kmin(r.Hi_, Z.Hi_)
for k := lo; k <= hi_; k++ {
v, ok := M.Get_(k) v, ok := M.Get_(k)
if !(v == "" && !ok) { if !(v == "" && !ok) {
t.Errorf("%s\tGet(%s):\nhave: %q, %t\nwant: %q, false", t.Errorf("%s\tGet(%s):\nhave: %q, %t\nwant: %q, false",
...@@ -215,3 +284,22 @@ func verifyGet(t *testing.T, M *RangedMap) { ...@@ -215,3 +284,22 @@ func verifyGet(t *testing.T, M *RangedMap) {
} }
} }
} }
// kmin returns min(a,b).
func kmin(a, b Key) Key {
if a < b {
return a
} else {
return b
}
}
// kmax returns max(a,b).
func kmax(a, b Key) Key {
if a > b {
return a
} else {
return b
}
}
...@@ -110,7 +110,7 @@ func TestRangedKeySet(t *testing.T) { ...@@ -110,7 +110,7 @@ func TestRangedKeySet(t *testing.T) {
S(1,7), S(1,7),
S(1,3, 5,7)), S(1,3, 5,7)),
// several ranges \ [-∞, ∞) -> ø // several ranges \ [-∞,∞) -> ø
E( E(
S(1,3, 5,7, 11,100), // A S(1,3, 5,7, 11,100), // A
S(noo, oo), // B S(noo, oo), // B
......
...@@ -27,8 +27,8 @@ import ( ...@@ -27,8 +27,8 @@ import (
"sort" "sort"
) )
const trace_RangedMap_str = false const trace_RangedMap_str = true
const debug_RangedMap_str = false const debug_RangedMap_str = true
// _RangedMap_str is Key->string map with adjacent keys mapped to the same value coalesced into Ranges. // _RangedMap_str is Key->string map with adjacent keys mapped to the same value coalesced into Ranges.
// //
...@@ -117,6 +117,10 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) { ...@@ -117,6 +117,10 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) {
M.verify() M.verify()
defer M.verify() defer M.verify()
if r.Empty() {
return // XXX or panic?
}
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for same-value/set case (just merge all covered // TODO optimize for same-value/set case (just merge all covered
// entries into one - - see commented AddRange from set vvv) // entries into one - - see commented AddRange from set vvv)
...@@ -369,7 +373,7 @@ func (M *_RangedMap_str) verify() { ...@@ -369,7 +373,7 @@ func (M *_RangedMap_str) verify() {
for _, bad := range badv { for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad) emsg += fmt.Sprintf("- %s\n", bad)
} }
emsg += fmt.Sprintf("\nS: %s\n", M) emsg += fmt.Sprintf("\nM: %s\n", M)
panic(emsg) panic(emsg)
} }
}() }()
......
...@@ -27,8 +27,8 @@ import ( ...@@ -27,8 +27,8 @@ import (
"sort" "sort"
) )
const trace_RangedMap_void = false const trace_RangedMap_void = true
const debug_RangedMap_void = false const debug_RangedMap_void = true
// _RangedMap_void is Key->void map with adjacent keys mapped to the same value coalesced into Ranges. // _RangedMap_void is Key->void map with adjacent keys mapped to the same value coalesced into Ranges.
// //
...@@ -117,6 +117,10 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) { ...@@ -117,6 +117,10 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) {
M.verify() M.verify()
defer M.verify() defer M.verify()
if r.Empty() {
return // XXX or panic?
}
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for same-value/set case (just merge all covered // TODO optimize for same-value/set case (just merge all covered
// entries into one - - see commented AddRange from set vvv) // entries into one - - see commented AddRange from set vvv)
...@@ -369,7 +373,7 @@ func (M *_RangedMap_void) verify() { ...@@ -369,7 +373,7 @@ func (M *_RangedMap_void) verify() {
for _, bad := range badv { for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad) emsg += fmt.Sprintf("- %s\n", bad)
} }
emsg += fmt.Sprintf("\nS: %s\n", M) emsg += fmt.Sprintf("\nM: %s\n", M)
panic(emsg) panic(emsg)
} }
}() }()
......
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