-
-
Save mattn/6daf8425916fc9a9f516 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file was auto-generated using github.com/clipperhouse/gen | |
// Modifying this file is not recommended as it will likely be overwritten in the future | |
// Sort functions are a modification of http://golang.org/pkg/sort/#Sort | |
// Copyright 2009 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package food | |
import ( | |
"errors" | |
) | |
// Foods is a slice of type *Food, for use with gen methods below. Use this type where you would use []*Food. (This is required because slices cannot be method receivers.) | |
type Foods []*Food | |
// All verifies that all elements of Foods return true for the passed func. See: http://clipperhouse.github.io/gen/#All | |
func (rcv Foods) All(fn func(*Food) bool) bool { | |
for _, v := range rcv { | |
if !fn(v) { | |
return false | |
} | |
} | |
return true | |
} | |
// Any verifies that one or more elements of Foods return true for the passed func. See: http://clipperhouse.github.io/gen/#Any | |
func (rcv Foods) Any(fn func(*Food) bool) bool { | |
for _, v := range rcv { | |
if fn(v) { | |
return true | |
} | |
} | |
return false | |
} | |
// Count gives the number elements of Foods that return true for the passed func. See: http://clipperhouse.github.io/gen/#Count | |
func (rcv Foods) Count(fn func(*Food) bool) (result int) { | |
for _, v := range rcv { | |
if fn(v) { | |
result++ | |
} | |
} | |
return | |
} | |
// Distinct returns a new Foods slice whose elements are unique. See: http://clipperhouse.github.io/gen/#Distinct | |
func (rcv Foods) Distinct() (result Foods) { | |
appended := make(map[*Food]bool) | |
for _, v := range rcv { | |
if !appended[v] { | |
result = append(result, v) | |
appended[v] = true | |
} | |
} | |
return result | |
} | |
// DistinctBy returns a new Foods slice whose elements are unique, where equality is defined by a passed func. See: http://clipperhouse.github.io/gen/#DistinctBy | |
func (rcv Foods) DistinctBy(equal func(*Food, *Food) bool) (result Foods) { | |
for _, v := range rcv { | |
eq := func(_app *Food) bool { | |
return equal(v, _app) | |
} | |
if !result.Any(eq) { | |
result = append(result, v) | |
} | |
} | |
return result | |
} | |
// Each iterates over Foods and executes the passed func against each element. See: http://clipperhouse.github.io/gen/#Each | |
func (rcv Foods) Each(fn func(*Food)) { | |
for _, v := range rcv { | |
fn(v) | |
} | |
} | |
// First returns the first element that returns true for the passed func. Returns error if no elements return true. See: http://clipperhouse.github.io/gen/#First | |
func (rcv Foods) First(fn func(*Food) bool) (result *Food, err error) { | |
for _, v := range rcv { | |
if fn(v) { | |
result = v | |
return | |
} | |
} | |
err = errors.New("no Foods elements return true for passed func") | |
return | |
} | |
// IsSortedBy reports whether an instance of Foods is sorted, using the pass func to define ‘less’. See: http://clipperhouse.github.io/gen/#SortBy | |
func (rcv Foods) IsSortedBy(less func(*Food, *Food) bool) bool { | |
n := len(rcv) | |
for i := n - 1; i > 0; i-- { | |
if less(rcv[i], rcv[i-1]) { | |
return false | |
} | |
} | |
return true | |
} | |
// IsSortedDesc reports whether an instance of Foods is sorted in descending order, using the pass func to define ‘less’. See: http://clipperhouse.github.io/gen/#SortBy | |
func (rcv Foods) IsSortedByDesc(less func(*Food, *Food) bool) bool { | |
greater := func(a, b *Food) bool { | |
return a != b && !less(a, b) | |
} | |
return rcv.IsSortedBy(greater) | |
} | |
// MaxBy returns an element of Foods containing the maximum value, when compared to other elements using a passed func defining ‘less’. In the case of multiple items being equally maximal, the last such element is returned. Returns error if no elements. See: http://clipperhouse.github.io/gen/#MaxBy | |
func (rcv Foods) MaxBy(less func(*Food, *Food) bool) (result *Food, err error) { | |
l := len(rcv) | |
if l == 0 { | |
err = errors.New("cannot determine the MaxBy of an empty slice") | |
return | |
} | |
m := 0 | |
for i := 1; i < l; i++ { | |
if rcv[i] != rcv[m] && !less(rcv[i], rcv[m]) { | |
m = i | |
} | |
} | |
result = rcv[m] | |
return | |
} | |
// MinBy returns an element of Foods containing the minimum value, when compared to other elements using a passed func defining ‘less’. In the case of multiple items being equally minimal, the first such element is returned. Returns error if no elements. See: http://clipperhouse.github.io/gen/#MinBy | |
func (rcv Foods) MinBy(less func(*Food, *Food) bool) (result *Food, err error) { | |
l := len(rcv) | |
if l == 0 { | |
err = errors.New("cannot determine the Min of an empty slice") | |
return | |
} | |
m := 0 | |
for i := 1; i < l; i++ { | |
if less(rcv[i], rcv[m]) { | |
m = i | |
} | |
} | |
result = rcv[m] | |
return | |
} | |
// Single returns exactly one element of Foods that returns true for the passed func. Returns error if no or multiple elements return true. See: http://clipperhouse.github.io/gen/#Single | |
func (rcv Foods) Single(fn func(*Food) bool) (result *Food, err error) { | |
var candidate *Food | |
found := false | |
for _, v := range rcv { | |
if fn(v) { | |
if found { | |
err = errors.New("multiple Foods elements return true for passed func") | |
return | |
} | |
candidate = v | |
found = true | |
} | |
} | |
if found { | |
result = candidate | |
} else { | |
err = errors.New("no Foods elements return true for passed func") | |
} | |
return | |
} | |
// SortBy returns a new ordered Foods slice, determined by a func defining ‘less’. See: http://clipperhouse.github.io/gen/#SortBy | |
func (rcv Foods) SortBy(less func(*Food, *Food) bool) Foods { | |
result := make(Foods, len(rcv)) | |
copy(result, rcv) | |
// Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached. | |
n := len(result) | |
maxDepth := 0 | |
for i := n; i > 0; i >>= 1 { | |
maxDepth++ | |
} | |
maxDepth *= 2 | |
quickSortFoods(result, less, 0, n, maxDepth) | |
return result | |
} | |
// SortByDesc returns a new, descending-ordered Foods slice, determined by a func defining ‘less’. See: http://clipperhouse.github.io/gen/#SortBy | |
func (rcv Foods) SortByDesc(less func(*Food, *Food) bool) Foods { | |
greater := func(a, b *Food) bool { | |
return a != b && !less(a, b) | |
} | |
return rcv.SortBy(greater) | |
} | |
// Where returns a new Foods slice whose elements return true for func. See: http://clipperhouse.github.io/gen/#Where | |
func (rcv Foods) Where(fn func(*Food) bool) (result Foods) { | |
for _, v := range rcv { | |
if fn(v) { | |
result = append(result, v) | |
} | |
} | |
return result | |
} | |
// Sort support methods | |
func swapFoods(rcv Foods, a, b int) { | |
rcv[a], rcv[b] = rcv[b], rcv[a] | |
} | |
// Insertion sort | |
func insertionSortFoods(rcv Foods, less func(*Food, *Food) bool, a, b int) { | |
for i := a + 1; i < b; i++ { | |
for j := i; j > a && less(rcv[j], rcv[j-1]); j-- { | |
swapFoods(rcv, j, j-1) | |
} | |
} | |
} | |
// siftDown implements the heap property on rcv[lo, hi). | |
// first is an offset into the array where the root of the heap lies. | |
func siftDownFoods(rcv Foods, less func(*Food, *Food) bool, lo, hi, first int) { | |
root := lo | |
for { | |
child := 2*root + 1 | |
if child >= hi { | |
break | |
} | |
if child+1 < hi && less(rcv[first+child], rcv[first+child+1]) { | |
child++ | |
} | |
if !less(rcv[first+root], rcv[first+child]) { | |
return | |
} | |
swapFoods(rcv, first+root, first+child) | |
root = child | |
} | |
} | |
func heapSortFoods(rcv Foods, less func(*Food, *Food) bool, a, b int) { | |
first := a | |
lo := 0 | |
hi := b - a | |
// Build heap with greatest element at top. | |
for i := (hi - 1) / 2; i >= 0; i-- { | |
siftDownFoods(rcv, less, i, hi, first) | |
} | |
// Pop elements, largest first, into end of rcv. | |
for i := hi - 1; i >= 0; i-- { | |
swapFoods(rcv, first, first+i) | |
siftDownFoods(rcv, less, lo, i, first) | |
} | |
} | |
// Quicksort, following Bentley and McIlroy, | |
// Engineering a Sort Function, SP&E November 1993. | |
// medianOfThree moves the median of the three values rcv[a], rcv[b], rcv[c] into rcv[a]. | |
func medianOfThreeFoods(rcv Foods, less func(*Food, *Food) bool, a, b, c int) { | |
m0 := b | |
m1 := a | |
m2 := c | |
// bubble sort on 3 elements | |
if less(rcv[m1], rcv[m0]) { | |
swapFoods(rcv, m1, m0) | |
} | |
if less(rcv[m2], rcv[m1]) { | |
swapFoods(rcv, m2, m1) | |
} | |
if less(rcv[m1], rcv[m0]) { | |
swapFoods(rcv, m1, m0) | |
} | |
// now rcv[m0] <= rcv[m1] <= rcv[m2] | |
} | |
func swapRangeFoods(rcv Foods, a, b, n int) { | |
for i := 0; i < n; i++ { | |
swapFoods(rcv, a+i, b+i) | |
} | |
} | |
func doPivotFoods(rcv Foods, less func(*Food, *Food) bool, lo, hi int) (midlo, midhi int) { | |
m := lo + (hi-lo)/2 // Written like this to avoid integer overflow. | |
if hi-lo > 40 { | |
// Tukey's Ninther, median of three medians of three. | |
s := (hi - lo) / 8 | |
medianOfThreeFoods(rcv, less, lo, lo+s, lo+2*s) | |
medianOfThreeFoods(rcv, less, m, m-s, m+s) | |
medianOfThreeFoods(rcv, less, hi-1, hi-1-s, hi-1-2*s) | |
} | |
medianOfThreeFoods(rcv, less, lo, m, hi-1) | |
// Invariants are: | |
// rcv[lo] = pivot (set up by ChoosePivot) | |
// rcv[lo <= i < a] = pivot | |
// rcv[a <= i < b] < pivot | |
// rcv[b <= i < c] is unexamined | |
// rcv[c <= i < d] > pivot | |
// rcv[d <= i < hi] = pivot | |
// | |
// Once b meets c, can swap the "= pivot" sections | |
// into the middle of the slice. | |
pivot := lo | |
a, b, c, d := lo+1, lo+1, hi, hi | |
for { | |
for b < c { | |
if less(rcv[b], rcv[pivot]) { // rcv[b] < pivot | |
b++ | |
} else if !less(rcv[pivot], rcv[b]) { // rcv[b] = pivot | |
swapFoods(rcv, a, b) | |
a++ | |
b++ | |
} else { | |
break | |
} | |
} | |
for b < c { | |
if less(rcv[pivot], rcv[c-1]) { // rcv[c-1] > pivot | |
c-- | |
} else if !less(rcv[c-1], rcv[pivot]) { // rcv[c-1] = pivot | |
swapFoods(rcv, c-1, d-1) | |
c-- | |
d-- | |
} else { | |
break | |
} | |
} | |
if b >= c { | |
break | |
} | |
// rcv[b] > pivot; rcv[c-1] < pivot | |
swapFoods(rcv, b, c-1) | |
b++ | |
c-- | |
} | |
min := func(a, b int) int { | |
if a < b { | |
return a | |
} | |
return b | |
} | |
n := min(b-a, a-lo) | |
swapRangeFoods(rcv, lo, b-n, n) | |
n = min(hi-d, d-c) | |
swapRangeFoods(rcv, c, hi-n, n) | |
return lo + b - a, hi - (d - c) | |
} | |
func quickSortFoods(rcv Foods, less func(*Food, *Food) bool, a, b, maxDepth int) { | |
for b-a > 7 { | |
if maxDepth == 0 { | |
heapSortFoods(rcv, less, a, b) | |
return | |
} | |
maxDepth-- | |
mlo, mhi := doPivotFoods(rcv, less, a, b) | |
// Avoiding recursion on the larger subproblem guarantees | |
// a stack depth of at most lg(b-a). | |
if mlo-a < b-mhi { | |
quickSortFoods(rcv, less, a, mlo, maxDepth) | |
a = mhi // i.e., quickSortFoods(rcv, mhi, b) | |
} else { | |
quickSortFoods(rcv, less, mhi, b, maxDepth) | |
b = mlo // i.e., quickSortFoods(rcv, a, mlo) | |
} | |
} | |
if b-a > 1 { | |
insertionSortFoods(rcv, less, a, b) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment