Skip to content

Commit

Permalink
Cannot properly compare equal to without equality comparison functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
umpc committed Jul 6, 2017
1 parent d2fb1f4 commit a662462
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 70 deletions.
67 changes: 12 additions & 55 deletions bounds.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,12 @@ package sortedmap
import "sort"

func (sm *SortedMap) setBoundIdx(boundVal interface{}) int {

if boundVal == nil {
return 0
}

smLen := len(sm.sorted)
idx := sort.Search(smLen, func(i int) bool {
return sort.Search(len(sm.sorted), func(i int) bool {
return sm.lessFn(boundVal, sm.idx[sm.sorted[i]])
})

// sort.Search returns the smallest index i in [0, n) at which f(i) is true.
// This sets the correct index for less than conditional comparisons.
if idx > 0 {
idx--
}

return idx
}

func (sm *SortedMap) lowerBoundIncrCondition(i, j interface{}) bool {
return sm.lessFn(j, i)
}

func (sm *SortedMap) lowerBoundRetCondition(i, j interface{}) bool {
return sm.lessFn(j, i)
}

func (sm *SortedMap) upperBoundIncrCondition(i, j interface{}) bool {
return !sm.lessFn(j, i) && !sm.lessFn(i, j)
}

func (sm *SortedMap) upperBoundRetCondition(i, j interface{}) bool {
return sm.lessFn(i, j)
}

func (sm *SortedMap) adjustIdxOrReturn(boundVal interface{}, incrCondition, retCondition func(boundVal, valFromIdx interface{}) bool) (int, bool) {
idx := sm.setBoundIdx(boundVal)
if idx < len(sm.sorted)-1 {
valFromIdx := sm.idx[sm.sorted[idx]]

if incrCondition(boundVal, valFromIdx) {
idx++
}

valFromIdx = sm.idx[sm.sorted[idx]]
if retCondition(boundVal, valFromIdx) {
return idx, false
}
}
return idx, true
}

func (sm *SortedMap) boundsIdxSearch(lowerBound, upperBound interface{}) []int {
Expand All @@ -68,22 +24,23 @@ func (sm *SortedMap) boundsIdxSearch(lowerBound, upperBound interface{}) []int {
}

lowerBoundIdx := sm.setBoundIdx(lowerBound)
if lowerBound != nil {
var ok bool
lowerBoundIdx, ok = sm.adjustIdxOrReturn(lowerBound, sm.lowerBoundIncrCondition, sm.lowerBoundRetCondition)
if !ok {
return nil
}
if lowerBoundIdx == smLen {
lowerBoundIdx--
}
if lowerBoundIdx > 0 && sm.lessFn(sm.idx[sm.sorted[lowerBoundIdx]], lowerBound) {
lowerBoundIdx++
}

upperBoundIdx := 0
if upperBound == nil {
upperBoundIdx = smLen - 1
} else {
var ok bool
upperBoundIdx, ok = sm.adjustIdxOrReturn(upperBound, sm.upperBoundIncrCondition, sm.upperBoundRetCondition)
if !ok {
return nil
upperBoundIdx = sm.setBoundIdx(upperBound)
if upperBoundIdx == smLen {
upperBoundIdx--
}
if upperBoundIdx > 0 && sm.lessFn(upperBound, sm.idx[sm.sorted[upperBoundIdx]]) {
upperBoundIdx--
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func main() {

### BoundedIterCh

```BoundedIterCh``` selects the records equal to or between the given bounds. Its first argument allows for reversing the order of the returned records.
```BoundedIterCh``` selects values that are greater than the lower bound and are less than or equal to the upper bound. Its first argument allows for reversing the order of the returned records.

```go
package main
Expand Down Expand Up @@ -373,7 +373,7 @@ func main() {

### BoundedDelete

```BoundedDelete``` is a similar pattern as the above ```Bounded``` methods. ```BoundedDelete``` removes values that are equal to or between the provided bounds values.
```BoundedDelete``` is a similar pattern as the above ```Bounded``` methods. ```BoundedDelete``` removes values that are greater than the lower bound and lower than or equal to the upper bound.

```go
package main
Expand Down
22 changes: 11 additions & 11 deletions sortedmap.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package sortedmap

// SortedMap contains a map, a slice, and a reference to a sorting function.
// SortedMap contains a map, a slice, and references to one or more comparison functions.
// SortedMap is not concurrency-safe, though it can be easily wrapped by a developer-defined type.
type SortedMap struct {
idx map[interface{}]interface{}
sorted []interface{}
lessFn SortLessFunc
lessFn ComparisonFunc
}

// Record defines a type used in batching and iterations, where keys and values are used together.
Expand All @@ -14,27 +14,27 @@ type Record struct {
Val interface{}
}

// SortLessFunc defines the type of the comparison function for the chosen value type.
type SortLessFunc func(i, j interface{}) bool
// ComparisonFunc defines the type of the comparison function for the chosen value type.
type ComparisonFunc func(i, j interface{}) bool

func unsortedSortLessFunc(_, _ interface{}) bool {
func noOpComparisonFunc(_, _ interface{}) bool {
return false
}

func setLessFunc(lessFn SortLessFunc) SortLessFunc {
if lessFn == nil {
return unsortedSortLessFunc
func setComparisonFunc(cmpFn ComparisonFunc) ComparisonFunc {
if cmpFn == nil {
return noOpComparisonFunc
}
return lessFn
return cmpFn
}

// New creates and initializes a new SortedMap structure and then returns a reference to it.
// New SortedMaps are created with a backing map/slice of length/capacity n.
func New(n int, lessFn SortLessFunc) *SortedMap {
func New(n int, cmpFn ComparisonFunc) *SortedMap {
return &SortedMap{
idx: make(map[interface{}]interface{}, n),
sorted: make([]interface{}, 0, n),
lessFn: setLessFunc(lessFn),
lessFn: setComparisonFunc(cmpFn),
}
}

Expand Down
4 changes: 2 additions & 2 deletions sortedmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ func TestNew(t *testing.T) {
}
}

func TestUnsortedLessFunc(t *testing.T) {
func TestNoOpFuncs(t *testing.T) {
if New(0, nil).lessFn(nil, nil) {
t.Fatal("TestUnsortedLessFunc failed: lessFn returned true!")
t.Fatal("TestNoOpFuncs failed: lessFn returned true!")
}
}

Expand Down

0 comments on commit a662462

Please sign in to comment.