2019-02-04 13:49:05 +08:00
|
|
|
// Copyright 2019 Google Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2019-02-04 13:39:51 +08:00
|
|
|
// Package attrrange simplifies tracking of attributes that apply to a range of
|
|
|
|
// items.
|
2019-02-09 13:57:30 +08:00
|
|
|
// Refer to the examples in the test file for details on usage.
|
2019-02-04 13:39:51 +08:00
|
|
|
package attrrange
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sort"
|
|
|
|
)
|
|
|
|
|
|
|
|
// AttrRange is a range of items that share the same attributes.
|
|
|
|
type AttrRange struct {
|
|
|
|
// Low is the first position where these attributes apply.
|
|
|
|
Low int
|
|
|
|
|
|
|
|
// High is the end of the range. The attributes apply to all items in range
|
|
|
|
// Low <= b < high.
|
|
|
|
High int
|
|
|
|
|
|
|
|
// AttrIdx is the index of the attributes that apply to this range.
|
|
|
|
AttrIdx int
|
|
|
|
}
|
|
|
|
|
|
|
|
// newAttrRange returns a new AttrRange instance.
|
|
|
|
func newAttrRange(low, high, attrIdx int) *AttrRange {
|
|
|
|
return &AttrRange{
|
|
|
|
Low: low,
|
|
|
|
High: high,
|
|
|
|
AttrIdx: attrIdx,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tracker tracks attributes that apply to a range of items.
|
|
|
|
// This object is not thread safe.
|
|
|
|
type Tracker struct {
|
|
|
|
// ranges maps low indices of ranges to the attribute ranges.
|
|
|
|
ranges map[int]*AttrRange
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewTracker returns a new tracker of ranges that share the same attributes.
|
|
|
|
func NewTracker() *Tracker {
|
|
|
|
return &Tracker{
|
|
|
|
ranges: map[int]*AttrRange{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds a new range of items that share attributes with the specified
|
|
|
|
// index.
|
|
|
|
// The low position of the range must not overlap with low position of any
|
|
|
|
// existing range.
|
|
|
|
func (t *Tracker) Add(low, high, attrIdx int) error {
|
|
|
|
ar := newAttrRange(low, high, attrIdx)
|
|
|
|
if ar, ok := t.ranges[low]; ok {
|
|
|
|
return fmt.Errorf("already have range starting on low:%d, existing:%+v", low, ar)
|
|
|
|
}
|
|
|
|
t.ranges[low] = ar
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ForPosition returns attribute index that apply to the specified position.
|
|
|
|
// Returns ErrNotFound when the requested position wasn't found in any of the
|
|
|
|
// known ranges.
|
|
|
|
func (t *Tracker) ForPosition(pos int) (*AttrRange, error) {
|
|
|
|
if ar, ok := t.ranges[pos]; ok {
|
|
|
|
return ar, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var keys []int
|
|
|
|
for k := range t.ranges {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Ints(keys)
|
|
|
|
|
|
|
|
var res *AttrRange
|
|
|
|
for _, k := range keys {
|
|
|
|
ar := t.ranges[k]
|
|
|
|
if ar.Low > pos {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if ar.High > pos {
|
|
|
|
res = ar
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if res == nil {
|
2019-02-05 13:05:31 +08:00
|
|
|
return nil, fmt.Errorf("did not find attribute range for position %d", pos)
|
2019-02-04 13:39:51 +08:00
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|