Skip to content

Commit

Permalink
Flatten fltr funcs into used methods
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlias committed Dec 22, 2023
1 parent 6efb245 commit 846e011
Showing 1 changed file with 48 additions and 59 deletions.
107 changes: 48 additions & 59 deletions attribute/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
//
// The second []KeyValue return value is a list of attributes that were
// excluded by the Filter (if non-nil).
func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) {
func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, keep Filter) (Set, []KeyValue) {
// Check for empty set.
if len(kvs) == 0 {
return empty(), nil
Expand All @@ -263,80 +263,63 @@ func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (S

*tmp = nil

// Use filteredToFront here for last-value-wins semantics.
uniq := filteredToFront(kvs, func() func(kv KeyValue) bool {
firstCall := true
var prev Key
return func(kv KeyValue) bool {
if firstCall {
firstCall, prev = false, kv.Key
} else {
if kv.Key == prev {
return false
}
prev = kv.Key
}
return true
}
}())
kvs = kvs[uniq:]

if filter != nil {
// Unique prior to filtering so the returned dropped attributes will
// not also include the deduplicated attributes.
k := filteredToBack(kvs, filter)
if k == len(kvs) {
return Set{equivalent: computeDistinct(kvs[:k])}, nil
}
return Set{equivalent: computeDistinct(kvs[:k])}, kvs[k:]
if keep == nil {
keep = func(KeyValue) bool { return true }
}

return Set{equivalent: computeDistinct(kvs)}, nil
}
n := len(kvs)
prev := kvs[n-1]

// filteredToBack filters slice in-place using f. All KeyValues that need to be
// removed are moved to the end. All KeyValues that need to be kept are moved
// (in-order) to the front. The index for the first KeyValue to be removed is
// returned.
func filteredToBack(slice []KeyValue, keep Filter) int {
var j int
for i := 0; i < len(slice); i++ {
if keep(slice[i]) {
slice[i], slice[j] = slice[j], slice[i]
j++
}
kept := n // Starting index of kept KeyValues.
if keep(prev) {
kept--
}
return j
}

// filteredToFront filters slice in-place using f. All KeyValues that need to
// be removed are moved to the front. All KeyValues that need to be kept are
// moved (in-order) to the back. The index for the first KeyValue to be kept is
// returned.
func filteredToFront(slice []KeyValue, keep Filter) int {
n := len(slice)
j := n
for i := n - 1; i >= 0; i-- {
if keep(slice[i]) {
j--
slice[i], slice[j] = slice[j], slice[i]
// Instead of iterating kvs once to de-duplicate and another time to
// filter, do both in a single pass.
//
// Iterate from back-to-front for last-value-wins semantics.
for i := n - 2; i >= 0; i-- {
kv := kvs[i]
if kv.Key == prev.Key {
// Delete duplicate from kvs while preserving order and keeping
// the deleted KeyValue in original slice.
copy(kvs[i:], kvs[i+1:])
kvs[len(kvs)-1] = kv
kvs = kvs[:len(kvs)-1]

// Update kept index for new kvs size.
kept--
} else {
prev = kv
if keep(kv) {
kept--
kvs[i], kvs[kept] = kvs[kept], kvs[i]
}
}
}
return j

switch kept {
case 0:
return Set{equivalent: computeDistinct(kvs)}, nil
case n:
return empty(), kvs
}
return Set{equivalent: computeDistinct(kvs[kept:])}, kvs[:kept]
}

// Filter returns a filtered copy of this Set. See the documentation for
// NewSetWithSortableFiltered for more details.
func (l *Set) Filter(re Filter) (Set, []KeyValue) {
if re == nil {
func (l *Set) Filter(keep Filter) (Set, []KeyValue) {
if keep == nil {
return *l, nil
}

// Iterate to the first attribute that will be filtered out.
start, n := 0, l.Len()
for ; start < n; start++ {
kv, _ := l.Get(start)
if !re(kv) {
if !keep(kv) {
break
}
}
Expand All @@ -352,7 +335,7 @@ func (l *Set) Filter(re Filter) (Set, []KeyValue) {
// immutable and filtering should not change this.
slice := l.ToSlice()

// Do not re-evaluate re(slice[i]).
// Do not re-evaluate keep(slice[i]).
end := len(slice) - 1
if start == end {
return Set{equivalent: computeDistinct(slice[:start])}, slice[start:]
Expand All @@ -362,7 +345,13 @@ func (l *Set) Filter(re Filter) (Set, []KeyValue) {
copy(slice[start:], slice[start+1:])
slice[end] = kv

div := filteredToBack(slice[start:end], re) + start
div := start // Index of the first KeyValue to be removed.
for i := start; i < end; i++ {
if keep(slice[i]) {
slice[i], slice[div] = slice[div], slice[i]
div++
}
}
return Set{equivalent: computeDistinct(slice[:div])}, slice[div:]
}

Expand Down

0 comments on commit 846e011

Please sign in to comment.