Skip to content

Instantly share code, notes, and snippets.

@mattn
Created September 26, 2014 12:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattn/6daf8425916fc9a9f516 to your computer and use it in GitHub Desktop.
Save mattn/6daf8425916fc9a9f516 to your computer and use it in GitHub Desktop.
// 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