Commit a6bac322 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 7829c494
#!/bin/bash -e
# rangemap.go.in -> specialized with concrete types
# gen-rangemap KIND VALUE out
# gen-rangemap TYPE VALUE out
# Copyright (C) 2018-2021 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
......@@ -21,7 +21,7 @@
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
KIND=$1
TYPE=$1
VALUE=$2
out=$3
......@@ -30,7 +30,7 @@ Value=${VALUE^}
input=$(dirname $0)/rangemap.go.in
echo "// Code generated by gen-rangemap; DO NOT EDIT." >$out
echo "// Code generated by gen-rangemap $TYPE $VALUE; DO NOT EDIT." >$out
echo >>$out
sed \
......@@ -38,11 +38,12 @@ sed \
-e "s/<KIND>/$KIND/g" \
-e "s/VALUE/$VALUE/g" \
-e "s/<Value>/$Value/g" \
-e "s/\bNode\b/${KIND}Node/g" \
-e "s/\bBTree\b/${KIND}BTree/g" \
-e "s/\bEntry\b/${KIND}Entry/g" \
-e "s/\bBucket\b/${KIND}Bucket/g" \
-e "s/\bBucketEntry\b/${KIND}BucketEntry/g" \
-e "s/\bbtreeState\b/${kind}btreeState/g" \
-e "s/\bbucketState\b/${kind}bucketState/g" \
-e "s/\bRangedMap\b/${TYPE}/g" \
-e "s/\bRangedMapEntry\b/${TYPE}Entry/g" \
-e "s/\bvInsert\b/vInsert_${TYPE}/g" \
-e "s/\bvDeleteSlice\b/vDeleteSlice_${TYPE}/g" \
-e "s/\bvReplaceSlice\b/vReplaceSlice_${TYPE}/g"\
-e "s/\btraceRangeMap\b/trace${TYPE}/g" \
-e "s/\bdebugRangeMap\b/debug${TYPE}/g" \
-e "s/\bdebugfRMap\b/debugf${TYPE}/g" \
$input >>$out
......@@ -35,11 +35,11 @@ type RangedMap 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)
entryv []RangeMapEntry // lo
entryv []RangedMapEntry // lo
}
// RangeMapEntry represents one entry in RangedMap.
type RangeMapEntry struct {
// RangedMapEntry represents one entry in RangedMap.
type RangedMapEntry struct {
KeyRange
Value VALUE
}
......@@ -102,12 +102,9 @@ func (M *RangedMap) Get_(k Key) (v VALUE, ok bool) {
return e.value, true
}
// SetRange changes M to map key range r to value v.
func (M *RangedMap) SetRange(r KeyRange, v VALUE) {
e := mapEntry{r,v}
e := RangedMapEntry{r,v}
if traceRangeMap {
fmt.Printf("\n\nSetRange:\n")
fmt.Printf(" M: %s\n", M)
......@@ -370,10 +367,10 @@ func (M *RangedMap) Clear() {
M.entryv = nil
}
// AllEntries returns slice of all key ranges in the set.
// AllRanges returns slice of all key ranges in the set.
//
// TODO -> iter?
func (M *RangedKeySet) AllEntries() /*readonly*/[]RangeMapEntry {
func (M *RangedKeySet) AllRanges() /*readonly*/[]RangedMapEntry {
return M.entryv
}
......@@ -390,7 +387,7 @@ func (M RangedMap) String() string {
return s
}
func (e *mapEntry) String() string {
func (e *RangedMapEntry) String() string {
s := e.keycov.String()
v := fmt.Sprintf("%v", e.value)
if v != "" { // omit ":<v>" in the case of set
......@@ -411,16 +408,16 @@ func debugfRMap(format string, argv ...interface{}) {
// ---- slice ops ----
// vInsert inserts e into *pv[i].
func vInsert(pv *[]RangeMapEntry, i int, e RangeMapEntry) {
func vInsert(pv *[]RangedMapEntry, i int, e RangedMapEntry) {
v := *pv
v = append(v, RangeMapEntry{})
v = append(v, RangedMapEntry{})
copy(v[i+1:], v[i:])
v[i] = e
*pv = v
}
// vDeleteSlice deletes *pv[lo:hi].
func vDeleteSlice(pv *[]RangeMapEntry, lo,hi int) {
func vDeleteSlice(pv *[]RangedMapEntry, lo,hi int) {
v := *pv
n := copy(v[lo:], v[hi:])
v = v[:lo+n]
......@@ -428,7 +425,7 @@ func vDeleteSlice(pv *[]RangeMapEntry, lo,hi int) {
}
// vReplaceSlice replaces *pv[lo:hi] with e.
func vReplaceSlice(pv *[]RangeMapEntry, lo,hi int, e RangeMapEntry) {
func vReplaceSlice(pv *[]RangedMapEntry, lo,hi int, e RangedMapEntry) {
v := *pv
n := copy(v[lo+1:], v[hi:])
v[lo] = e
......
......@@ -20,16 +20,19 @@
package blib
// set of [lo,hi) Key ranges.
//go:generate gen-rangemap void struct{} zrangemap_void.go
//go:generate ./gen-rangemap _RangedMap_void void zrangemap_void.go
// RangedKeySet is set of Keys with adjacent keys coalesced into Ranges.
//
// Zero value represents empty set.
type RangedKeySet struct {
m _RangedKeyMap_void // XXX naming
m _RangedMap_void // XXX naming
}
// void is used as value type for RangedMap to be used as set.
type void struct{}
func (_ void) String() string { return "" }
// Union returns RangedKeySet(A.keys | B.keys).
......
// Code generated by gen-rangemap _RangedMap_void void; DO NOT EDIT.
// 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
// map [lo,hi) Key ranges to values.
import (
"fmt"
"sort"
)
const trace_RangedMap_void = true
const debug_RangedMap_void = true
// _RangedMap_void is Key->void map with adjacent keys mapped to the same value coalesced into Ranges.
//
// Zero value represents empty map.
type _RangedMap_void 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)
entryv []_RangedMap_voidEntry // lo↑
}
// _RangedMap_voidEntry represents one entry in _RangedMap_void.
type _RangedMap_voidEntry struct {
KeyRange
Value void
}
// Get returns value associated with key k.
func (M *_RangedMap_void) Get(k Key) void {
v, _ := M.Get_(k)
return v
}
// Set changes M to map key k to value v.
func (M *_RangedMap_void) Set(k Key, v void) {
M.SetRange(KeyRange{Lo: k, Hi_: k}, v)
}
// Del removes key k.
func (M *_RangedMap_void) Del(k Key) {
M.DelRange(KeyRange{Lo: k, Hi_: k})
}
// Has returns whether key k is present in the map.
func (M *_RangedMap_void) Has(k Key) bool {
_, ok := M.Get_(k)
return ok
}
// Get_ is comma-ok version of Get.
func (M *_RangedMap_void) Get_(k Key) (v void, ok bool) {
if trace_RangedMap_void {
fmt.Printf("\n\nGet_:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" k: %s\n", k)
defer func() {
fmt.Printf("->·: %v, %t\n", v, ok)
}()
}
M.verify()
// find first ilo: k < [ilo].hi
l := len(M.entryv)
ilo := sort.Search(l, func(i int) bool {
return k <= M.entryv[i].Hi_
})
debugf_RangedMap_void("\tilo: %d\n", ilo)
if ilo == l { // not found
return
}
e := M.entryv[ilo]
if !(e.Lo <= k) { // not found
return
}
// found
return e.value, true
}
// SetRange changes M to map key range r to value v.
func (M *_RangedMap_void) SetRange(r KeyRange, v void) {
e := _RangedMap_voidEntry{r,v}
if trace_RangedMap_void {
fmt.Printf("\n\nSetRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" e: %s\n", e)
defer fmt.Printf("->u: %s\n", M)
}
M.verify()
defer M.verify()
// 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
M.entryv = append(M.entryv, e)
l++
debugf_RangedMap_void("\tappend %s\t-> %s\n", e, M)
}
// find last jhi: [jhi].Lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if M.entryv[jhi].Lo <= r.Hi_ {
continue
}
break
}
debugf_RangedMap_void("\tjhi: %d\n", jhi)
// entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one
// XXX check different values
if (jhi - ilo) > 1 {
lo := S.rangev[ilo].Lo
hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice__RangedMap_void(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugf_RangedMap_void("\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__RangedMap_void(&S.rangev, ilo, r)
debugf_RangedMap_void("\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
debugf_RangedMap_void("\textend left\t-> %s\n", S)
}
if r.Hi_ > S.rangev[ilo].Hi_ {
S.rangev[ilo].Hi_ = r.Hi_
debugf_RangedMap_void("\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 { // XXX && .value same
vReplaceSlice__RangedMap_void(&S.rangev, ilo,ilo+2,
KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
debugf_RangedMap_void("\tmerge right\t-> %s\n", S)
}
}
if ilo > 0 { // left
if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo { // XXX && .value same
vReplaceSlice__RangedMap_void(&S.rangev, ilo-1,ilo+1,
KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
debugf_RangedMap_void("\tmerge left\t-> %s\n", S)
}
}
// done
}
// DelRange removes range r from the map.
func (M *_RangedMap_void) DelRange(r KeyRange) {
if trace_RangedMap_void {
fmt.Printf("\n\nDelRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer fmt.Printf("->d: %s\n", M)
}
M.verify()
defer M.verify()
// 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
debugf_RangedMap_void("\tnon-overlap right\n")
return
}
// find last jhi: [jhi].Lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if M.entryv[jhi].Lo <= r.Hi_ {
continue
}
break
}
debugf_RangedMap_void("\tjhi: %d\n", jhi)
if jhi == 0 {
debugf_RangedMap_void("\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 && M.entryv[ilo].Lo < r.Lo && r.Hi_ < M.entryv[ilo].Hi_ {
x := M.entryv[ilo]
vInsert__RangedMap_void(&M.entryv, ilo, x)
jhi++
debugf_RangedMap_void("\tpresplit copy %s\t-> %s\n", x, M)
}
if M.entryv[ilo].Lo < r.Lo { // shrink left
M.entryv[ilo].Hi_ = r.Lo-1
ilo++
debugf_RangedMap_void("\tshrink [%d] left\t-> %s\n", ilo, M)
}
if r.Hi_ < M.entryv[jhi-1].Hi_ { // shrink right
M.entryv[jhi-1].Lo = r.Hi_+1
jhi--
debugf_RangedMap_void("\tshrink [%d] right\t-> %s\n", jhi-1, M)
}
if (jhi - ilo) > 0 {
vDeleteSlice__RangedMap_void(&M.entryv, ilo,jhi)
debugf_RangedMap_void("\tdelete M[%d:%d]\t-> %s\n", ilo, jhi, M)
}
// done
}
// HasRange returns whether all keys from range r belong to the map.
func (M *_RangedMap_void) HasRange(r KeyRange) (yes bool) {
if trace_RangedMap_void {
fmt.Printf("\n\nHasRange:\n")
fmt.Printf(" M: %s\n", M)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
M.verify()
// 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
}
// all keys from r are in M if r ∈ [ilo] XXX not in case of different values
return (M.entryv[ilo].Lo <= r.Lo && r.Hi_ <= M.entryv[ilo].Hi_)
}
// --------
// verify checks _RangedMap_void for internal consistency:
// - ranges must be not overlapping and ↑
// - adjacent ranges must map to different values
func (M *_RangedMap_void) 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 := "M.verify: fail:\n\n"
for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad)
}
emsg += fmt.Sprintf("\nS: %s\n", M)
panic(emsg)
}
}()
hi_Prev := KeyMin
var v_Prev void
for i, e := range M.entryv {
hiPrev := hi_Prev + 1
if i > 0 {
if (e.value == v_Prev) {
if !(hiPrev < e.Lo) { // NOTE not ≤ - adjacent ranges must be merged
badf("[%d]: same value: !(hiPrev < e.lo)", i)
}
} else {
if !(hi_Prev <= e.Lo) {
badf("[%d]: different value: !(hiPrev ≤ e.lo)", i)
}
}
}
if !(e.Lo <= e.Hi_) {
badf("[%d]: !(e.lo ≤ e.hi_)", i)
}
hi_Prev = e.Hi_
v_Prev = e.value
}
}
// Clone returns copy of the map.
//
// NOTE values are _not_ cloned.
func (orig *_RangedMap_void) Clone() *_RangedMap_void {
klon := &_RangedMap_void{}
klon.entryv = append(klon.entryv, orig.entryv...)
return klon
}
// Empty returns whether the map is empty.
func (M *_RangedMap_void) Empty() bool {
return len(M.entryv) == 0
}
// Equal returns whether A == B.
func (A *_RangedMap_void) Equal(B *_RangedMap_void) bool {
if len(A.entryv) != len(B.entryv) {
return false
}
for i, ea := range A.entryv {
eb := B.entryv[i]
if ea != eb {
return false
}
}
return true
}
// Clear removes all elements from the map.
func (M *_RangedMap_void) Clear() {
M.entryv = nil
}
// AllRanges returns slice of all key ranges in the set.
//
// TODO -> iter?
func (M *RangedKeySet) AllRanges() /*readonly*/[]_RangedMap_voidEntry {
return M.entryv
}
// XXX -> ptr?
func (M _RangedMap_void) String() string {
s := "{"
for i, e := range M.entryv {
if i > 0 {
s += " "
}
s += e.String()
}
s += "}"
return s
}
func (e *_RangedMap_voidEntry) String() string {
s := e.keycov.String()
v := fmt.Sprintf("%v", e.value)
if v != "" { // omit ":<v>" in the case of set
s += ":" + v
}
return s
}
func debugf_RangedMap_void(format string, argv ...interface{}) {
if !debug_RangedMap_void {
return
}
fmt.Printf(format, argv...)
}
// ---- slice ops ----
// vInsert__RangedMap_void inserts e into *pv[i].
func vInsert__RangedMap_void(pv *[]_RangedMap_voidEntry, i int, e _RangedMap_voidEntry) {
v := *pv
v = append(v, _RangedMap_voidEntry{})
copy(v[i+1:], v[i:])
v[i] = e
*pv = v
}
// vDeleteSlice__RangedMap_void deletes *pv[lo:hi].
func vDeleteSlice__RangedMap_void(pv *[]_RangedMap_voidEntry, lo,hi int) {
v := *pv
n := copy(v[lo:], v[hi:])
v = v[:lo+n]
*pv = v
}
// vReplaceSlice__RangedMap_void replaces *pv[lo:hi] with e.
func vReplaceSlice__RangedMap_void(pv *[]_RangedMap_voidEntry, lo,hi int, e _RangedMap_voidEntry) {
v := *pv
n := copy(v[lo+1:], v[hi:])
v[lo] = e
v = v[:lo+1+n]
*pv = v
}
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