Commit 24930939 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent ed2de0de
...@@ -25,8 +25,8 @@ import ( ...@@ -25,8 +25,8 @@ import (
"sort" "sort"
) )
const traceRangeMap = true const traceRangeMap = false
const debugRangeMap = true const debugRangeMap = false
// 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.
// //
...@@ -116,7 +116,8 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) { ...@@ -116,7 +116,8 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) {
defer M.verify() defer M.verify()
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for set case (just merge all covered entries into one) // TODO optimize for set case (just merge all covered entries into one -
// - see commented AddRange vvv)
i := M.delRange(r) i := M.delRange(r)
vInsert(&M.entryv, i, e) vInsert(&M.entryv, i, e)
debugfRMap("\tinsert %s\t-> %s\n", e, M) debugfRMap("\tinsert %s\t-> %s\n", e, M)
...@@ -144,18 +145,18 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) { ...@@ -144,18 +145,18 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) {
// done // done
/* /* how it was for just set:
// find first ilo: r.Lo < [ilo].hi // find first ilo: r.Lo < [ilo].hi
l := len(M.entryv) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugfRMap("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found if ilo == l { // not found
M.entryv = append(M.entryv, e) S.rangev = append(S.rangev, r)
l++ l++
debugfRMap("\tappend %s\t-> %s\n", e, M) debugfRSet("\tappend %s\t-> %s\n", r, S)
} }
// find last jhi: [jhi].Lo < r.hi // find last jhi: [jhi].Lo < r.hi
...@@ -164,97 +165,53 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) { ...@@ -164,97 +165,53 @@ func (M *RangedMap) SetRange(r KeyRange, v VALUE) {
if jhi == l { if jhi == l {
break break
} }
if M.entryv[jhi].Lo <= r.Hi_ { if S.rangev[jhi].Lo <= r.Hi_ {
continue continue
} }
break break
} }
debugfRMap("\tjhi: %d\n", jhi) debugfRSet("\tjhi: %d\n", jhi)
// [ilo+1:jhi-1] should be deleted
if (jhi - ilo) > 2 {
vDeleteSlice(&M.entryv, ilo+1,jhi-1)
debugfRMap("\tdelete M[%d:%d]\t-> %s\n", ilo+1, jhi-1, M)
}
// if r was overlapping with sole region -> presplit it TODO only if !vsame
x := M.entryv[ilo]
if jhi-ilo == 1 && x.Lo < r.Lo && r.Hi_ < x.Hi_ {
vInsert(&M.entryv, ilo, x)
jhi++
debugfRMap("\tpresplit copy %s\t-> %s\n", x, M)
}
jhi = -1 // no longer valid
// create new entry
// now it is
vInsert(&M.entryv, ilo+1, e)
// [ilo] is now to the left
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - XXX
if jhi-ilo == 1 {
x := M.entryv[ilo]
if x.Value != v {
vInsert(&M.entryv, ilo, x)
jhi++
debugfRMap("\tpresplit copy %s\t-> %s\n", x, M)
} else {
// XXX extend left/right if needed XXX here?
}
}
if xl.Value != v {
}
// entries in [ilo:jhi) [r.Lo,r.hi) and should be merged into one // entries in [ilo:jhi) [r.Lo,r.hi) and should be merged into one
// FIXME check different values
if (jhi - ilo) > 1 { if (jhi - ilo) > 1 {
lo := M.entryv[ilo].Lo lo := S.rangev[ilo].Lo
hi_ := M.entryv[jhi-1].Hi_ hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice(&M.entryv, ilo,jhi, RangedMapEntry{v, KeyRange{lo,hi_}}) vReplaceSlice(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugfRMap("\tmerge M[%d:%d]\t-> %s\n", ilo, jhi, M) debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
} }
jhi = -1 // no longer valid jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry // if [r.lo,r.hi) was outside of any entry - create new entry
if r.Hi_ < M.entryv[ilo].Lo { if r.Hi_ < S.rangev[ilo].Lo {
vInsert(&M.entryv, ilo, e) vInsert(&S.rangev, ilo, r)
debugfRMap("\tinsert %s\t-> %s\n", e, M) debugfRSet("\tinsert %s\t-> %s\n", r, S)
} }
// now we have covered entries merged as needed into [ilo] // now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider // extend this entry if r coverage is wider
if r.Lo < M.entryv[ilo].Lo { if r.Lo < S.rangev[ilo].Lo {
M.entryv[ilo].Lo = r.Lo S.rangev[ilo].Lo = r.Lo
debugfRMap("\textend left\t-> %s\n", M) debugfRSet("\textend left\t-> %s\n", S)
} }
if r.Hi_ > M.entryv[ilo].Hi_ { if r.Hi_ > S.rangev[ilo].Hi_ {
M.entryv[ilo].Hi_ = r.Hi_ S.rangev[ilo].Hi_ = r.Hi_
debugfRMap("\textend right\t-> %s\n", M) debugfRSet("\textend right\t-> %s\n", S)
} }
// and check if we should merge it with right/left neighbours // and check if we should merge it with right/left neighbours
if ilo+1 < len(M.entryv) { // right if ilo+1 < len(S.rangev) { // right
x := M.entryv[ilo] if S.rangev[ilo].Hi_+1 == S.rangev[ilo+1].Lo {
right := M.entryv[ilo+1] vReplaceSlice(&S.rangev, ilo,ilo+2,
if (x.Hi_+1 == right.Lo) && (v == right.Value) { KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
vReplaceSlice(&M.entryv, ilo,ilo+2, debugfRSet("\tmerge right\t-> %s\n", S)
RangedMapEntry{v, KeyRange{x.Lo, right.Hi_}})
debugfRMap("\tmerge right\t-> %s\n", M)
} }
} }
if ilo > 0 { // left if ilo > 0 { // left
left := M.entryv[ilo-1] if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo {
x := M.entryv[ilo] vReplaceSlice(&S.rangev, ilo-1,ilo+1,
if (left.Hi_+1 == x.Lo) && (left.Value == v) { KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
vReplaceSlice(&M.entryv, ilo-1,ilo+1, debugfRSet("\tmerge left\t-> %s\n", S)
RangedMapEntry{v, KeyRange{left.Lo, x.Hi_}})
debugfRMap("\tmerge left\t-> %s\n", M)
} }
} }
......
...@@ -130,9 +130,6 @@ func TestRangedMap(t *testing.T) { ...@@ -130,9 +130,6 @@ func TestRangedMap(t *testing.T) {
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 {
...@@ -185,6 +182,7 @@ func verifyGet(t *testing.T, M *_RangedMap_str) { ...@@ -185,6 +182,7 @@ func verifyGet(t *testing.T, M *_RangedMap_str) {
var Mranges []RangedMapEntry var Mranges []RangedMapEntry
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"
for _, e := range Mranges { for _, e := range Mranges {
for k := e.Lo; k <= e.Hi_; k++ { for k := e.Lo; k <= e.Hi_; k++ {
v, ok := M.Get_(k) v, ok := M.Get_(k)
...@@ -195,7 +193,7 @@ func verifyGet(t *testing.T, M *_RangedMap_str) { ...@@ -195,7 +193,7 @@ func verifyGet(t *testing.T, M *_RangedMap_str) {
} }
} }
// verify no-data // verify "no-data"
// NA = [-∞,∞) \ M // NA = [-∞,∞) \ M
na := RangedKeySet{} na := RangedKeySet{}
na.AddRange(KeyRange{-10,+10}) // models -∞,∞ na.AddRange(KeyRange{-10,+10}) // models -∞,∞
......
...@@ -150,7 +150,7 @@ func (S *RangedKeySet) AllRanges() /*readonly*/[]KeyRange { ...@@ -150,7 +150,7 @@ func (S *RangedKeySet) AllRanges() /*readonly*/[]KeyRange {
return rv return rv
} }
// XXX -> ptr?
func (S RangedKeySet) String() string { func (S RangedKeySet) String() string {
return S.m.String() // RangeMap<void> formats for set // RangeMap<void> supports formatting for set out of the box
return S.m.String()
} }
// Copyright (C) 2021 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package blib
// set of [lo,hi) Key ranges.
import (
"fmt"
"sort"
)
const traceRangeSet = false
const debugRangeSet = false
// KeyRange represents [lo,hi) Key range.
type KeyRange struct {
Lo Key
Hi_ Key // NOTE _not_ hi) to avoid overflow at ; hi = hi_ + 1
}
// RangedKeySet is set of Keys with adjacent keys coalesced into Ranges.
//
// Zero value represents empty set.
type RangedKeySet struct {
// TODO rework to use BTree lo->hi_ instead if in practice in treediff,
// and other usage places, N(ranges) turns out to be not small
// (i.e. performance turns out to be not acceptable)
rangev []KeyRange // lo
}
// Has returns whether key k belongs to the range.
func (r *KeyRange) Has(k Key) bool {
return (r.Lo <= k && k <= r.Hi_)
}
// Add adds key k to the set.
func (S *RangedKeySet) Add(k Key) {
S.AddRange(KeyRange{Lo: k, Hi_: k})
}
// Del removes key k from the set.
func (S *RangedKeySet) Del(k Key) {
S.DelRange(KeyRange{Lo: k, Hi_: k})
}
// Has returns whether key k belongs to the set.
func (S *RangedKeySet) Has(k Key) bool {
return S.HasRange(KeyRange{Lo: k, Hi_: k})
}
// AddRange adds range r to the set.
func (S *RangedKeySet) AddRange(r KeyRange) {
if traceRangeSet {
fmt.Printf("\n\nAddRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer fmt.Printf("->u: %s\n", S)
}
S.verify()
defer S.verify()
// find first ilo: r.Lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= S.rangev[i].Hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
S.rangev = append(S.rangev, r)
l++
debugfRSet("\tappend %s\t-> %s\n", r, S)
}
// find last jhi: [jhi].Lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if S.rangev[jhi].Lo <= r.Hi_ {
continue
}
break
}
debugfRSet("\tjhi: %d\n", jhi)
// entries in [ilo:jhi) [r.Lo,r.hi) and should be merged into one
if (jhi - ilo) > 1 {
lo := S.rangev[ilo].Lo
hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
}
jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry
if r.Hi_ < S.rangev[ilo].Lo {
vInsert(&S.rangev, ilo, r)
debugfRSet("\tinsert %s\t-> %s\n", r, S)
}
// now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider
if r.Lo < S.rangev[ilo].Lo {
S.rangev[ilo].Lo = r.Lo
debugfRSet("\textend left\t-> %s\n", S)
}
if r.Hi_ > S.rangev[ilo].Hi_ {
S.rangev[ilo].Hi_ = r.Hi_
debugfRSet("\textend right\t-> %s\n", S)
}
// and check if we should merge it with right/left neighbours
if ilo+1 < len(S.rangev) { // right
if S.rangev[ilo].Hi_+1 == S.rangev[ilo+1].Lo {
vReplaceSlice(&S.rangev, ilo,ilo+2,
KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
debugfRSet("\tmerge right\t-> %s\n", S)
}
}
if ilo > 0 { // left
if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo {
vReplaceSlice(&S.rangev, ilo-1,ilo+1,
KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
debugfRSet("\tmerge left\t-> %s\n", S)
}
}
// done
}
// DelRange removes range r from the set.
func (S *RangedKeySet) DelRange(r KeyRange) {
if traceRangeSet {
fmt.Printf("\n\nDelRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer fmt.Printf("->d: %s\n", S)
}
S.verify()
defer S.verify()
// find first ilo: r.Lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= S.rangev[i].Hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
debugfRSet("\tnon-overlap right\n")
return
}
// find last jhi: [jhi].Lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if S.rangev[jhi].Lo <= r.Hi_ {
continue
}
break
}
debugfRSet("\tjhi: %d\n", jhi)
if jhi == 0 {
debugfRSet("\tnon-overlap left\n")
return
}
// [ilo+1:jhi-1] should be deleted
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - they should be deleted, or shrinked,
// or split+shrinked if ilo==jhi-1 and r is inside [ilo]
if jhi-ilo == 1 && S.rangev[ilo].Lo < r.Lo && r.Hi_ < S.rangev[ilo].Hi_ {
x := S.rangev[ilo]
vInsert(&S.rangev, ilo, x)
jhi++
debugfRSet("\tpresplit copy %s\t-> %s\n", x, S)
}
if S.rangev[ilo].Lo < r.Lo { // shrink left
S.rangev[ilo] = KeyRange{S.rangev[ilo].Lo, r.Lo-1}
ilo++
debugfRSet("\tshrink [%d] left\t-> %s\n", ilo, S)
}
if r.Hi_ < S.rangev[jhi-1].Hi_ { // shrink right
S.rangev[jhi-1] = KeyRange{r.Hi_+1, S.rangev[jhi-1].Hi_}
jhi--
debugfRSet("\tshrink [%d] right\t-> %s\n", jhi-1, S)
}
if (jhi - ilo) > 0 {
vDeleteSlice(&S.rangev, ilo,jhi)
debugfRSet("\tdelete S[%d:%d]\t-> %s\n", ilo, jhi, S)
}
// done
}
// HasRange returns whether all keys from range r belong to the set.
func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) {
if traceRangeSet {
fmt.Printf("\n\nHasRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
S.verify()
// find first ilo: r.lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.Lo <= S.rangev[i].Hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// all keys from r are in S if r [ilo]
return (S.rangev[ilo].Lo <= r.Lo && r.Hi_ <= S.rangev[ilo].Hi_)
}
// Union returns RangedKeySet(A.keys | B.keys).
func (A *RangedKeySet) Union(B *RangedKeySet) *RangedKeySet {
U := A.Clone()
U.UnionInplace(B)
return U
}
// Difference returns RangedKeySet(A.keys \ B.keys).
func (A *RangedKeySet) Difference(B *RangedKeySet) *RangedKeySet {
D := A.Clone()
D.DifferenceInplace(B)
return D
}
// XXX Intersection
func (A *RangedKeySet) UnionInplace(B *RangedKeySet) {
A.verify()
B.verify()
defer A.verify()
// XXX dumb
for _, r := range B.rangev {
A.AddRange(r)
}
}
func (A *RangedKeySet) DifferenceInplace(B *RangedKeySet) {
A.verify()
B.verify()
defer A.verify()
// XXX dumb
for _, r := range B.rangev {
if len(A.rangev) == 0 {
break
}
A.DelRange(r)
}
}
// --------
// verify checks RangedKeySet for internal consistency:
// - ranges must be not overlapping nor adjacent and
func (S *RangedKeySet) verify() {
// TODO !debug -> return
var badv []string
badf := func(format string, argv ...interface{}) {
badv = append(badv, fmt.Sprintf(format, argv...))
}
defer func() {
if badv != nil {
emsg := "S.verify: fail:\n\n"
for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad)
}
emsg += fmt.Sprintf("\nS: %s\n", S)
panic(emsg)
}
}()
hi_Prev := KeyMin
for i, r := range S.rangev {
hiPrev := hi_Prev + 1
if i > 0 && !(hiPrev < r.Lo) { // NOTE not ≤ - adjacent ranges must be merged
badf("[%d]: !(hiPrev < r.lo)", i)
}
if !(r.Lo <= r.Hi_) {
badf("[%d]: !(r.lo <= r.hi_)", i)
}
hi_Prev = r.Hi_
}
}
// Clone returns copy of the set.
func (orig *RangedKeySet) Clone() *RangedKeySet {
klon := &RangedKeySet{}
klon.rangev = append(klon.rangev, orig.rangev...)
return klon
}
// Empty returns whether the set is empty.
func (S *RangedKeySet) Empty() bool {
return len(S.rangev) == 0
}
// Equal returns whether A == B.
func (A *RangedKeySet) Equal(B *RangedKeySet) bool {
if len(A.rangev) != len(B.rangev) {
return false
}
for i, ra := range A.rangev {
rb := B.rangev[i]
if ra != rb {
return false
}
}
return true
}
// Clear removes all elements from the set.
func (S *RangedKeySet) Clear() {
S.rangev = nil
}
// AllRanges returns slice of all key ranges in the set.
//
// TODO -> iter?
func (S *RangedKeySet) AllRanges() /*readonly*/[]KeyRange {
return S.rangev
}
// XXX -> ptr?
func (S RangedKeySet) String() string {
s := "{"
for i, r := range S.rangev {
if i > 0 {
s += " "
}
s += r.String()
}
s += "}"
return s
}
func (r KeyRange) String() string {
var shi string
if r.Hi_ == KeyMax {
shi = KStr(r.Hi_) //
} else {
shi = fmt.Sprintf("%d", r.Hi_+1)
}
return fmt.Sprintf("[%s,%s)", KStr(r.Lo), shi)
}
func debugfRSet(format string, argv ...interface{}) {
if !debugRangeSet {
return
}
fmt.Printf(format, argv...)
}
// ---- slice ops ----
// vInsert inserts r into *pv[i].
func vInsert(pv *[]KeyRange, i int, r KeyRange) {
v := *pv
v = append(v, KeyRange{})
copy(v[i+1:], v[i:])
v[i] = r
*pv = v
}
// vDeleteSlice deletes *pv[lo:hi].
func vDeleteSlice(pv *[]KeyRange, lo,hi int) {
v := *pv
n := copy(v[lo:], v[hi:])
v = v[:lo+n]
*pv = v
}
// vReplaceSlice replaces *pv[lo:hi] with r.
func vReplaceSlice(pv *[]KeyRange, lo,hi int, r KeyRange) {
v := *pv
n := copy(v[lo+1:], v[hi:])
v[lo] = r
v = v[:lo+1+n]
*pv = v
}
...@@ -27,8 +27,8 @@ import ( ...@@ -27,8 +27,8 @@ import (
"sort" "sort"
) )
const trace_RangedMap_str = true const trace_RangedMap_str = false
const debug_RangedMap_str = true const debug_RangedMap_str = false
// _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.
// //
...@@ -118,7 +118,8 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) { ...@@ -118,7 +118,8 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) {
defer M.verify() defer M.verify()
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for set case (just merge all covered entries into one) // TODO optimize for set case (just merge all covered entries into one -
// - see commented AddRange vvv)
i := M.delRange(r) i := M.delRange(r)
vInsert__RangedMap_str(&M.entryv, i, e) vInsert__RangedMap_str(&M.entryv, i, e)
debugf_RangedMap_str("\tinsert %s\t-> %s\n", e, M) debugf_RangedMap_str("\tinsert %s\t-> %s\n", e, M)
...@@ -146,18 +147,18 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) { ...@@ -146,18 +147,18 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) {
// done // done
/* /* how it was for just set:
// find first ilo: r.Lo < [ilo].hi // find first ilo: r.Lo < [ilo].hi
l := len(M.entryv) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugf_RangedMap_str("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found if ilo == l { // not found
M.entryv = append(M.entryv, e) S.rangev = append(S.rangev, r)
l++ l++
debugf_RangedMap_str("\tappend %s\t-> %s\n", e, M) debugfRSet("\tappend %s\t-> %s\n", r, S)
} }
// find last jhi: [jhi].Lo < r.hi // find last jhi: [jhi].Lo < r.hi
...@@ -166,97 +167,53 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) { ...@@ -166,97 +167,53 @@ func (M *_RangedMap_str) SetRange(r KeyRange, v string) {
if jhi == l { if jhi == l {
break break
} }
if M.entryv[jhi].Lo <= r.Hi_ { if S.rangev[jhi].Lo <= r.Hi_ {
continue continue
} }
break break
} }
debugf_RangedMap_str("\tjhi: %d\n", jhi) debugfRSet("\tjhi: %d\n", jhi)
// [ilo+1:jhi-1] should be deleted
if (jhi - ilo) > 2 {
vDeleteSlice__RangedMap_str(&M.entryv, ilo+1,jhi-1)
debugf_RangedMap_str("\tdelete M[%d:%d]\t-> %s\n", ilo+1, jhi-1, M)
}
// if r was overlapping with sole region -> presplit it TODO only if !vsame
x := M.entryv[ilo]
if jhi-ilo == 1 && x.Lo < r.Lo && r.Hi_ < x.Hi_ {
vInsert__RangedMap_str(&M.entryv, ilo, x)
jhi++
debugf_RangedMap_str("\tpresplit copy %s\t-> %s\n", x, M)
}
jhi = -1 // no longer valid
// create new entry
// now it is
vInsert__RangedMap_str(&M.entryv, ilo+1, e)
// [ilo] is now to the left
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - XXX
if jhi-ilo == 1 {
x := M.entryv[ilo]
if x.Value != v {
vInsert__RangedMap_str(&M.entryv, ilo, x)
jhi++
debugf_RangedMap_str("\tpresplit copy %s\t-> %s\n", x, M)
} else {
// XXX extend left/right if needed XXX here?
}
}
if xl.Value != v {
}
// entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one // entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one
// FIXME check different values
if (jhi - ilo) > 1 { if (jhi - ilo) > 1 {
lo := M.entryv[ilo].Lo lo := S.rangev[ilo].Lo
hi_ := M.entryv[jhi-1].Hi_ hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice__RangedMap_str(&M.entryv, ilo,jhi, _RangedMap_strEntry{v, KeyRange{lo,hi_}}) vReplaceSlice__RangedMap_str(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugf_RangedMap_str("\tmerge M[%d:%d]\t-> %s\n", ilo, jhi, M) debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
} }
jhi = -1 // no longer valid jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry // if [r.lo,r.hi) was outside of any entry - create new entry
if r.Hi_ < M.entryv[ilo].Lo { if r.Hi_ < S.rangev[ilo].Lo {
vInsert__RangedMap_str(&M.entryv, ilo, e) vInsert__RangedMap_str(&S.rangev, ilo, r)
debugf_RangedMap_str("\tinsert %s\t-> %s\n", e, M) debugfRSet("\tinsert %s\t-> %s\n", r, S)
} }
// now we have covered entries merged as needed into [ilo] // now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider // extend this entry if r coverage is wider
if r.Lo < M.entryv[ilo].Lo { if r.Lo < S.rangev[ilo].Lo {
M.entryv[ilo].Lo = r.Lo S.rangev[ilo].Lo = r.Lo
debugf_RangedMap_str("\textend left\t-> %s\n", M) debugfRSet("\textend left\t-> %s\n", S)
} }
if r.Hi_ > M.entryv[ilo].Hi_ { if r.Hi_ > S.rangev[ilo].Hi_ {
M.entryv[ilo].Hi_ = r.Hi_ S.rangev[ilo].Hi_ = r.Hi_
debugf_RangedMap_str("\textend right\t-> %s\n", M) debugfRSet("\textend right\t-> %s\n", S)
} }
// and check if we should merge it with right/left neighbours // and check if we should merge it with right/left neighbours
if ilo+1 < len(M.entryv) { // right if ilo+1 < len(S.rangev) { // right
x := M.entryv[ilo] if S.rangev[ilo].Hi_+1 == S.rangev[ilo+1].Lo {
right := M.entryv[ilo+1] vReplaceSlice__RangedMap_str(&S.rangev, ilo,ilo+2,
if (x.Hi_+1 == right.Lo) && (v == right.Value) { KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
vReplaceSlice__RangedMap_str(&M.entryv, ilo,ilo+2, debugfRSet("\tmerge right\t-> %s\n", S)
_RangedMap_strEntry{v, KeyRange{x.Lo, right.Hi_}})
debugf_RangedMap_str("\tmerge right\t-> %s\n", M)
} }
} }
if ilo > 0 { // left if ilo > 0 { // left
left := M.entryv[ilo-1] if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo {
x := M.entryv[ilo] vReplaceSlice__RangedMap_str(&S.rangev, ilo-1,ilo+1,
if (left.Hi_+1 == x.Lo) && (left.Value == v) { KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
vReplaceSlice__RangedMap_str(&M.entryv, ilo-1,ilo+1, debugfRSet("\tmerge left\t-> %s\n", S)
_RangedMap_strEntry{v, KeyRange{left.Lo, x.Hi_}})
debugf_RangedMap_str("\tmerge left\t-> %s\n", M)
} }
} }
......
...@@ -27,8 +27,8 @@ import ( ...@@ -27,8 +27,8 @@ import (
"sort" "sort"
) )
const trace_RangedMap_void = true const trace_RangedMap_void = false
const debug_RangedMap_void = true const debug_RangedMap_void = false
// _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.
// //
...@@ -118,7 +118,8 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) { ...@@ -118,7 +118,8 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) {
defer M.verify() defer M.verify()
// clear range for r and insert new entry // clear range for r and insert new entry
// TODO optimize for set case (just merge all covered entries into one) // TODO optimize for set case (just merge all covered entries into one -
// - see commented AddRange vvv)
i := M.delRange(r) i := M.delRange(r)
vInsert__RangedMap_void(&M.entryv, i, e) vInsert__RangedMap_void(&M.entryv, i, e)
debugf_RangedMap_void("\tinsert %s\t-> %s\n", e, M) debugf_RangedMap_void("\tinsert %s\t-> %s\n", e, M)
...@@ -146,18 +147,18 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) { ...@@ -146,18 +147,18 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) {
// done // done
/* /* how it was for just set:
// find first ilo: r.Lo < [ilo].hi // find first ilo: r.Lo < [ilo].hi
l := len(M.entryv) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.Lo <= M.entryv[i].Hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugf_RangedMap_void("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found if ilo == l { // not found
M.entryv = append(M.entryv, e) S.rangev = append(S.rangev, r)
l++ l++
debugf_RangedMap_void("\tappend %s\t-> %s\n", e, M) debugfRSet("\tappend %s\t-> %s\n", r, S)
} }
// find last jhi: [jhi].Lo < r.hi // find last jhi: [jhi].Lo < r.hi
...@@ -166,97 +167,53 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) { ...@@ -166,97 +167,53 @@ func (M *_RangedMap_void) SetRange(r KeyRange, v void) {
if jhi == l { if jhi == l {
break break
} }
if M.entryv[jhi].Lo <= r.Hi_ { if S.rangev[jhi].Lo <= r.Hi_ {
continue continue
} }
break break
} }
debugf_RangedMap_void("\tjhi: %d\n", jhi) debugfRSet("\tjhi: %d\n", jhi)
// [ilo+1:jhi-1] should be deleted
if (jhi - ilo) > 2 {
vDeleteSlice__RangedMap_void(&M.entryv, ilo+1,jhi-1)
debugf_RangedMap_void("\tdelete M[%d:%d]\t-> %s\n", ilo+1, jhi-1, M)
}
// if r was overlapping with sole region -> presplit it TODO only if !vsame
x := M.entryv[ilo]
if jhi-ilo == 1 && x.Lo < r.Lo && r.Hi_ < x.Hi_ {
vInsert__RangedMap_void(&M.entryv, ilo, x)
jhi++
debugf_RangedMap_void("\tpresplit copy %s\t-> %s\n", x, M)
}
jhi = -1 // no longer valid
// create new entry
// now it is
vInsert__RangedMap_void(&M.entryv, ilo+1, e)
// [ilo] is now to the left
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - XXX
if jhi-ilo == 1 {
x := M.entryv[ilo]
if x.Value != v {
vInsert__RangedMap_void(&M.entryv, ilo, x)
jhi++
debugf_RangedMap_void("\tpresplit copy %s\t-> %s\n", x, M)
} else {
// XXX extend left/right if needed XXX here?
}
}
if xl.Value != v {
}
// entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one // entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one
// FIXME check different values
if (jhi - ilo) > 1 { if (jhi - ilo) > 1 {
lo := M.entryv[ilo].Lo lo := S.rangev[ilo].Lo
hi_ := M.entryv[jhi-1].Hi_ hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice__RangedMap_void(&M.entryv, ilo,jhi, _RangedMap_voidEntry{v, KeyRange{lo,hi_}}) vReplaceSlice__RangedMap_void(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugf_RangedMap_void("\tmerge M[%d:%d]\t-> %s\n", ilo, jhi, M) debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
} }
jhi = -1 // no longer valid jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry // if [r.lo,r.hi) was outside of any entry - create new entry
if r.Hi_ < M.entryv[ilo].Lo { if r.Hi_ < S.rangev[ilo].Lo {
vInsert__RangedMap_void(&M.entryv, ilo, e) vInsert__RangedMap_void(&S.rangev, ilo, r)
debugf_RangedMap_void("\tinsert %s\t-> %s\n", e, M) debugfRSet("\tinsert %s\t-> %s\n", r, S)
} }
// now we have covered entries merged as needed into [ilo] // now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider // extend this entry if r coverage is wider
if r.Lo < M.entryv[ilo].Lo { if r.Lo < S.rangev[ilo].Lo {
M.entryv[ilo].Lo = r.Lo S.rangev[ilo].Lo = r.Lo
debugf_RangedMap_void("\textend left\t-> %s\n", M) debugfRSet("\textend left\t-> %s\n", S)
} }
if r.Hi_ > M.entryv[ilo].Hi_ { if r.Hi_ > S.rangev[ilo].Hi_ {
M.entryv[ilo].Hi_ = r.Hi_ S.rangev[ilo].Hi_ = r.Hi_
debugf_RangedMap_void("\textend right\t-> %s\n", M) debugfRSet("\textend right\t-> %s\n", S)
} }
// and check if we should merge it with right/left neighbours // and check if we should merge it with right/left neighbours
if ilo+1 < len(M.entryv) { // right if ilo+1 < len(S.rangev) { // right
x := M.entryv[ilo] if S.rangev[ilo].Hi_+1 == S.rangev[ilo+1].Lo {
right := M.entryv[ilo+1] vReplaceSlice__RangedMap_void(&S.rangev, ilo,ilo+2,
if (x.Hi_+1 == right.Lo) && (v == right.Value) { KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
vReplaceSlice__RangedMap_void(&M.entryv, ilo,ilo+2, debugfRSet("\tmerge right\t-> %s\n", S)
_RangedMap_voidEntry{v, KeyRange{x.Lo, right.Hi_}})
debugf_RangedMap_void("\tmerge right\t-> %s\n", M)
} }
} }
if ilo > 0 { // left if ilo > 0 { // left
left := M.entryv[ilo-1] if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo {
x := M.entryv[ilo] vReplaceSlice__RangedMap_void(&S.rangev, ilo-1,ilo+1,
if (left.Hi_+1 == x.Lo) && (left.Value == v) { KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
vReplaceSlice__RangedMap_void(&M.entryv, ilo-1,ilo+1, debugfRSet("\tmerge left\t-> %s\n", S)
_RangedMap_voidEntry{v, KeyRange{left.Lo, x.Hi_}})
debugf_RangedMap_void("\tmerge left\t-> %s\n", M)
} }
} }
......
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