diff --git a/ProgressTest/DataInit.go b/ProgressTest/DataInit.go index 50284a8..7a85a49 100644 --- a/ProgressTest/DataInit.go +++ b/ProgressTest/DataInit.go @@ -8,7 +8,7 @@ package ProgressTest import ( "Go-Tool/util/file" - "Go-Tool/util/jsonEnhance" + "encoding/json" ) type DeliverList struct { @@ -24,6 +24,6 @@ type Deliver struct { func MakeData() DeliverList { var deliver DeliverList content, _ := file.ReadJsonFile("F:\\Go_BySelf\\src\\Go-Tool\\ProgressTest\\deliverData.json") - jsonEnhance.UnmarshalFromString(content, &deliver) + _ = json.Unmarshal([]byte(content), &deliver) return deliver } diff --git a/ProgressTest/DeliverRule2_test.go b/ProgressTest/DeliverRule2_test.go index cbe40d2..71556bb 100644 --- a/ProgressTest/DeliverRule2_test.go +++ b/ProgressTest/DeliverRule2_test.go @@ -9,13 +9,14 @@ package ProgressTest import ( "Go-Tool/util/rand" "fmt" + _ "github.com/ahmetb/go-linq" "math" "testing" ) const ( MinGroupNum = 10 - MaxGroupNum = 80 + MaxGroupNum = 30 ) //需求(直接举例): @@ -26,22 +27,16 @@ const ( //第四步:40每组的数据,要分成最后的10 * 4 的4组,按照每次取前5再随机取5个组成一组的方式组成4组 //第五步:不足4组的,按照取前5和随机5个的方式进行分组 func TestDeliver2(t *testing.T) { - - firstOrderRule = FirstOrderRule - secondOrderRule = SecondOrderRule - thirdOrderRule = ThirdOrderRule - - list := MakeData() //创建数据 - resultList := deliver2(list.Deliver) //进行分组操作 + dataList := MakeData() //创建数据 + resultList := deliver2(dataList.Deliver) //进行分组操作 fmt.Printf(fmt.Sprintf("%v", resultList)) } func deliver2(delivers []*Deliver) [][]int { - resultList := make([][]int, 0) newDelivers := make([]*Deliver, 0) //获得第一次按照大区间分组后剩下的元素数量、第一次分组所有组、分到的大组数量 - leaveNum, partitions, partition := FirstOrder(delivers, newDelivers) + leaveNum, partitions, partition, newDelivers := FirstOrder(delivers, newDelivers) resultList = withCompletePartition(partitions, resultList) //对完整的分组进行处理 resultList = withLeavePartition(resultList, newDelivers, leaveNum, partition) //对剩余的分组进行处理 @@ -63,7 +58,7 @@ func withCompletePartition(partitions [][]*Deliver, resultList [][]int) [][]int return resultList } -func FirstOrder(delivers []*Deliver, newDelivers []*Deliver) (int, [][]*Deliver, int) { +func FirstOrder(delivers []*Deliver, newDelivers []*Deliver) (int, [][]*Deliver, int, []*Deliver) { newDelivers = firstOrderRule(delivers) //第一次排序 partition := len(newDelivers) / MaxGroupNum leaveNum := len(newDelivers) % MaxGroupNum @@ -72,25 +67,29 @@ func FirstOrder(delivers []*Deliver, newDelivers []*Deliver) (int, [][]*Deliver, for i := 0; i < partition; i++ { partitions = append(partitions, newDelivers[i*MaxGroupNum:(i+1)*MaxGroupNum]) } - return leaveNum, partitions, partition + return leaveNum, partitions, partition, newDelivers } func secondOrder(delivers []*Deliver, resultList [][]int, listNum int) [][]int { newDelivers := secondOrderRule(delivers) //第二次排序 if listNum > 4*MinGroupNum { - fourInOne := listNum / (4 * MinGroupNum) - leave := listNum % (4 * MinGroupNum) - - for i := 0; i < fourInOne; i++ { - resultList = append(resultList, calculateFourInOne(newDelivers[i*4*MinGroupNum:(i+1)*4*MinGroupNum])...) //四倍在一组的计算 - } - - if leave != 0 { - resultList = append(resultList, calculateByLeft(toList(newDelivers[fourInOne*4*MinGroupNum:]))...) - } + resultList = moreThenFour(listNum, resultList, newDelivers) //大于4倍区间的处理 } else { - resultList = append(resultList, calculateByLeft(toList(newDelivers))...) + resultList = append(resultList, calculateByLeft(thirdOrderRule(newDelivers))...) + } + return resultList +} + +func moreThenFour(listNum int, resultList [][]int, newDelivers []*Deliver) [][]int { + fourInOne := listNum / (4 * MinGroupNum) + leave := listNum % (4 * MinGroupNum) + + for i := 0; i < fourInOne; i++ { + resultList = append(resultList, calculateByLeft(thirdOrderRule(newDelivers[i*4*MinGroupNum:(i+1)*4*MinGroupNum]))...) //四倍在一组的计算 + } + if leave != 0 { + resultList = append(resultList, calculateByLeft(thirdOrderRule(newDelivers[fourInOne*4*MinGroupNum:]))...) } return resultList } @@ -103,12 +102,6 @@ func toList(deliver []*Deliver) [][]int { return result } -func calculateFourInOne(delivers []*Deliver) [][]int { - Ids := thirdOrderRule(delivers) //第三次排序 - result := calculateByLeft(Ids) - return result -} - func calculateByLeft(leftList [][]int) [][]int { result := make([][]int, 0) for len(leftList) != 0 { @@ -138,3 +131,11 @@ func getFirstSome(list [][]int) []int { func getFrontAndEnd(leftList [][]int) ([]int, [][]int) { return rand.GetAwardByWeightWithLeftAward(leftList) } + +func init() { + //初始化排序规则 + firstOrderRule = FirstOrderRule + secondOrderRule = SecondOrderRule + thirdOrderRule = ThirdOrderRule + +} diff --git a/ProgressTest/DeliverRule_test.go b/ProgressTest/DeliverRule_test.go index 2da8bb0..a3ac009 100644 --- a/ProgressTest/DeliverRule_test.go +++ b/ProgressTest/DeliverRule_test.go @@ -1,7 +1,7 @@ /* * @Author : huangzj * @Time : 2020/11/13 12:00 - * @Description:在工程中有一个需求是对 指定数量的数组进行划分,按照每一层的规则分成对应数量,这边做一个测试. + * @Description:在工程中有一个需求是对 指定数量的数组进行划分,按照每一层的规则分成对应数量,这边做一个测试.(这种方式写的代码太麻烦了,直接废弃,后面有机会再弄) */ package ProgressTest @@ -9,7 +9,7 @@ package ProgressTest import ( "Go-Tool/util/rand" "fmt" - "github.com/ahmetalpbalkan/go-linq" + "github.com/ahmetb/go-linq" "testing" ) diff --git a/ProgressTest/OrderRule.go b/ProgressTest/OrderRule.go index 798c567..fbecf09 100644 --- a/ProgressTest/OrderRule.go +++ b/ProgressTest/OrderRule.go @@ -6,7 +6,7 @@ package ProgressTest -import "github.com/ahmetalpbalkan/go-linq" +import "github.com/ahmetb/go-linq" type orderRule = func([]*Deliver) []*Deliver type intOrderRule = func([]*Deliver) [][]int diff --git a/readme.md b/readme.md index 4b98fec..c44a9d9 100644 --- a/readme.md +++ b/readme.md @@ -58,6 +58,7 @@ 2020/11/16:新增项目案例(按照一定规则对一组数据进行排序分组) +2020/11/23:修改项目案例(按照一定规则对一组数据进行排序分组) # mod vendor模式加载包 通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到 diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/LICENSE b/vendor/github.com/ahmetalpbalkan/go-linq/LICENSE deleted file mode 100644 index 71dd824..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/LICENSE +++ /dev/null @@ -1,14 +0,0 @@ -Copyright 2016 Ahmet Alp Balkan - -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. - diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/aggregate.go b/vendor/github.com/ahmetalpbalkan/go-linq/aggregate.go deleted file mode 100644 index a8658c5..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/aggregate.go +++ /dev/null @@ -1,53 +0,0 @@ -package linq - -// Aggregate applies an accumulator function over a sequence. -// -// Aggregate method makes it simple to perform a calculation over a sequence of values. -// This method works by calling f() one time for each element in source -// except the first one. Each time f() is called, Aggregate passes both -// the element from the sequence and an aggregated value (as the first argument to f()). -// The first element of source is used as the initial aggregate value. -// The result of f() replaces the previous aggregated value. -// -// Aggregate returns the final result of f(). -func (q Query) Aggregate( - f func(interface{}, interface{}) interface{}) interface{} { - next := q.Iterate() - - result, any := next() - if !any { - return nil - } - - for current, ok := next(); ok; current, ok = next() { - result = f(result, current) - } - - return result -} - -// AggregateWithSeed applies an accumulator function over a sequence. -// The specified seed value is used as the initial accumulator value. -// -// Aggregate method makes it simple to perform a calculation over a sequence of values. -// This method works by calling f() one time for each element in source -// except the first one. Each time f() is called, Aggregate passes both -// the element from the sequence and an aggregated value (as the first argument to f()). -// The value of the seed parameter is used as the initial aggregate value. -// The result of f() replaces the previous aggregated value. -// -// Aggregate returns the final result of f(). -func (q Query) AggregateWithSeed( - seed interface{}, - f func(interface{}, interface{}) interface{}, -) interface{} { - - next := q.Iterate() - result := seed - - for current, ok := next(); ok; current, ok = next() { - result = f(result, current) - } - - return result -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/doc.go b/vendor/github.com/ahmetalpbalkan/go-linq/doc.go deleted file mode 100644 index 8231f70..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package linq provides methods for querying and manipulating -// slices, arrays, maps, strings, channels and collections. -// -// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan -package linq diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/except.go b/vendor/github.com/ahmetalpbalkan/go-linq/except.go deleted file mode 100644 index c34a6b4..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/except.go +++ /dev/null @@ -1,59 +0,0 @@ -package linq - -// Except produces the set difference of two sequences. -// The set difference is the members of the first sequence -// that don't appear in the second sequence. -func (q Query) Except(q2 Query) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - - next2 := q2.Iterate() - set := make(map[interface{}]bool) - for i, ok := next2(); ok; i, ok = next2() { - set[i] = true - } - - return func() (item interface{}, ok bool) { - for item, ok = next(); ok; item, ok = next() { - if _, has := set[item]; !has { - return - } - } - - return - } - }, - } -} - -// ExceptBy invokes a transform function on each element of a collection -// and produces the set difference of two sequences. -// The set difference is the members of the first sequence -// that don't appear in the second sequence. -func (q Query) ExceptBy( - q2 Query, selector func(interface{}) interface{}) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - - next2 := q2.Iterate() - set := make(map[interface{}]bool) - for i, ok := next2(); ok; i, ok = next2() { - s := selector(i) - set[s] = true - } - - return func() (item interface{}, ok bool) { - for item, ok = next(); ok; item, ok = next() { - s := selector(item) - if _, has := set[s]; !has { - return - } - } - - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/groupby.go b/vendor/github.com/ahmetalpbalkan/go-linq/groupby.go deleted file mode 100644 index 2affbf8..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/groupby.go +++ /dev/null @@ -1,48 +0,0 @@ -package linq - -// Group is a type that is used to store the result of GroupBy method. -type Group struct { - Key interface{} - Group []interface{} -} - -// GroupBy method groups the elements of a collection according -// to a specified key selector function and projects the elements for each group -// by using a specified function. -func (q Query) GroupBy( - keySelector func(interface{}) interface{}, - elementSelector func(interface{}) interface{}, -) Query { - - return Query{ - func() Iterator { - next := q.Iterate() - set := make(map[interface{}][]interface{}) - - for item, ok := next(); ok; item, ok = next() { - key := keySelector(item) - set[key] = append(set[key], elementSelector(item)) - } - - len := len(set) - idx := 0 - groups := make([]Group, len) - for k, v := range set { - groups[idx] = Group{k, v} - idx++ - } - - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = groups[index] - index++ - } - - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/groupjoin.go b/vendor/github.com/ahmetalpbalkan/go-linq/groupjoin.go deleted file mode 100644 index 7a3b56b..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/groupjoin.go +++ /dev/null @@ -1,50 +0,0 @@ -package linq - -// GroupJoin correlates the elements of two collections based on key equality, -// and groups the results. -// -// This method produces hierarchical results, which means that elements from outer query -// are paired with collections of matching elements from inner. GroupJoin enables you -// to base your results on a whole set of matches for each element of outer query. -// -// The resultSelector function is called only one time for each outer element -// together with a collection of all the inner elements that match the outer element. -// This differs from the Join method, in which the result selector function is invoked -// on pairs that contain one element from outer and one element from inner. -// -// GroupJoin preserves the order of the elements of outer, and for each element of outer, -// the order of the matching elements from inner. -func (q Query) GroupJoin( - inner Query, - outerKeySelector func(interface{}) interface{}, - innerKeySelector func(interface{}) interface{}, - resultSelector func(outer interface{}, inners []interface{}) interface{}, -) Query { - - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - innernext := inner.Iterate() - - innerLookup := make(map[interface{}][]interface{}) - for innerItem, ok := innernext(); ok; innerItem, ok = innernext() { - innerKey := innerKeySelector(innerItem) - innerLookup[innerKey] = append(innerLookup[innerKey], innerItem) - } - - return func() (item interface{}, ok bool) { - if item, ok = outernext(); !ok { - return - } - - if group, has := innerLookup[outerKeySelector(item)]; !has { - item = resultSelector(item, []interface{}{}) - } else { - item = resultSelector(item, group) - } - - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/join.go b/vendor/github.com/ahmetalpbalkan/go-linq/join.go deleted file mode 100644 index 95cb835..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/join.go +++ /dev/null @@ -1,56 +0,0 @@ -package linq - -// Join correlates the elements of two collection based on matching keys. -// -// A join refers to the operation of correlating the elements of two sources -// of information based on a common key. Join brings the two information sources -// and the keys by which they are matched together in one method call. -// This differs from the use of SelectMany, which requires more than one method call -// to perform the same operation. -// -// Join preserves the order of the elements of outer collection, -// and for each of these elements, the order of the matching elements of inner. -func (q Query) Join( - inner Query, - outerKeySelector func(interface{}) interface{}, - innerKeySelector func(interface{}) interface{}, - resultSelector func(outer interface{}, inner interface{}) interface{}, -) Query { - - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - innernext := inner.Iterate() - - innerLookup := make(map[interface{}][]interface{}) - for innerItem, ok := innernext(); ok; innerItem, ok = innernext() { - innerKey := innerKeySelector(innerItem) - innerLookup[innerKey] = append(innerLookup[innerKey], innerItem) - } - - var outerItem interface{} - var innerGroup []interface{} - innerLen, innerIndex := 0, 0 - - return func() (item interface{}, ok bool) { - if innerIndex >= innerLen { - has := false - for !has { - outerItem, ok = outernext() - if !ok { - return - } - - innerGroup, has = innerLookup[outerKeySelector(outerItem)] - innerLen = len(innerGroup) - innerIndex = 0 - } - } - - item = resultSelector(outerItem, innerGroup[innerIndex]) - innerIndex++ - return item, true - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/orderby.go b/vendor/github.com/ahmetalpbalkan/go-linq/orderby.go deleted file mode 100644 index ff7f5ce..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/orderby.go +++ /dev/null @@ -1,212 +0,0 @@ -package linq - -import "sort" - -type order struct { - selector func(interface{}) interface{} - compare comparer - desc bool -} - -// OrderedQuery is the type returned from OrderBy, OrderByDescending -// ThenBy and ThenByDescending functions. -type OrderedQuery struct { - Query - original Query - orders []order -} - -// OrderBy sorts the elements of a collection in ascending order. -// Elements are sorted according to a key. -func (q Query) OrderBy( - selector func(interface{}) interface{}) OrderedQuery { - return OrderedQuery{ - orders: []order{{selector: selector}}, - original: q, - Query: Query{ - Iterate: func() Iterator { - items := q.sort([]order{{selector: selector}}) - len := len(items) - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = items[index] - index++ - } - - return - } - }, - }, - } -} - -// OrderByDescending sorts the elements of a collection in descending order. -// Elements are sorted according to a key. -func (q Query) OrderByDescending( - selector func(interface{}) interface{}) OrderedQuery { - return OrderedQuery{ - orders: []order{{selector: selector, desc: true}}, - original: q, - Query: Query{ - Iterate: func() Iterator { - items := q.sort([]order{{selector: selector, desc: true}}) - len := len(items) - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = items[index] - index++ - } - - return - } - }, - }, - } -} - -// ThenBy performs a subsequent ordering of the elements in a collection -// in ascending order. This method enables you to specify multiple sort criteria -// by applying any number of ThenBy or ThenByDescending methods. -func (oq OrderedQuery) ThenBy( - selector func(interface{}) interface{}) OrderedQuery { - return OrderedQuery{ - orders: append(oq.orders, order{selector: selector}), - original: oq.original, - Query: Query{ - Iterate: func() Iterator { - items := oq.original.sort(append(oq.orders, order{selector: selector})) - len := len(items) - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = items[index] - index++ - } - - return - } - }, - }, - } -} - -// ThenByDescending performs a subsequent ordering of the elements in a collection -// in descending order. This method enables you to specify multiple sort criteria -// by applying any number of ThenBy or ThenByDescending methods. -func (oq OrderedQuery) ThenByDescending( - selector func(interface{}) interface{}) OrderedQuery { - return OrderedQuery{ - orders: append(oq.orders, order{selector: selector, desc: true}), - original: oq.original, - Query: Query{ - Iterate: func() Iterator { - items := oq.original.sort(append(oq.orders, order{selector: selector, desc: true})) - len := len(items) - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = items[index] - index++ - } - - return - } - }, - }, - } -} - -// Sort returns a new query by sorting elements with provided less function -// in ascending order. The comparer function should return true if the parameter i -// is less than j. While this method is uglier than chaining OrderBy, OrderByDescending, -// ThenBy and ThenByDescending methods, it's performance is much better. -func (q Query) Sort(less func(i, j interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - items := q.lessSort(less) - len := len(items) - index := 0 - - return func() (item interface{}, ok bool) { - ok = index < len - if ok { - item = items[index] - index++ - } - - return - } - }, - } -} - -type sorter struct { - items []interface{} - less func(i, j interface{}) bool -} - -func (s sorter) Len() int { - return len(s.items) -} - -func (s sorter) Swap(i, j int) { - s.items[i], s.items[j] = s.items[j], s.items[i] -} - -func (s sorter) Less(i, j int) bool { - return s.less(s.items[i], s.items[j]) -} - -func (q Query) sort(orders []order) (r []interface{}) { - next := q.Iterate() - for item, ok := next(); ok; item, ok = next() { - r = append(r, item) - } - - for i, j := range orders { - orders[i].compare = getComparer(j.selector(r[0])) - } - - s := sorter{ - items: r, - less: func(i, j interface{}) bool { - for _, order := range orders { - x, y := order.selector(i), order.selector(j) - switch order.compare(x, y) { - case 0: - continue - case -1: - return !order.desc - default: - return order.desc - } - } - - return false - }} - - sort.Sort(s) - return -} - -func (q Query) lessSort(less func(i, j interface{}) bool) (r []interface{}) { - next := q.Iterate() - for item, ok := next(); ok; item, ok = next() { - r = append(r, item) - } - - s := sorter{items: r, less: less} - - sort.Sort(s) - return -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/result.go b/vendor/github.com/ahmetalpbalkan/go-linq/result.go deleted file mode 100644 index 979be93..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/result.go +++ /dev/null @@ -1,394 +0,0 @@ -package linq - -import ( - "math" - "reflect" -) - -// All determines whether all elements of a collection satisfy a condition. -func (q Query) All(predicate func(interface{}) bool) bool { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if !predicate(item) { - return false - } - } - - return true -} - -// Any determines whether any element of a collection exists. -func (q Query) Any() bool { - _, ok := q.Iterate()() - return ok -} - -// AnyWith determines whether any element of a collection satisfies a condition. -func (q Query) AnyWith(predicate func(interface{}) bool) bool { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if predicate(item) { - return true - } - } - - return false -} - -// Average computes the average of a collection of numeric values. -func (q Query) Average() (r float64) { - next := q.Iterate() - item, ok := next() - if !ok { - return math.NaN() - } - - n := 1 - switch item.(type) { - case int, int8, int16, int32, int64: - conv := getIntConverter(item) - sum := conv(item) - - for item, ok = next(); ok; item, ok = next() { - sum += conv(item) - n++ - } - - r = float64(sum) - case uint, uint8, uint16, uint32, uint64: - conv := getUIntConverter(item) - sum := conv(item) - - for item, ok = next(); ok; item, ok = next() { - sum += conv(item) - n++ - } - - r = float64(sum) - default: - conv := getFloatConverter(item) - r = conv(item) - - for item, ok = next(); ok; item, ok = next() { - r += conv(item) - n++ - } - } - - return r / float64(n) -} - -// Contains determines whether a collection contains a specified element. -func (q Query) Contains(value interface{}) bool { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if item == value { - return true - } - } - - return false -} - -// Count returns the number of elements in a collection. -func (q Query) Count() (r int) { - next := q.Iterate() - - for _, ok := next(); ok; _, ok = next() { - r++ - } - - return -} - -// CountWith returns a number that represents how many elements -// in the specified collection satisfy a condition. -func (q Query) CountWith(predicate func(interface{}) bool) (r int) { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if predicate(item) { - r++ - } - } - - return -} - -// First returns the first element of a collection. -func (q Query) First() interface{} { - item, _ := q.Iterate()() - return item -} - -// FirstWith returns the first element of a collection that satisfies -// a specified condition. -func (q Query) FirstWith(predicate func(interface{}) bool) interface{} { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if predicate(item) { - return item - } - } - - return nil -} - -// Last returns the last element of a collection. -func (q Query) Last() (r interface{}) { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - r = item - } - - return -} - -// LastWith returns the last element of a collection that satisfies -// a specified condition. -func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - if predicate(item) { - r = item - } - } - - return -} - -// Max returns the maximum value in a collection of values. -func (q Query) Max() (r interface{}) { - next := q.Iterate() - item, ok := next() - if !ok { - return nil - } - - compare := getComparer(item) - r = item - - for item, ok := next(); ok; item, ok = next() { - if compare(item, r) > 0 { - r = item - } - } - - return -} - -// Min returns the minimum value in a collection of values. -func (q Query) Min() (r interface{}) { - next := q.Iterate() - item, ok := next() - if !ok { - return nil - } - - compare := getComparer(item) - r = item - - for item, ok := next(); ok; item, ok = next() { - if compare(item, r) < 0 { - r = item - } - } - - return -} - -// Results iterates over a collection and returnes slice of interfaces -func (q Query) Results() (r []interface{}) { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - r = append(r, item) - } - - return -} - -// SequenceEqual determines whether two collections are equal. -func (q Query) SequenceEqual(q2 Query) bool { - next := q.Iterate() - next2 := q2.Iterate() - - for item, ok := next(); ok; item, ok = next() { - item2, ok2 := next2() - if !ok2 || item != item2 { - return false - } - } - - _, ok2 := next2() - return !ok2 -} - -// Single returns the only element of a collection, and nil -// if there is not exactly one element in the collection. -func (q Query) Single() interface{} { - next := q.Iterate() - item, ok := next() - if !ok { - return nil - } - - _, ok = next() - if ok { - return nil - } - - return item -} - -// SingleWith returns the only element of a collection that satisfies -// a specified condition, and nil if more than one such element exists. -func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) { - next := q.Iterate() - found := false - - for item, ok := next(); ok; item, ok = next() { - if predicate(item) { - if found { - return nil - } - - found = true - r = item - } - } - - return -} - -// SumInts computes the sum of a collection of numeric values. -// -// Values can be of any integer type: int, int8, int16, int32, int64. -// The result is int64. Method returns zero if collection contains no elements. -func (q Query) SumInts() (r int64) { - next := q.Iterate() - item, ok := next() - if !ok { - return 0 - } - - conv := getIntConverter(item) - r = conv(item) - - for item, ok = next(); ok; item, ok = next() { - r += conv(item) - } - - return -} - -// SumUInts computes the sum of a collection of numeric values. -// -// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64. -// The result is uint64. Method returns zero if collection contains no elements. -func (q Query) SumUInts() (r uint64) { - next := q.Iterate() - item, ok := next() - if !ok { - return 0 - } - - conv := getUIntConverter(item) - r = conv(item) - - for item, ok = next(); ok; item, ok = next() { - r += conv(item) - } - - return -} - -// SumFloats computes the sum of a collection of numeric values. -// -// Values can be of any float type: float32 or float64. The result is float64. -// Method returns zero if collection contains no elements. -func (q Query) SumFloats() (r float64) { - next := q.Iterate() - item, ok := next() - if !ok { - return 0 - } - - conv := getFloatConverter(item) - r = conv(item) - - for item, ok = next(); ok; item, ok = next() { - r += conv(item) - } - - return -} - -// ToChannel iterates over a collection and outputs each element -// to a channel, then closes it. -func (q Query) ToChannel(result chan<- interface{}) { - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - result <- item - } - - close(result) -} - -// ToMap iterates over a collection and populates result map with elements. -// Collection elements have to be of KeyValue type to use this method. -// To populate a map with elements of different type use ToMapBy method. -func (q Query) ToMap(result interface{}) { - q.ToMapBy( - result, - func(i interface{}) interface{} { - return i.(KeyValue).Key - }, - func(i interface{}) interface{} { - return i.(KeyValue).Value - }) -} - -// ToMapBy iterates over a collection and populates result map with elements. -// Functions keySelector and valueSelector are executed for each element of the collection -// to generate key and value for the map. Generated key and value types must be assignable -// to the map's key and value types. -func (q Query) ToMapBy( - result interface{}, - keySelector func(interface{}) interface{}, - valueSelector func(interface{}) interface{}, -) { - res := reflect.ValueOf(result) - m := reflect.Indirect(res) - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - key := reflect.ValueOf(keySelector(item)) - value := reflect.ValueOf(valueSelector(item)) - - m.SetMapIndex(key, value) - } - - res.Elem().Set(m) -} - -// ToSlice iterates over a collection and populates result slice with elements. -// Collection elements must be assignable to the slice's element type. -func (q Query) ToSlice(result interface{}) { - res := reflect.ValueOf(result) - slice := reflect.Indirect(res) - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - slice = reflect.Append(slice, reflect.ValueOf(item)) - } - - res.Elem().Set(slice) -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/select.go b/vendor/github.com/ahmetalpbalkan/go-linq/select.go deleted file mode 100644 index e607229..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/select.go +++ /dev/null @@ -1,71 +0,0 @@ -package linq - -// Select projects each element of a collection into a new form. -// Returns a query with the result of invoking the transform function -// on each element of original source. -// -// This projection method requires the transform function, selector, -// to produce one value for each value in the source collection. -// If selector returns a value that is itself a collection, -// it is up to the consumer to traverse the subcollections manually. -// In such a situation, it might be better for your query to return a single -// coalesced collection of values. To achieve this, use the SelectMany method -// instead of Select. Although SelectMany works similarly to Select, -// it differs in that the transform function returns a collection -// that is then expanded by SelectMany before it is returned. -func (q Query) Select(selector func(interface{}) interface{}) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - - return func() (item interface{}, ok bool) { - var it interface{} - it, ok = next() - if ok { - item = selector(it) - } - - return - } - }, - } -} - -// SelectIndexed projects each element of a collection into a new form -// by incorporating the element's index. Returns a query with the result -// of invoking the transform function on each element of original source. -// -// The first argument to selector represents the zero-based index of that element -// in the source collection. This can be useful if the elements are in a known order -// and you want to do something with an element at a particular index, -// for example. It can also be useful if you want to retrieve the index of one -// or more elements. The second argument to selector represents the element to process. -// -// This projection method requires the transform function, selector, -// to produce one value for each value in the source collection. -// If selector returns a value that is itself a collection, -// it is up to the consumer to traverse the subcollections manually. -// In such a situation, it might be better for your query to return a single -// coalesced collection of values. To achieve this, use the SelectMany method -// instead of Select. Although SelectMany works similarly to Select, -// it differs in that the transform function returns a collection -// that is then expanded by SelectMany before it is returned. -func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - index := 0 - - return func() (item interface{}, ok bool) { - var it interface{} - it, ok = next() - if ok { - item = selector(index, it) - index++ - } - - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/selectmany.go b/vendor/github.com/ahmetalpbalkan/go-linq/selectmany.go deleted file mode 100644 index 25ea8c3..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/selectmany.go +++ /dev/null @@ -1,151 +0,0 @@ -package linq - -// SelectMany projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection. -func (q Query) SelectMany(selector func(interface{}) Query) Query { - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - var inner interface{} - var innernext Iterator - - return func() (item interface{}, ok bool) { - for !ok { - if inner == nil { - inner, ok = outernext() - if !ok { - return - } - - innernext = selector(inner).Iterate() - } - - item, ok = innernext() - if !ok { - inner = nil - } - } - - return - } - }, - } -} - -// SelectManyIndexed projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection. -// -// The first argument to selector represents the zero-based index of that element -// in the source collection. This can be useful if the elements are in a known order -// and you want to do something with an element at a particular index, for example. -// It can also be useful if you want to retrieve the index of one or more elements. -// The second argument to selector represents the element to process. -func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query { - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - index := 0 - var inner interface{} - var innernext Iterator - - return func() (item interface{}, ok bool) { - for !ok { - if inner == nil { - inner, ok = outernext() - if !ok { - return - } - - innernext = selector(index, inner).Iterate() - index++ - } - - item, ok = innernext() - if !ok { - inner = nil - } - } - - return - } - }, - } -} - -// SelectManyBy projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection, and invokes -// a result selector function on each element therein. -func (q Query) SelectManyBy( - selector func(interface{}) Query, - resultSelector func(interface{}, interface{}) interface{}, -) Query { - - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - var outer interface{} - var innernext Iterator - - return func() (item interface{}, ok bool) { - for !ok { - if outer == nil { - outer, ok = outernext() - if !ok { - return - } - - innernext = selector(outer).Iterate() - } - - item, ok = innernext() - if !ok { - outer = nil - } - } - - item = resultSelector(outer, item) - return - } - }, - } -} - -// SelectManyByIndexed projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection, and invokes -// a result selector function on each element therein. -// The index of each source element is used in the intermediate projected form -// of that element. -func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query, - resultSelector func(interface{}, interface{}) interface{}) Query { - - return Query{ - Iterate: func() Iterator { - outernext := q.Iterate() - index := 0 - var outer interface{} - var innernext Iterator - - return func() (item interface{}, ok bool) { - for !ok { - if outer == nil { - outer, ok = outernext() - if !ok { - return - } - - innernext = selector(index, outer).Iterate() - index++ - } - - item, ok = innernext() - if !ok { - outer = nil - } - } - - item = resultSelector(outer, item) - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/skip.go b/vendor/github.com/ahmetalpbalkan/go-linq/skip.go deleted file mode 100644 index 1110ae5..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/skip.go +++ /dev/null @@ -1,91 +0,0 @@ -package linq - -// Skip bypasses a specified number of elements in a collection -// and then returns the remaining elements. -func (q Query) Skip(count int) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - n := count - - return func() (item interface{}, ok bool) { - for ; n > 0; n-- { - item, ok = next() - if !ok { - return - } - } - - return next() - } - }, - } -} - -// SkipWhile bypasses elements in a collection as long as a specified condition is true -// and then returns the remaining elements. -// -// This method tests each element by using predicate and skips the element -// if the result is true. After the predicate function returns false for an element, -// that element and the remaining elements in source are returned -// and there are no more invocations of predicate. -func (q Query) SkipWhile(predicate func(interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - ready := false - - return func() (item interface{}, ok bool) { - for !ready { - item, ok = next() - if !ok { - return - } - - ready = !predicate(item) - if ready { - return - } - } - - return next() - } - }, - } -} - -// SkipWhileIndexed bypasses elements in a collection as long as a specified condition -// is true and then returns the remaining elements. The element's index is used -// in the logic of the predicate function. -// -// This method tests each element by using predicate and skips the element -// if the result is true. After the predicate function returns false for an element, -// that element and the remaining elements in source are returned -// and there are no more invocations of predicate. -func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - ready := false - index := 0 - - return func() (item interface{}, ok bool) { - for !ready { - item, ok = next() - if !ok { - return - } - - ready = !predicate(index, item) - if ready { - return - } - - index++ - } - - return next() - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/take.go b/vendor/github.com/ahmetalpbalkan/go-linq/take.go deleted file mode 100644 index d21fc96..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/take.go +++ /dev/null @@ -1,84 +0,0 @@ -package linq - -// Take returns a specified number of contiguous elements from the start of a collection. -func (q Query) Take(count int) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - n := count - - return func() (item interface{}, ok bool) { - if n <= 0 { - return - } - - n-- - return next() - } - }, - } -} - -// TakeWhile returns elements from a collection as long as a specified condition is true, -// and then skips the remaining elements. -func (q Query) TakeWhile(predicate func(interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - done := false - - return func() (item interface{}, ok bool) { - if done { - return - } - - item, ok = next() - if !ok { - done = true - return - } - - if predicate(item) { - return - } - - done = true - return nil, false - } - }, - } -} - -// TakeWhileIndexed returns elements from a collection as long as a specified condition -// is true. The element's index is used in the logic of the predicate function. -// The first argument of predicate represents the zero-based index of the element -// within collection. The second argument represents the element to test. -func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - done := false - index := 0 - - return func() (item interface{}, ok bool) { - if done { - return - } - - item, ok = next() - if !ok { - done = true - return - } - - if predicate(index, item) { - index++ - return - } - - done = true - return nil, false - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/where.go b/vendor/github.com/ahmetalpbalkan/go-linq/where.go deleted file mode 100644 index 26d0bda..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/where.go +++ /dev/null @@ -1,46 +0,0 @@ -package linq - -// Where filters a collection of values based on a predicate. -func (q Query) Where(predicate func(interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - - return func() (item interface{}, ok bool) { - for item, ok = next(); ok; item, ok = next() { - if predicate(item) { - return - } - } - - return - } - }, - } -} - -// WhereIndexed filters a collection of values based on a predicate. -// Each element's index is used in the logic of the predicate function. -// -// The first argument represents the zero-based index of the element within collection. -// The second argument of predicate represents the element to test. -func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query { - return Query{ - Iterate: func() Iterator { - next := q.Iterate() - index := 0 - - return func() (item interface{}, ok bool) { - for item, ok = next(); ok; item, ok = next() { - if predicate(index, item) { - return - } - - index++ - } - - return - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/zip.go b/vendor/github.com/ahmetalpbalkan/go-linq/zip.go deleted file mode 100644 index 1314b9a..0000000 --- a/vendor/github.com/ahmetalpbalkan/go-linq/zip.go +++ /dev/null @@ -1,35 +0,0 @@ -package linq - -// Zip applies a specified function to the corresponding elements -// of two collections, producing a collection of the results. -// -// The method steps through the two input collections, applying function -// resultSelector to corresponding elements of the two collections. -// The method returns a collection of the values that are returned by resultSelector. -// If the input collections do not have the same number of elements, -// the method combines elements until it reaches the end of one of the collections. -// For example, if one collection has three elements and the other one has four, -// the result collection has only three elements. -func (q Query) Zip( - q2 Query, - resultSelector func(interface{}, interface{}) interface{}, -) Query { - - return Query{ - Iterate: func() Iterator { - next1 := q.Iterate() - next2 := q2.Iterate() - - return func() (item interface{}, ok bool) { - item1, ok1 := next1() - item2, ok2 := next2() - - if ok1 && ok2 { - return resultSelector(item1, item2), true - } - - return nil, false - } - }, - } -} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/.gitignore b/vendor/github.com/ahmetb/go-linq/.gitignore similarity index 100% rename from vendor/github.com/ahmetalpbalkan/go-linq/.gitignore rename to vendor/github.com/ahmetb/go-linq/.gitignore diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/.travis.yml b/vendor/github.com/ahmetb/go-linq/.travis.yml similarity index 97% rename from vendor/github.com/ahmetalpbalkan/go-linq/.travis.yml rename to vendor/github.com/ahmetb/go-linq/.travis.yml index 6587753..157e59f 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/.travis.yml +++ b/vendor/github.com/ahmetb/go-linq/.travis.yml @@ -2,14 +2,13 @@ sudo: false language: go go: - - 1.5 - 1.7 before_install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - go get -u github.com/golang/lint/golint - + script: - go vet -x ./... - golint ./... diff --git a/vendor/github.com/ahmetb/go-linq/LICENSE b/vendor/github.com/ahmetb/go-linq/LICENSE new file mode 100644 index 0000000..c1ab55f --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Ahmet Alp Balkan + + 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. diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/README.md b/vendor/github.com/ahmetb/go-linq/README.md similarity index 58% rename from vendor/github.com/ahmetalpbalkan/go-linq/README.md rename to vendor/github.com/ahmetb/go-linq/README.md index 475464c..4e9f12b 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/README.md +++ b/vendor/github.com/ahmetb/go-linq/README.md @@ -1,16 +1,21 @@ # go-linq [![GoDoc](https://godoc.org/github.com/ahmetalpbalkan/go-linq?status.svg)](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [![Build Status](https://travis-ci.org/ahmetalpbalkan/go-linq.svg?branch=master)](https://travis-ci.org/ahmetalpbalkan/go-linq) [![Coverage Status](https://coveralls.io/repos/github/ahmetalpbalkan/go-linq/badge.svg?branch=master)](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/ahmetalpbalkan/go-linq)](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq) A powerful language integrated query (LINQ) library for Go. -* Written in vanilla Go! -* Safe for concurrent use +* Written in vanilla Go, no dependencies! * Complete lazy evaluation with iterator pattern +* Safe for concurrent use +* Supports generic functions to make your code cleaner and free of type assertions * Supports arrays, slices, maps, strings, channels and custom collections -(collection needs to implement `Iterable` interface and element - `Comparable` -interface) ## Installation $ go get github.com/ahmetalpbalkan/go-linq +We recommend using a dependency manager (e.g. [govendor][govendor] or +[godep][godep]) to maintain a local copy of this package in your project. + +[govendor]: https://github.com/kardianos/govendor +[godep]: https://github.com/tools/godep/ + > :warning: :warning: `go-linq` has recently introduced _breaking API changes_ > with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with > a refined interface, dramatically increased performance and memory efficiency, @@ -26,16 +31,20 @@ Usage is as easy as chaining methods like: `From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)` -**Example: Find all owners of cars manufactured from 2015** +**Example 1: Find all owners of cars manufactured after 2015** + ```go import . "github.com/ahmetalpbalkan/go-linq" type Car struct { - id, year int + year int owner, model string } -owners := []string{} +... + + +var owners []string From(cars).Where(func(c interface{}) bool { return c.(Car).year >= 2015 @@ -44,7 +53,21 @@ From(cars).Where(func(c interface{}) bool { }).ToSlice(&owners) ``` -**Example: Find the author who has written the most books** +Or, you can use generic functions, like `WhereT` and `SelectT` to simplify your code +(at a performance penalty): + +```go +var owners []string + +From(cars).WhereT(func(c Car) bool { + return c.year >= 2015 +}).SelectT(func(c Car) string { + return c.owner +}).ToSlice(&owners) +``` + +**Example 2: Find the author who has written the most books** + ```go import . "github.com/ahmetalpbalkan/go-linq" @@ -71,7 +94,8 @@ author := From(books).SelectMany( // make a flat array of authors }).First() // take the first author ``` -**Example: Implement a custom method that leaves only values greater than the specified threshold** +**Example 3: Implement a custom method that leaves only values greater than the specified threshold** + ```go type MyQuery Query @@ -96,10 +120,67 @@ func (q MyQuery) GreaterThan(threshold int) Query { result := MyQuery(Range(1,10)).GreaterThan(5).Results() ``` -**More examples** can be found in [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq). +## Generic Functions + +Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without +typing `interface{}`s and type assertions. This will introduce a performance penalty (5x-10x slower) +but will yield in a cleaner and more readable code. + +Methods with `T` suffix (such as `WhereT`) accept functions with generic types. So instead of + + .Select(func(v interface{}) interface{} {...}) + +you can type: + + .SelectT(func(v YourType) YourOtherType {...}) + +This will make your code free of `interface{}` and type assertions. + +**Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions** + +```go +var results []string + +From(sentences). + // split sentences to words + SelectManyT(func(sentence string) Query { + return From(strings.Split(sentence, " ")) + }). + // group the words + GroupByT( + func(word string) string { return word }, + func(word string) string { return word }, + ). + // order by count + OrderByDescendingT(func(wordGroup Group) int { + return len(wordGroup.Group) + }). + // order by the word + ThenByT(func(wordGroup Group) string { + return wordGroup.Key.(string) + }). + Take(5). // take the top 5 + // project the words using the index as rank + SelectIndexedT(func(index int, wordGroup Group) string { + return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group)) + }). + ToSlice(&results) +``` + +**More examples** can be found in the [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq). ## Release Notes + ~~~ +v3.0.0 (2017-01-10) +* Breaking change: ToSlice() now overwrites existing slice starting + from index 0 and grows/reslices it as needed. +* Generic methods support (thanks @cleitonmarx!) + - Accepting parametrized functions was originally proposed in #26 + - You can now avoid type assertions and interface{}s + - Functions with generic methods are named as "MethodNameT" and + signature for the existing LINQ methods are unchanged. +* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy(). v2.0.0 (2016-09-02) * IMPORTANT: This release is a BREAKING CHANGE. The old version diff --git a/vendor/github.com/ahmetb/go-linq/aggregate.go b/vendor/github.com/ahmetb/go-linq/aggregate.go new file mode 100644 index 0000000..bb1975d --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/aggregate.go @@ -0,0 +1,158 @@ +package linq + +// Aggregate applies an accumulator function over a sequence. +// +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source +// except the first one. Each time f() is called, Aggregate passes both the +// element from the sequence and an aggregated value (as the first argument to +// f()). The first element of source is used as the initial aggregate value. The +// result of f() replaces the previous aggregated value. +// +// Aggregate returns the final result of f(). +func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{} { + next := q.Iterate() + + result, any := next() + if !any { + return nil + } + + for current, ok := next(); ok; current, ok = next() { + result = f(result, current) + } + + return result +} + +// AggregateT is the typed version of Aggregate. +// +// - f is of type: func(TSource, TSource) TSource +// +// NOTE: Aggregate has better performance than AggregateT. +func (q Query) AggregateT(f interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateT", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + return q.Aggregate(fFunc) +} + +// AggregateWithSeed applies an accumulator function over a sequence. The +// specified seed value is used as the initial accumulator value. +// +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source +// except the first one. Each time f() is called, Aggregate passes both the +// element from the sequence and an aggregated value (as the first argument to +// f()). The value of the seed parameter is used as the initial aggregate value. +// The result of f() replaces the previous aggregated value. +// +// Aggregate returns the final result of f(). +func (q Query) AggregateWithSeed(seed interface{}, + f func(interface{}, interface{}) interface{}) interface{} { + + next := q.Iterate() + result := seed + + for current, ok := next(); ok; current, ok = next() { + result = f(result, current) + } + + return result +} + +// AggregateWithSeedT is the typed version of AggregateWithSeed. +// +// - f is of type "func(TAccumulate, TSource) TAccumulate" +// +// NOTE: AggregateWithSeed has better performance than +// AggregateWithSeedT. +func (q Query) AggregateWithSeedT(seed interface{}, + f interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateWithSeed", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + return q.AggregateWithSeed(seed, fFunc) +} + +// AggregateWithSeedBy applies an accumulator function over a sequence. The +// specified seed value is used as the initial accumulator value, and the +// specified function is used to select the result value. +// +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source. +// Each time func is called, Aggregate passes both the element from the sequence +// and an aggregated value (as the first argument to func). The value of the +// seed parameter is used as the initial aggregate value. The result of func +// replaces the previous aggregated value. +// +// The final result of func is passed to resultSelector to obtain the final +// result of Aggregate. +func (q Query) AggregateWithSeedBy(seed interface{}, + f func(interface{}, interface{}) interface{}, + resultSelector func(interface{}) interface{}) interface{} { + + next := q.Iterate() + result := seed + + for current, ok := next(); ok; current, ok = next() { + result = f(result, current) + } + + return resultSelector(result) +} + +// AggregateWithSeedByT is the typed version of AggregateWithSeedBy. +// +// - f is of type "func(TAccumulate, TSource) TAccumulate" +// - resultSelectorFn is of type "func(TAccumulate) TResult" +// +// NOTE: AggregateWithSeedBy has better performance than +// AggregateWithSeedByT. +func (q Query) AggregateWithSeedByT(seed interface{}, + f interface{}, + resultSelectorFn interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateWithSeedByT", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "AggregateWithSeedByT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(result interface{}) interface{} { + return resultSelectorGenericFunc.Call(result) + } + + return q.AggregateWithSeedBy(seed, fFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/compare.go b/vendor/github.com/ahmetb/go-linq/compare.go similarity index 90% rename from vendor/github.com/ahmetalpbalkan/go-linq/compare.go rename to vendor/github.com/ahmetb/go-linq/compare.go index c78e4aa..3e0ffbf 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/compare.go +++ b/vendor/github.com/ahmetb/go-linq/compare.go @@ -2,21 +2,21 @@ package linq type comparer func(interface{}, interface{}) int -// Comparable is an interface that has to be implemented by a -// custom collection elememts in order to work with linq. +// Comparable is an interface that has to be implemented by a custom collection +// elememts in order to work with linq. // // Example: -// func (f foo) CompareTo(c Comparable) int { -// a, b := f.f1, c.(foo).f1 +// func (f foo) CompareTo(c Comparable) int { +// a, b := f.f1, c.(foo).f1 // -// if a < b { -// return -1 -// } else if a > b { -// return 1 -// } +// if a < b { +// return -1 +// } else if a > b { +// return 1 +// } // -// return 0 -// } +// return 0 +// } type Comparable interface { CompareTo(Comparable) int } diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/concat.go b/vendor/github.com/ahmetb/go-linq/concat.go similarity index 78% rename from vendor/github.com/ahmetalpbalkan/go-linq/concat.go rename to vendor/github.com/ahmetb/go-linq/concat.go index 6210126..3101c56 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/concat.go +++ b/vendor/github.com/ahmetb/go-linq/concat.go @@ -1,7 +1,7 @@ package linq -// Append inserts an item to the end of a collection, -// so it becomes the last item. +// Append inserts an item to the end of a collection, so it becomes the last +// item. func (q Query) Append(item interface{}) Query { return Query{ Iterate: func() Iterator { @@ -28,8 +28,8 @@ func (q Query) Append(item interface{}) Query { // Concat concatenates two collections. // // The Concat method differs from the Union method because the Concat method -// returns all the original elements in the input sequences. -// The Union method returns only unique elements. +// returns all the original elements in the input sequences. The Union method +// returns only unique elements. func (q Query) Concat(q2 Query) Query { return Query{ Iterate: func() Iterator { @@ -53,8 +53,8 @@ func (q Query) Concat(q2 Query) Query { } } -// Prepend inserts an item to the beginning of a collection, -// so it becomes the first item. +// Prepend inserts an item to the beginning of a collection, so it becomes the +// first item. func (q Query) Prepend(item interface{}) Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/convert.go b/vendor/github.com/ahmetb/go-linq/convert.go similarity index 100% rename from vendor/github.com/ahmetalpbalkan/go-linq/convert.go rename to vendor/github.com/ahmetb/go-linq/convert.go diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/distinct.go b/vendor/github.com/ahmetb/go-linq/distinct.go similarity index 60% rename from vendor/github.com/ahmetalpbalkan/go-linq/distinct.go rename to vendor/github.com/ahmetb/go-linq/distinct.go index 7a32c31..aaef37a 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/distinct.go +++ b/vendor/github.com/ahmetb/go-linq/distinct.go @@ -1,7 +1,7 @@ package linq -// Distinct method returns distinct elements from a collection. -// The result is an unordered collection that contains no duplicate values. +// Distinct method returns distinct elements from a collection. The result is an +// unordered collection that contains no duplicate values. func (q Query) Distinct() Query { return Query{ Iterate: func() Iterator { @@ -22,11 +22,11 @@ func (q Query) Distinct() Query { } } -// Distinct method returns distinct elements from a collection. -// The result is an ordered collection that contains no duplicate values. +// Distinct method returns distinct elements from a collection. The result is an +// ordered collection that contains no duplicate values. // // NOTE: Distinct method on OrderedQuery type has better performance than -// Distinct method on Query type +// Distinct method on Query type. func (oq OrderedQuery) Distinct() OrderedQuery { return OrderedQuery{ orders: oq.orders, @@ -73,3 +73,26 @@ func (q Query) DistinctBy(selector func(interface{}) interface{}) Query { }, } } + +// DistinctByT is the typed version of DistinctBy. +// +// - selectorFn is of type "func(TSource) TSource". +// +// NOTE: DistinctBy has better performance than DistinctByT. +func (q Query) DistinctByT(selectorFn interface{}) Query { + selectorFunc, ok := selectorFn.(func(interface{}) interface{}) + if !ok { + selectorGenericFunc, err := newGenericFunc( + "DistinctByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc = func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + } + return q.DistinctBy(selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/doc.go b/vendor/github.com/ahmetb/go-linq/doc.go new file mode 100644 index 0000000..c89c4fe --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/doc.go @@ -0,0 +1,6 @@ +// Package linq provides methods for querying and manipulating slices, arrays, +// maps, strings, channels and collections. +// +// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan, Cleiton Marques +// Souza. +package linq diff --git a/vendor/github.com/ahmetb/go-linq/except.go b/vendor/github.com/ahmetb/go-linq/except.go new file mode 100644 index 0000000..d146992 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/except.go @@ -0,0 +1,79 @@ +package linq + +// Except produces the set difference of two sequences. The set difference is +// the members of the first sequence that don't appear in the second sequence. +func (q Query) Except(q2 Query) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + + next2 := q2.Iterate() + set := make(map[interface{}]bool) + for i, ok := next2(); ok; i, ok = next2() { + set[i] = true + } + + return func() (item interface{}, ok bool) { + for item, ok = next(); ok; item, ok = next() { + if _, has := set[item]; !has { + return + } + } + + return + } + }, + } +} + +// ExceptBy invokes a transform function on each element of a collection and +// produces the set difference of two sequences. The set difference is the +// members of the first sequence that don't appear in the second sequence. +func (q Query) ExceptBy(q2 Query, + selector func(interface{}) interface{}) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + + next2 := q2.Iterate() + set := make(map[interface{}]bool) + for i, ok := next2(); ok; i, ok = next2() { + s := selector(i) + set[s] = true + } + + return func() (item interface{}, ok bool) { + for item, ok = next(); ok; item, ok = next() { + s := selector(item) + if _, has := set[s]; !has { + return + } + } + + return + } + }, + } +} + +// ExceptByT is the typed version of ExceptBy. +// +// - selectorFn is of type "func(TSource) TSource" +// +// NOTE: ExceptBy has better performance than ExceptByT. +func (q Query) ExceptByT(q2 Query, + selectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "ExceptByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.ExceptBy(q2, selectorFunc) +} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/from.go b/vendor/github.com/ahmetb/go-linq/from.go similarity index 75% rename from vendor/github.com/ahmetalpbalkan/go-linq/from.go rename to vendor/github.com/ahmetb/go-linq/from.go index 56ab451..21ee9f4 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/from.go +++ b/vendor/github.com/ahmetb/go-linq/from.go @@ -5,30 +5,30 @@ import "reflect" // Iterator is an alias for function to iterate over data. type Iterator func() (item interface{}, ok bool) -// Query is the type returned from query functions. -// It can be iterated manually as shown in the example. +// Query is the type returned from query functions. It can be iterated manually +// as shown in the example. type Query struct { Iterate func() Iterator } -// KeyValue is a type that is used to iterate over a map -// (if query is created from a map). This type is also used by -// ToMap() method to output result of a query into a map. +// KeyValue is a type that is used to iterate over a map (if query is created +// from a map). This type is also used by ToMap() method to output result of a +// query into a map. type KeyValue struct { Key interface{} Value interface{} } -// Iterable is an interface that has to be implemented by a -// custom collection in order to work with linq. +// Iterable is an interface that has to be implemented by a custom collection in +// order to work with linq. type Iterable interface { Iterate() Iterator } -// From initializes a linq query with passed slice, array or map -// as the source. String, channel or struct implementing Iterable -// interface can be used as an input. In this case From delegates it -// to FromString, FromChannel and FromIterable internally. +// From initializes a linq query with passed slice, array or map as the source. +// String, channel or struct implementing Iterable interface can be used as an +// input. In this case From delegates it to FromString, FromChannel and +// FromIterable internally. func From(source interface{}) Query { src := reflect.ValueOf(source) @@ -84,8 +84,8 @@ func From(source interface{}) Query { } } -// FromChannel initializes a linq query with passed channel, -// linq iterates over channel until it is closed. +// FromChannel initializes a linq query with passed channel, linq iterates over +// channel until it is closed. func FromChannel(source <-chan interface{}) Query { return Query{ Iterate: func() Iterator { @@ -97,8 +97,8 @@ func FromChannel(source <-chan interface{}) Query { } } -// FromString initializes a linq query with passed string, -// linq iterates over runes of string. +// FromString initializes a linq query with passed string, linq iterates over +// runes of string. func FromString(source string) Query { runes := []rune(source) len := len(runes) @@ -120,8 +120,8 @@ func FromString(source string) Query { } } -// FromIterable initializes a linq query with custom collection passed. -// This collection has to implement Iterable interface, linq iterates over items, +// FromIterable initializes a linq query with custom collection passed. This +// collection has to implement Iterable interface, linq iterates over items, // that has to implement Comparable interface or be basic types. func FromIterable(source Iterable) Query { return Query{ diff --git a/vendor/github.com/ahmetb/go-linq/genericfunc.go b/vendor/github.com/ahmetb/go-linq/genericfunc.go new file mode 100644 index 0000000..77cba2d --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/genericfunc.go @@ -0,0 +1,138 @@ +package linq + +import ( + "fmt" + "reflect" + "strings" +) + +// genericType represents a any reflect.Type. +type genericType int + +var genericTp = reflect.TypeOf(new(genericType)).Elem() + +// functionCache keeps genericFunc reflection objects in cache. +type functionCache struct { + MethodName string + ParamName string + FnValue reflect.Value + FnType reflect.Type + TypesIn []reflect.Type + TypesOut []reflect.Type +} + +// genericFunc is a type used to validate and call dynamic functions. +type genericFunc struct { + Cache *functionCache +} + +// Call calls a dynamic function. +func (g *genericFunc) Call(params ...interface{}) interface{} { + paramsIn := make([]reflect.Value, len(params)) + for i, param := range params { + paramsIn[i] = reflect.ValueOf(param) + } + paramsOut := g.Cache.FnValue.Call(paramsIn) + if len(paramsOut) >= 1 { + return paramsOut[0].Interface() + } + return nil +} + +// newGenericFunc instantiates a new genericFunc pointer +func newGenericFunc(methodName, paramName string, fn interface{}, validateFunc func(*functionCache) error) (*genericFunc, error) { + cache := &functionCache{} + cache.FnValue = reflect.ValueOf(fn) + + if cache.FnValue.Kind() != reflect.Func { + return nil, fmt.Errorf("%s: parameter [%s] is not a function type. It is a '%s'", methodName, paramName, cache.FnValue.Type()) + } + cache.MethodName = methodName + cache.ParamName = paramName + cache.FnType = cache.FnValue.Type() + numTypesIn := cache.FnType.NumIn() + cache.TypesIn = make([]reflect.Type, numTypesIn) + for i := 0; i < numTypesIn; i++ { + cache.TypesIn[i] = cache.FnType.In(i) + } + + numTypesOut := cache.FnType.NumOut() + cache.TypesOut = make([]reflect.Type, numTypesOut) + for i := 0; i < numTypesOut; i++ { + cache.TypesOut[i] = cache.FnType.Out(i) + } + if err := validateFunc(cache); err != nil { + return nil, err + } + + return &genericFunc{Cache: cache}, nil +} + +// simpleParamValidator creates a function to validate genericFunc based in the +// In and Out function parameters. +func simpleParamValidator(In []reflect.Type, Out []reflect.Type) func(cache *functionCache) error { + return func(cache *functionCache) error { + var isValid = func() bool { + if In != nil { + if len(In) != len(cache.TypesIn) { + return false + } + for i, paramIn := range In { + if paramIn != genericTp && paramIn != cache.TypesIn[i] { + return false + } + } + } + if Out != nil { + if len(Out) != len(cache.TypesOut) { + return false + } + for i, paramOut := range Out { + if paramOut != genericTp && paramOut != cache.TypesOut[i] { + return false + } + } + } + return true + } + + if !isValid() { + return fmt.Errorf("%s: parameter [%s] has a invalid function signature. Expected: '%s', actual: '%s'", cache.MethodName, cache.ParamName, formatFnSignature(In, Out), formatFnSignature(cache.TypesIn, cache.TypesOut)) + } + return nil + } +} + +// newElemTypeSlice creates a slice of items elem types. +func newElemTypeSlice(items ...interface{}) []reflect.Type { + typeList := make([]reflect.Type, len(items)) + for i, item := range items { + typeItem := reflect.TypeOf(item) + if typeItem.Kind() == reflect.Ptr { + typeList[i] = typeItem.Elem() + } + } + return typeList +} + +// formatFnSignature formats the func signature based in the parameters types. +func formatFnSignature(In []reflect.Type, Out []reflect.Type) string { + paramInNames := make([]string, len(In)) + for i, typeIn := range In { + if typeIn == genericTp { + paramInNames[i] = "T" + } else { + paramInNames[i] = typeIn.String() + } + + } + paramOutNames := make([]string, len(Out)) + for i, typeOut := range Out { + if typeOut == genericTp { + paramOutNames[i] = "T" + } else { + paramOutNames[i] = typeOut.String() + } + } + return fmt.Sprintf("func(%s)%s", strings.Join(paramInNames, ","), strings.Join(paramOutNames, ",")) +} diff --git a/vendor/github.com/ahmetb/go-linq/groupby.go b/vendor/github.com/ahmetb/go-linq/groupby.go new file mode 100644 index 0000000..face510 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/groupby.go @@ -0,0 +1,81 @@ +package linq + +// Group is a type that is used to store the result of GroupBy method. +type Group struct { + Key interface{} + Group []interface{} +} + +// GroupBy method groups the elements of a collection according to a specified +// key selector function and projects the elements for each group by using a +// specified function. +func (q Query) GroupBy(keySelector func(interface{}) interface{}, + elementSelector func(interface{}) interface{}) Query { + return Query{ + func() Iterator { + next := q.Iterate() + set := make(map[interface{}][]interface{}) + + for item, ok := next(); ok; item, ok = next() { + key := keySelector(item) + set[key] = append(set[key], elementSelector(item)) + } + + len := len(set) + idx := 0 + groups := make([]Group, len) + for k, v := range set { + groups[idx] = Group{k, v} + idx++ + } + + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = groups[index] + index++ + } + + return + } + }, + } +} + +// GroupByT is the typed version of GroupBy. +// +// - keySelectorFn is of type "func(TSource) TKey" +// - elementSelectorFn is of type "func(TSource) TElement" +// +// NOTE: GroupBy has better performance than GroupByT. +func (q Query) GroupByT(keySelectorFn interface{}, + elementSelectorFn interface{}) Query { + keySelectorGenericFunc, err := newGenericFunc( + "GroupByT", "keySelectorFn", keySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + keySelectorFunc := func(item interface{}) interface{} { + return keySelectorGenericFunc.Call(item) + } + + elementSelectorGenericFunc, err := newGenericFunc( + "GroupByT", "elementSelectorFn", elementSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + elementSelectorFunc := func(item interface{}) interface{} { + return elementSelectorGenericFunc.Call(item) + + } + + return q.GroupBy(keySelectorFunc, elementSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/groupjoin.go b/vendor/github.com/ahmetb/go-linq/groupjoin.go new file mode 100644 index 0000000..f9f8144 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/groupjoin.go @@ -0,0 +1,107 @@ +package linq + +import "reflect" + +// GroupJoin correlates the elements of two collections based on key equality, +// and groups the results. +// +// This method produces hierarchical results, which means that elements from +// outer query are paired with collections of matching elements from inner. +// GroupJoin enables you to base your results on a whole set of matches for each +// element of outer query. +// +// The resultSelector function is called only one time for each outer element +// together with a collection of all the inner elements that match the outer +// element. This differs from the Join method, in which the result selector +// function is invoked on pairs that contain one element from outer and one +// element from inner. +// +// GroupJoin preserves the order of the elements of outer, and for each element +// of outer, the order of the matching elements from inner. +func (q Query) GroupJoin(inner Query, + outerKeySelector func(interface{}) interface{}, + innerKeySelector func(interface{}) interface{}, + resultSelector func(outer interface{}, inners []interface{}) interface{}) Query { + + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + innernext := inner.Iterate() + + innerLookup := make(map[interface{}][]interface{}) + for innerItem, ok := innernext(); ok; innerItem, ok = innernext() { + innerKey := innerKeySelector(innerItem) + innerLookup[innerKey] = append(innerLookup[innerKey], innerItem) + } + + return func() (item interface{}, ok bool) { + if item, ok = outernext(); !ok { + return + } + + if group, has := innerLookup[outerKeySelector(item)]; !has { + item = resultSelector(item, []interface{}{}) + } else { + item = resultSelector(item, group) + } + + return + } + }, + } +} + +// GroupJoinT is the typed version of GroupJoin. +// +// - inner: The query to join to the outer query. +// - outerKeySelectorFn is of type "func(TOuter) TKey" +// - innerKeySelectorFn is of type "func(TInner) TKey" +// - resultSelectorFn: is of type "func(TOuter, inners []TInner) TResult" +// +// NOTE: GroupJoin has better performance than GroupJoinT. +func (q Query) GroupJoinT(inner Query, + outerKeySelectorFn interface{}, + innerKeySelectorFn interface{}, + resultSelectorFn interface{}) Query { + outerKeySelectorGenericFunc, err := newGenericFunc( + "GroupJoinT", "outerKeySelectorFn", outerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + outerKeySelectorFunc := func(item interface{}) interface{} { + return outerKeySelectorGenericFunc.Call(item) + } + + innerKeySelectorFuncGenericFunc, err := newGenericFunc( + "GroupJoinT", "innerKeySelectorFn", innerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + innerKeySelectorFunc := func(item interface{}) interface{} { + return innerKeySelectorFuncGenericFunc.Call(item) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "GroupJoinT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, inners []interface{}) interface{} { + innerSliceType := reflect.MakeSlice(resultSelectorGenericFunc.Cache.TypesIn[1], 0, 0) + innersSlicePointer := reflect.New(innerSliceType.Type()) + From(inners).ToSlice(innersSlicePointer.Interface()) + innersTyped := reflect.Indirect(innersSlicePointer).Interface() + return resultSelectorGenericFunc.Call(outer, innersTyped) + } + + return q.GroupJoin(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/intersect.go b/vendor/github.com/ahmetb/go-linq/intersect.go similarity index 65% rename from vendor/github.com/ahmetalpbalkan/go-linq/intersect.go rename to vendor/github.com/ahmetb/go-linq/intersect.go index 6499bb8..511ed3b 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/intersect.go +++ b/vendor/github.com/ahmetb/go-linq/intersect.go @@ -2,8 +2,8 @@ package linq // Intersect produces the set intersection of the source collection and the // provided input collection. The intersection of two sets A and B is defined as -// the set that contains all the elements of A that also appear in B, -// but no other elements. +// the set that contains all the elements of A that also appear in B, but no +// other elements. func (q Query) Intersect(q2 Query) Query { return Query{ Iterate: func() Iterator { @@ -31,14 +31,12 @@ func (q Query) Intersect(q2 Query) Query { // IntersectBy produces the set intersection of the source collection and the // provided input collection. The intersection of two sets A and B is defined as -// the set that contains all the elements of A that also appear in B, -// but no other elements. +// the set that contains all the elements of A that also appear in B, but no +// other elements. // // IntersectBy invokes a transform function on each element of both collections. -func (q Query) IntersectBy( - q2 Query, - selector func(interface{}) interface{}, -) Query { +func (q Query) IntersectBy(q2 Query, + selector func(interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -65,3 +63,25 @@ func (q Query) IntersectBy( }, } } + +// IntersectByT is the typed version of IntersectBy. +// +// - selectorFn is of type "func(TSource) TSource" +// +// NOTE: IntersectBy has better performance than IntersectByT. +func (q Query) IntersectByT(q2 Query, + selectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "IntersectByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.IntersectBy(q2, selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/join.go b/vendor/github.com/ahmetb/go-linq/join.go new file mode 100644 index 0000000..68211a2 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/join.go @@ -0,0 +1,105 @@ +package linq + +// Join correlates the elements of two collection based on matching keys. +// +// A join refers to the operation of correlating the elements of two sources of +// information based on a common key. Join brings the two information sources +// and the keys by which they are matched together in one method call. This +// differs from the use of SelectMany, which requires more than one method call +// to perform the same operation. +// +// Join preserves the order of the elements of outer collection, and for each of +// these elements, the order of the matching elements of inner. +func (q Query) Join(inner Query, + outerKeySelector func(interface{}) interface{}, + innerKeySelector func(interface{}) interface{}, + resultSelector func(outer interface{}, inner interface{}) interface{}) Query { + + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + innernext := inner.Iterate() + + innerLookup := make(map[interface{}][]interface{}) + for innerItem, ok := innernext(); ok; innerItem, ok = innernext() { + innerKey := innerKeySelector(innerItem) + innerLookup[innerKey] = append(innerLookup[innerKey], innerItem) + } + + var outerItem interface{} + var innerGroup []interface{} + innerLen, innerIndex := 0, 0 + + return func() (item interface{}, ok bool) { + if innerIndex >= innerLen { + has := false + for !has { + outerItem, ok = outernext() + if !ok { + return + } + + innerGroup, has = innerLookup[outerKeySelector(outerItem)] + innerLen = len(innerGroup) + innerIndex = 0 + } + } + + item = resultSelector(outerItem, innerGroup[innerIndex]) + innerIndex++ + return item, true + } + }, + } +} + +// JoinT is the typed version of Join. +// +// - outerKeySelectorFn is of type "func(TOuter) TKey" +// - innerKeySelectorFn is of type "func(TInner) TKey" +// - resultSelectorFn is of type "func(TOuter,TInner) TResult" +// +// NOTE: Join has better performance than JoinT. +func (q Query) JoinT(inner Query, + outerKeySelectorFn interface{}, + innerKeySelectorFn interface{}, + resultSelectorFn interface{}) Query { + outerKeySelectorGenericFunc, err := newGenericFunc( + "JoinT", "outerKeySelectorFn", outerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + outerKeySelectorFunc := func(item interface{}) interface{} { + return outerKeySelectorGenericFunc.Call(item) + } + + innerKeySelectorFuncGenericFunc, err := newGenericFunc( + "JoinT", "innerKeySelectorFn", + innerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + innerKeySelectorFunc := func(item interface{}) interface{} { + return innerKeySelectorFuncGenericFunc.Call(item) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "JoinT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, inner interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, inner) + } + + return q.Join(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/orderby.go b/vendor/github.com/ahmetb/go-linq/orderby.go new file mode 100644 index 0000000..110559d --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/orderby.go @@ -0,0 +1,313 @@ +package linq + +import "sort" + +type order struct { + selector func(interface{}) interface{} + compare comparer + desc bool +} + +// OrderedQuery is the type returned from OrderBy, OrderByDescending ThenBy and +// ThenByDescending functions. +type OrderedQuery struct { + Query + original Query + orders []order +} + +// OrderBy sorts the elements of a collection in ascending order. Elements are +// sorted according to a key. +func (q Query) OrderBy(selector func(interface{}) interface{}) OrderedQuery { + return OrderedQuery{ + orders: []order{{selector: selector}}, + original: q, + Query: Query{ + Iterate: func() Iterator { + items := q.sort([]order{{selector: selector}}) + len := len(items) + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = items[index] + index++ + } + + return + } + }, + }, + } +} + +// OrderByT is the typed version of OrderBy. +// +// - selectorFn is of type "func(TSource) TKey" +// +// NOTE: OrderBy has better performance than OrderByT. +func (q Query) OrderByT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "OrderByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.OrderBy(selectorFunc) +} + +// OrderByDescending sorts the elements of a collection in descending order. +// Elements are sorted according to a key. +func (q Query) OrderByDescending(selector func(interface{}) interface{}) OrderedQuery { + return OrderedQuery{ + orders: []order{{selector: selector, desc: true}}, + original: q, + Query: Query{ + Iterate: func() Iterator { + items := q.sort([]order{{selector: selector, desc: true}}) + len := len(items) + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = items[index] + index++ + } + + return + } + }, + }, + } +} + +// OrderByDescendingT is the typed version of OrderByDescending. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: OrderByDescending has better performance than OrderByDescendingT. +func (q Query) OrderByDescendingT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "OrderByDescendingT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.OrderByDescending(selectorFunc) +} + +// ThenBy performs a subsequent ordering of the elements in a collection in +// ascending order. This method enables you to specify multiple sort criteria by +// applying any number of ThenBy or ThenByDescending methods. +func (oq OrderedQuery) ThenBy( + selector func(interface{}) interface{}) OrderedQuery { + return OrderedQuery{ + orders: append(oq.orders, order{selector: selector}), + original: oq.original, + Query: Query{ + Iterate: func() Iterator { + items := oq.original.sort(append(oq.orders, order{selector: selector})) + len := len(items) + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = items[index] + index++ + } + + return + } + }, + }, + } +} + +// ThenByT is the typed version of ThenBy. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: ThenBy has better performance than ThenByT. +func (oq OrderedQuery) ThenByT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "ThenByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return oq.ThenBy(selectorFunc) +} + +// ThenByDescending performs a subsequent ordering of the elements in a +// collection in descending order. This method enables you to specify multiple +// sort criteria by applying any number of ThenBy or ThenByDescending methods. +func (oq OrderedQuery) ThenByDescending(selector func(interface{}) interface{}) OrderedQuery { + return OrderedQuery{ + orders: append(oq.orders, order{selector: selector, desc: true}), + original: oq.original, + Query: Query{ + Iterate: func() Iterator { + items := oq.original.sort(append(oq.orders, order{selector: selector, desc: true})) + len := len(items) + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = items[index] + index++ + } + + return + } + }, + }, + } +} + +// ThenByDescendingT is the typed version of ThenByDescending. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: ThenByDescending has better performance than ThenByDescendingT. +func (oq OrderedQuery) ThenByDescendingT(selectorFn interface{}) OrderedQuery { + selectorFunc, ok := selectorFn.(func(interface{}) interface{}) + if !ok { + selectorGenericFunc, err := newGenericFunc( + "ThenByDescending", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc = func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + } + return oq.ThenByDescending(selectorFunc) +} + +// Sort returns a new query by sorting elements with provided less function in +// ascending order. The comparer function should return true if the parameter i +// is less than j. While this method is uglier than chaining OrderBy, +// OrderByDescending, ThenBy and ThenByDescending methods, it's performance is +// much better. +func (q Query) Sort(less func(i, j interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + items := q.lessSort(less) + len := len(items) + index := 0 + + return func() (item interface{}, ok bool) { + ok = index < len + if ok { + item = items[index] + index++ + } + + return + } + }, + } +} + +// SortT is the typed version of Sort. +// - lessFn is of type "func(TSource,TSource) bool" +// NOTE: Sort has better performance than SortT. +func (q Query) SortT(lessFn interface{}) Query { + lessGenericFunc, err := newGenericFunc( + "SortT", "lessFn", lessFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + lessFunc := func(i, j interface{}) bool { + return lessGenericFunc.Call(i, j).(bool) + } + + return q.Sort(lessFunc) +} + +type sorter struct { + items []interface{} + less func(i, j interface{}) bool +} + +func (s sorter) Len() int { + return len(s.items) +} + +func (s sorter) Swap(i, j int) { + s.items[i], s.items[j] = s.items[j], s.items[i] +} + +func (s sorter) Less(i, j int) bool { + return s.less(s.items[i], s.items[j]) +} + +func (q Query) sort(orders []order) (r []interface{}) { + next := q.Iterate() + for item, ok := next(); ok; item, ok = next() { + r = append(r, item) + } + + if len(r) == 0 { + return + } + + for i, j := range orders { + orders[i].compare = getComparer(j.selector(r[0])) + } + + s := sorter{ + items: r, + less: func(i, j interface{}) bool { + for _, order := range orders { + x, y := order.selector(i), order.selector(j) + switch order.compare(x, y) { + case 0: + continue + case -1: + return !order.desc + default: + return order.desc + } + } + + return false + }} + + sort.Sort(s) + return +} + +func (q Query) lessSort(less func(i, j interface{}) bool) (r []interface{}) { + next := q.Iterate() + for item, ok := next(); ok; item, ok = next() { + r = append(r, item) + } + + s := sorter{items: r, less: less} + + sort.Sort(s) + return +} diff --git a/vendor/github.com/ahmetb/go-linq/result.go b/vendor/github.com/ahmetb/go-linq/result.go new file mode 100644 index 0000000..34e47ab --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/result.go @@ -0,0 +1,658 @@ +package linq + +import ( + "math" + "reflect" +) + +// All determines whether all elements of a collection satisfy a condition. +func (q Query) All(predicate func(interface{}) bool) bool { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if !predicate(item) { + return false + } + } + + return true +} + +// AllT is the typed version of All. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: All has better performance than AllT. +func (q Query) AllT(predicateFn interface{}) bool { + + predicateGenericFunc, err := newGenericFunc( + "AllT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.All(predicateFunc) +} + +// Any determines whether any element of a collection exists. +func (q Query) Any() bool { + _, ok := q.Iterate()() + return ok +} + +// AnyWith determines whether any element of a collection satisfies a condition. +func (q Query) AnyWith(predicate func(interface{}) bool) bool { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if predicate(item) { + return true + } + } + + return false +} + +// AnyWithT is the typed version of AnyWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: AnyWith has better performance than AnyWithT. +func (q Query) AnyWithT(predicateFn interface{}) bool { + + predicateGenericFunc, err := newGenericFunc( + "AnyWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.AnyWith(predicateFunc) +} + +// Average computes the average of a collection of numeric values. +func (q Query) Average() (r float64) { + next := q.Iterate() + item, ok := next() + if !ok { + return math.NaN() + } + + n := 1 + switch item.(type) { + case int, int8, int16, int32, int64: + conv := getIntConverter(item) + sum := conv(item) + + for item, ok = next(); ok; item, ok = next() { + sum += conv(item) + n++ + } + + r = float64(sum) + case uint, uint8, uint16, uint32, uint64: + conv := getUIntConverter(item) + sum := conv(item) + + for item, ok = next(); ok; item, ok = next() { + sum += conv(item) + n++ + } + + r = float64(sum) + default: + conv := getFloatConverter(item) + r = conv(item) + + for item, ok = next(); ok; item, ok = next() { + r += conv(item) + n++ + } + } + + return r / float64(n) +} + +// Contains determines whether a collection contains a specified element. +func (q Query) Contains(value interface{}) bool { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if item == value { + return true + } + } + + return false +} + +// Count returns the number of elements in a collection. +func (q Query) Count() (r int) { + next := q.Iterate() + + for _, ok := next(); ok; _, ok = next() { + r++ + } + + return +} + +// CountWith returns a number that represents how many elements in the specified +// collection satisfy a condition. +func (q Query) CountWith(predicate func(interface{}) bool) (r int) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if predicate(item) { + r++ + } + } + + return +} + +// CountWithT is the typed version of CountWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: CountWith has better performance than CountWithT. +func (q Query) CountWithT(predicateFn interface{}) int { + + predicateGenericFunc, err := newGenericFunc( + "CountWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.CountWith(predicateFunc) +} + +// First returns the first element of a collection. +func (q Query) First() interface{} { + item, _ := q.Iterate()() + return item +} + +// FirstWith returns the first element of a collection that satisfies a +// specified condition. +func (q Query) FirstWith(predicate func(interface{}) bool) interface{} { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if predicate(item) { + return item + } + } + + return nil +} + +// FirstWithT is the typed version of FirstWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: FirstWith has better performance than FirstWithT. +func (q Query) FirstWithT(predicateFn interface{}) interface{} { + + predicateGenericFunc, err := newGenericFunc( + "FirstWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.FirstWith(predicateFunc) +} + +// ForEach performs the specified action on each element of a collection. +func (q Query) ForEach(action func(interface{})) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + action(item) + } +} + +// ForEachT is the typed version of ForEach. +// +// - actionFn is of type "func(TSource)" +// +// NOTE: ForEach has better performance than ForEachT. +func (q Query) ForEachT(actionFn interface{}) { + actionGenericFunc, err := newGenericFunc( + "ForEachT", "actionFn", actionFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), nil), + ) + + if err != nil { + panic(err) + } + + actionFunc := func(item interface{}) { + actionGenericFunc.Call(item) + } + + q.ForEach(actionFunc) +} + +// ForEachIndexed performs the specified action on each element of a collection. +// +// The first argument to action represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to action represents the +// element to process. +func (q Query) ForEachIndexed(action func(int, interface{})) { + next := q.Iterate() + index := 0 + + for item, ok := next(); ok; item, ok = next() { + action(index, item) + index++ + } +} + +// ForEachIndexedT is the typed version of ForEachIndexed. +// +// - actionFn is of type "func(int, TSource)" +// +// NOTE: ForEachIndexed has better performance than ForEachIndexedT. +func (q Query) ForEachIndexedT(actionFn interface{}) { + actionGenericFunc, err := newGenericFunc( + "ForEachIndexedT", "actionFn", actionFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil), + ) + + if err != nil { + panic(err) + } + + actionFunc := func(index int, item interface{}) { + actionGenericFunc.Call(index, item) + } + + q.ForEachIndexed(actionFunc) +} + +// Last returns the last element of a collection. +func (q Query) Last() (r interface{}) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + r = item + } + + return +} + +// LastWith returns the last element of a collection that satisfies a specified +// condition. +func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + if predicate(item) { + r = item + } + } + + return +} + +// LastWithT is the typed version of LastWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: LastWith has better performance than LastWithT. +func (q Query) LastWithT(predicateFn interface{}) interface{} { + + predicateGenericFunc, err := newGenericFunc( + "LastWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.LastWith(predicateFunc) +} + +// Max returns the maximum value in a collection of values. +func (q Query) Max() (r interface{}) { + next := q.Iterate() + item, ok := next() + if !ok { + return nil + } + + compare := getComparer(item) + r = item + + for item, ok := next(); ok; item, ok = next() { + if compare(item, r) > 0 { + r = item + } + } + + return +} + +// Min returns the minimum value in a collection of values. +func (q Query) Min() (r interface{}) { + next := q.Iterate() + item, ok := next() + if !ok { + return nil + } + + compare := getComparer(item) + r = item + + for item, ok := next(); ok; item, ok = next() { + if compare(item, r) < 0 { + r = item + } + } + + return +} + +// Results iterates over a collection and returnes slice of interfaces +func (q Query) Results() (r []interface{}) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + r = append(r, item) + } + + return +} + +// SequenceEqual determines whether two collections are equal. +func (q Query) SequenceEqual(q2 Query) bool { + next := q.Iterate() + next2 := q2.Iterate() + + for item, ok := next(); ok; item, ok = next() { + item2, ok2 := next2() + if !ok2 || item != item2 { + return false + } + } + + _, ok2 := next2() + return !ok2 +} + +// Single returns the only element of a collection, and nil if there is not +// exactly one element in the collection. +func (q Query) Single() interface{} { + next := q.Iterate() + item, ok := next() + if !ok { + return nil + } + + _, ok = next() + if ok { + return nil + } + + return item +} + +// SingleWith returns the only element of a collection that satisfies a +// specified condition, and nil if more than one such element exists. +func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) { + next := q.Iterate() + found := false + + for item, ok := next(); ok; item, ok = next() { + if predicate(item) { + if found { + return nil + } + + found = true + r = item + } + } + + return +} + +// SingleWithT is the typed version of SingleWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: SingleWith has better performance than SingleWithT. +func (q Query) SingleWithT(predicateFn interface{}) interface{} { + predicateGenericFunc, err := newGenericFunc( + "SingleWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.SingleWith(predicateFunc) +} + +// SumInts computes the sum of a collection of numeric values. +// +// Values can be of any integer type: int, int8, int16, int32, int64. The result +// is int64. Method returns zero if collection contains no elements. +func (q Query) SumInts() (r int64) { + next := q.Iterate() + item, ok := next() + if !ok { + return 0 + } + + conv := getIntConverter(item) + r = conv(item) + + for item, ok = next(); ok; item, ok = next() { + r += conv(item) + } + + return +} + +// SumUInts computes the sum of a collection of numeric values. +// +// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, +// uint64. The result is uint64. Method returns zero if collection contains no +// elements. +func (q Query) SumUInts() (r uint64) { + next := q.Iterate() + item, ok := next() + if !ok { + return 0 + } + + conv := getUIntConverter(item) + r = conv(item) + + for item, ok = next(); ok; item, ok = next() { + r += conv(item) + } + + return +} + +// SumFloats computes the sum of a collection of numeric values. +// +// Values can be of any float type: float32 or float64. The result is float64. +// Method returns zero if collection contains no elements. +func (q Query) SumFloats() (r float64) { + next := q.Iterate() + item, ok := next() + if !ok { + return 0 + } + + conv := getFloatConverter(item) + r = conv(item) + + for item, ok = next(); ok; item, ok = next() { + r += conv(item) + } + + return +} + +// ToChannel iterates over a collection and outputs each element to a channel, +// then closes it. +func (q Query) ToChannel(result chan<- interface{}) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + result <- item + } + + close(result) +} + +// ToMap iterates over a collection and populates result map with elements. +// Collection elements have to be of KeyValue type to use this method. To +// populate a map with elements of different type use ToMapBy method. ToMap +// doesn't empty the result map before populating it. +func (q Query) ToMap(result interface{}) { + q.ToMapBy( + result, + func(i interface{}) interface{} { + return i.(KeyValue).Key + }, + func(i interface{}) interface{} { + return i.(KeyValue).Value + }) +} + +// ToMapBy iterates over a collection and populates the result map with +// elements. Functions keySelector and valueSelector are executed for each +// element of the collection to generate key and value for the map. Generated +// key and value types must be assignable to the map's key and value types. +// ToMapBy doesn't empty the result map before populating it. +func (q Query) ToMapBy(result interface{}, + keySelector func(interface{}) interface{}, + valueSelector func(interface{}) interface{}) { + res := reflect.ValueOf(result) + m := reflect.Indirect(res) + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + key := reflect.ValueOf(keySelector(item)) + value := reflect.ValueOf(valueSelector(item)) + + m.SetMapIndex(key, value) + } + + res.Elem().Set(m) +} + +// ToMapByT is the typed version of ToMapBy. +// +// - keySelectorFn is of type "func(TSource)TKey" +// - valueSelectorFn is of type "func(TSource)TValue" +// +// NOTE: ToMapBy has better performance than ToMapByT. +func (q Query) ToMapByT(result interface{}, + keySelectorFn interface{}, valueSelectorFn interface{}) { + keySelectorGenericFunc, err := newGenericFunc( + "ToMapByT", "keySelectorFn", keySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + keySelectorFunc := func(item interface{}) interface{} { + return keySelectorGenericFunc.Call(item) + } + + valueSelectorGenericFunc, err := newGenericFunc( + "ToMapByT", "valueSelectorFn", valueSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + valueSelectorFunc := func(item interface{}) interface{} { + return valueSelectorGenericFunc.Call(item) + } + + q.ToMapBy(result, keySelectorFunc, valueSelectorFunc) +} + +// ToSlice iterates over a collection and saves the results in the slice pointed +// by v. It overwrites the existing slice, starting from index 0. +// +// If the slice pointed by v has sufficient capacity, v will be pointed to a +// resliced slice. If it does not, a new underlying array will be allocated and +// v will point to it. +func (q Query) ToSlice(v interface{}) { + res := reflect.ValueOf(v) + slice := reflect.Indirect(res) + + cap := slice.Cap() + res.Elem().Set(slice.Slice(0, cap)) // make len(slice)==cap(slice) from now on + + next := q.Iterate() + index := 0 + for item, ok := next(); ok; item, ok = next() { + if index >= cap { + slice, cap = grow(slice) + } + slice.Index(index).Set(reflect.ValueOf(item)) + index++ + } + + // reslice the len(res)==cap(res) actual res size + res.Elem().Set(slice.Slice(0, index)) +} + +// grow grows the slice s by doubling its capacity, then it returns the new +// slice (resliced to its full capacity) and the new capacity. +func grow(s reflect.Value) (v reflect.Value, newCap int) { + cap := s.Cap() + if cap == 0 { + cap = 1 + } else { + cap *= 2 + } + newSlice := reflect.MakeSlice(s.Type(), cap, cap) + reflect.Copy(newSlice, s) + return newSlice, cap +} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/reverse.go b/vendor/github.com/ahmetb/go-linq/reverse.go similarity index 76% rename from vendor/github.com/ahmetalpbalkan/go-linq/reverse.go rename to vendor/github.com/ahmetb/go-linq/reverse.go index eaacb9f..8716c22 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/reverse.go +++ b/vendor/github.com/ahmetb/go-linq/reverse.go @@ -2,9 +2,9 @@ package linq // Reverse inverts the order of the elements in a collection. // -// Unlike OrderBy, this sorting method does not consider the actual values themselves -// in determining the order. Rather, it just returns the elements in the reverse order -// from which they are produced by the underlying source. +// Unlike OrderBy, this sorting method does not consider the actual values +// themselves in determining the order. Rather, it just returns the elements in +// the reverse order from which they are produced by the underlying source. func (q Query) Reverse() Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetb/go-linq/select.go b/vendor/github.com/ahmetb/go-linq/select.go new file mode 100644 index 0000000..5dc8cc7 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/select.go @@ -0,0 +1,109 @@ +package linq + +// Select projects each element of a collection into a new form. Returns a query +// with the result of invoking the transform function on each element of +// original source. +// +// This projection method requires the transform function, selector, to produce +// one value for each value in the source collection. If selector returns a +// value that is itself a collection, it is up to the consumer to traverse the +// subcollections manually. In such a situation, it might be better for your +// query to return a single coalesced collection of values. To achieve this, use +// the SelectMany method instead of Select. Although SelectMany works similarly +// to Select, it differs in that the transform function returns a collection +// that is then expanded by SelectMany before it is returned. +func (q Query) Select(selector func(interface{}) interface{}) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + + return func() (item interface{}, ok bool) { + var it interface{} + it, ok = next() + if ok { + item = selector(it) + } + + return + } + }, + } +} + +// SelectT is the typed version of Select. +// - selectorFn is of type "func(TSource)TResult" +// NOTE: Select has better performance than SelectT. +func (q Query) SelectT(selectorFn interface{}) Query { + + selectGenericFunc, err := newGenericFunc( + "SelectT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectGenericFunc.Call(item) + } + + return q.Select(selectorFunc) +} + +// SelectIndexed projects each element of a collection into a new form by +// incorporating the element's index. Returns a query with the result of +// invoking the transform function on each element of original source. +// +// The first argument to selector represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to selector represents the +// element to process. +// +// This projection method requires the transform function, selector, to produce +// one value for each value in the source collection. If selector returns a +// value that is itself a collection, it is up to the consumer to traverse the +// subcollections manually. In such a situation, it might be better for your +// query to return a single coalesced collection of values. To achieve this, use +// the SelectMany method instead of Select. Although SelectMany works similarly +// to Select, it differs in that the transform function returns a collection +// that is then expanded by SelectMany before it is returned. +func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + index := 0 + + return func() (item interface{}, ok bool) { + var it interface{} + it, ok = next() + if ok { + item = selector(index, it) + index++ + } + + return + } + }, + } +} + +// SelectIndexedT is the typed version of SelectIndexed. +// - selectorFn is of type "func(int,TSource)TResult" +// NOTE: SelectIndexed has better performance than SelectIndexedT. +func (q Query) SelectIndexedT(selectorFn interface{}) Query { + selectGenericFunc, err := newGenericFunc( + "SelectIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, item interface{}) interface{} { + return selectGenericFunc.Call(index, item) + } + + return q.SelectIndexed(selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/selectmany.go b/vendor/github.com/ahmetb/go-linq/selectmany.go new file mode 100644 index 0000000..74fa671 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/selectmany.go @@ -0,0 +1,265 @@ +package linq + +// SelectMany projects each element of a collection to a Query, iterates and +// flattens the resulting collection into one collection. +func (q Query) SelectMany(selector func(interface{}) Query) Query { + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + var inner interface{} + var innernext Iterator + + return func() (item interface{}, ok bool) { + for !ok { + if inner == nil { + inner, ok = outernext() + if !ok { + return + } + + innernext = selector(inner).Iterate() + } + + item, ok = innernext() + if !ok { + inner = nil + } + } + + return + } + }, + } +} + +// SelectManyT is the typed version of SelectMany. +// +// - selectorFn is of type "func(TSource)Query" +// +// NOTE: SelectMany has better performance than SelectManyT. +func (q Query) SelectManyT(selectorFn interface{}) Query { + + selectManyGenericFunc, err := newGenericFunc( + "SelectManyT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(inner interface{}) Query { + return selectManyGenericFunc.Call(inner).(Query) + } + return q.SelectMany(selectorFunc) + +} + +// SelectManyIndexed projects each element of a collection to a Query, iterates +// and flattens the resulting collection into one collection. +// +// The first argument to selector represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to selector represents the +// element to process. +func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query { + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + index := 0 + var inner interface{} + var innernext Iterator + + return func() (item interface{}, ok bool) { + for !ok { + if inner == nil { + inner, ok = outernext() + if !ok { + return + } + + innernext = selector(index, inner).Iterate() + index++ + } + + item, ok = innernext() + if !ok { + inner = nil + } + } + + return + } + }, + } +} + +// SelectManyIndexedT is the typed version of SelectManyIndexed. +// +// - selectorFn is of type "func(int,TSource)Query" +// +// NOTE: SelectManyIndexed has better performance than SelectManyIndexedT. +func (q Query) SelectManyIndexedT(selectorFn interface{}) Query { + + selectManyIndexedGenericFunc, err := newGenericFunc( + "SelectManyIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, inner interface{}) Query { + return selectManyIndexedGenericFunc.Call(index, inner).(Query) + } + + return q.SelectManyIndexed(selectorFunc) +} + +// SelectManyBy projects each element of a collection to a Query, iterates and +// flattens the resulting collection into one collection, and invokes a result +// selector function on each element therein. +func (q Query) SelectManyBy(selector func(interface{}) Query, + resultSelector func(interface{}, interface{}) interface{}) Query { + + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + var outer interface{} + var innernext Iterator + + return func() (item interface{}, ok bool) { + for !ok { + if outer == nil { + outer, ok = outernext() + if !ok { + return + } + + innernext = selector(outer).Iterate() + } + + item, ok = innernext() + if !ok { + outer = nil + } + } + + item = resultSelector(item, outer) + return + } + }, + } +} + +// SelectManyByT is the typed version of SelectManyBy. +// +// - selectorFn is of type "func(TSource)Query" +// - resultSelectorFn is of type "func(TSource,TCollection)TResult" +// +// NOTE: SelectManyBy has better performance than SelectManyByT. +func (q Query) SelectManyByT(selectorFn interface{}, + resultSelectorFn interface{}) Query { + + selectorGenericFunc, err := newGenericFunc( + "SelectManyByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(outer interface{}) Query { + return selectorGenericFunc.Call(outer).(Query) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "SelectManyByT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, item interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, item) + } + + return q.SelectManyBy(selectorFunc, resultSelectorFunc) +} + +// SelectManyByIndexed projects each element of a collection to a Query, +// iterates and flattens the resulting collection into one collection, and +// invokes a result selector function on each element therein. The index of each +// source element is used in the intermediate projected form of that element. +func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query, + resultSelector func(interface{}, interface{}) interface{}) Query { + + return Query{ + Iterate: func() Iterator { + outernext := q.Iterate() + index := 0 + var outer interface{} + var innernext Iterator + + return func() (item interface{}, ok bool) { + for !ok { + if outer == nil { + outer, ok = outernext() + if !ok { + return + } + + innernext = selector(index, outer).Iterate() + index++ + } + + item, ok = innernext() + if !ok { + outer = nil + } + } + + item = resultSelector(item, outer) + return + } + }, + } +} + +// SelectManyByIndexedT is the typed version of SelectManyByIndexed. +// +// - selectorFn is of type "func(int,TSource)Query" +// - resultSelectorFn is of type "func(TSource,TCollection)TResult" +// +// NOTE: SelectManyByIndexed has better performance than +// SelectManyByIndexedT. +func (q Query) SelectManyByIndexedT(selectorFn interface{}, + resultSelectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "SelectManyByIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, outer interface{}) Query { + return selectorGenericFunc.Call(index, outer).(Query) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "SelectManyByIndexedT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, item interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, item) + } + + return q.SelectManyByIndexed(selectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/skip.go b/vendor/github.com/ahmetb/go-linq/skip.go new file mode 100644 index 0000000..0fb05d3 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/skip.go @@ -0,0 +1,134 @@ +package linq + +// Skip bypasses a specified number of elements in a collection and then returns +// the remaining elements. +func (q Query) Skip(count int) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + n := count + + return func() (item interface{}, ok bool) { + for ; n > 0; n-- { + item, ok = next() + if !ok { + return + } + } + + return next() + } + }, + } +} + +// SkipWhile bypasses elements in a collection as long as a specified condition +// is true and then returns the remaining elements. +// +// This method tests each element by using predicate and skips the element if +// the result is true. After the predicate function returns false for an +// element, that element and the remaining elements in source are returned and +// there are no more invocations of predicate. +func (q Query) SkipWhile(predicate func(interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + ready := false + + return func() (item interface{}, ok bool) { + for !ready { + item, ok = next() + if !ok { + return + } + + ready = !predicate(item) + if ready { + return + } + } + + return next() + } + }, + } +} + +// SkipWhileT is the typed version of SkipWhile. +// +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: SkipWhile has better performance than SkipWhileT. +func (q Query) SkipWhileT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "SkipWhileT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.SkipWhile(predicateFunc) +} + +// SkipWhileIndexed bypasses elements in a collection as long as a specified +// condition is true and then returns the remaining elements. The element's +// index is used in the logic of the predicate function. +// +// This method tests each element by using predicate and skips the element if +// the result is true. After the predicate function returns false for an +// element, that element and the remaining elements in source are returned and +// there are no more invocations of predicate. +func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + ready := false + index := 0 + + return func() (item interface{}, ok bool) { + for !ready { + item, ok = next() + if !ok { + return + } + + ready = !predicate(index, item) + if ready { + return + } + + index++ + } + + return next() + } + }, + } +} + +// SkipWhileIndexedT is the typed version of SkipWhileIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: SkipWhileIndexed has better performance than SkipWhileIndexedT. +func (q Query) SkipWhileIndexedT(predicateFn interface{}) Query { + predicateGenericFunc, err := newGenericFunc( + "SkipWhileIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return predicateGenericFunc.Call(index, item).(bool) + } + + return q.SkipWhileIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/take.go b/vendor/github.com/ahmetb/go-linq/take.go new file mode 100644 index 0000000..c2707e5 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/take.go @@ -0,0 +1,129 @@ +package linq + +// Take returns a specified number of contiguous elements from the start of a +// collection. +func (q Query) Take(count int) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + n := count + + return func() (item interface{}, ok bool) { + if n <= 0 { + return + } + + n-- + return next() + } + }, + } +} + +// TakeWhile returns elements from a collection as long as a specified condition +// is true, and then skips the remaining elements. +func (q Query) TakeWhile(predicate func(interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + done := false + + return func() (item interface{}, ok bool) { + if done { + return + } + + item, ok = next() + if !ok { + done = true + return + } + + if predicate(item) { + return + } + + done = true + return nil, false + } + }, + } +} + +// TakeWhileT is the typed version of TakeWhile. +// +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: TakeWhile has better performance than TakeWhileT. +func (q Query) TakeWhileT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "TakeWhileT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.TakeWhile(predicateFunc) +} + +// TakeWhileIndexed returns elements from a collection as long as a specified +// condition is true. The element's index is used in the logic of the predicate +// function. The first argument of predicate represents the zero-based index of +// the element within collection. The second argument represents the element to +// test. +func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + done := false + index := 0 + + return func() (item interface{}, ok bool) { + if done { + return + } + + item, ok = next() + if !ok { + done = true + return + } + + if predicate(index, item) { + index++ + return + } + + done = true + return nil, false + } + }, + } +} + +// TakeWhileIndexedT is the typed version of TakeWhileIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: TakeWhileIndexed has better performance than TakeWhileIndexedT. +func (q Query) TakeWhileIndexedT(predicateFn interface{}) Query { + whereFunc, err := newGenericFunc( + "TakeWhileIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return whereFunc.Call(index, item).(bool) + } + + return q.TakeWhileIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetalpbalkan/go-linq/union.go b/vendor/github.com/ahmetb/go-linq/union.go similarity index 78% rename from vendor/github.com/ahmetalpbalkan/go-linq/union.go rename to vendor/github.com/ahmetb/go-linq/union.go index 9ca4b65..717b83b 100644 --- a/vendor/github.com/ahmetalpbalkan/go-linq/union.go +++ b/vendor/github.com/ahmetb/go-linq/union.go @@ -2,10 +2,9 @@ package linq // Union produces the set union of two collections. // -// This method excludes duplicates from the return set. -// This is different behavior to the Concat method, -// which returns all the elements in the input collection -// including duplicates. +// This method excludes duplicates from the return set. This is different +// behavior to the Concat method, which returns all the elements in the input +// collection including duplicates. func (q Query) Union(q2 Query) Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetb/go-linq/where.go b/vendor/github.com/ahmetb/go-linq/where.go new file mode 100644 index 0000000..6fd4302 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/where.go @@ -0,0 +1,89 @@ +package linq + +// Where filters a collection of values based on a predicate. +func (q Query) Where(predicate func(interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + + return func() (item interface{}, ok bool) { + for item, ok = next(); ok; item, ok = next() { + if predicate(item) { + return + } + } + + return + } + }, + } +} + +// WhereT is the typed version of Where. +// +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: Where has better performance than WhereT. +func (q Query) WhereT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "WhereT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.Where(predicateFunc) +} + +// WhereIndexed filters a collection of values based on a predicate. Each +// element's index is used in the logic of the predicate function. +// +// The first argument represents the zero-based index of the element within +// collection. The second argument of predicate represents the element to test. +func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query { + return Query{ + Iterate: func() Iterator { + next := q.Iterate() + index := 0 + + return func() (item interface{}, ok bool) { + for item, ok = next(); ok; item, ok = next() { + if predicate(index, item) { + return + } + + index++ + } + + return + } + }, + } +} + +// WhereIndexedT is the typed version of WhereIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: WhereIndexed has better performance than WhereIndexedT. +func (q Query) WhereIndexedT(predicateFn interface{}) Query { + predicateGenericFunc, err := newGenericFunc( + "WhereIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return predicateGenericFunc.Call(index, item).(bool) + } + + return q.WhereIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/zip.go b/vendor/github.com/ahmetb/go-linq/zip.go new file mode 100644 index 0000000..da3dcd3 --- /dev/null +++ b/vendor/github.com/ahmetb/go-linq/zip.go @@ -0,0 +1,55 @@ +package linq + +// Zip applies a specified function to the corresponding elements of two +// collections, producing a collection of the results. +// +// The method steps through the two input collections, applying function +// resultSelector to corresponding elements of the two collections. The method +// returns a collection of the values that are returned by resultSelector. If +// the input collections do not have the same number of elements, the method +// combines elements until it reaches the end of one of the collections. For +// example, if one collection has three elements and the other one has four, the +// result collection has only three elements. +func (q Query) Zip(q2 Query, + resultSelector func(interface{}, interface{}) interface{}) Query { + + return Query{ + Iterate: func() Iterator { + next1 := q.Iterate() + next2 := q2.Iterate() + + return func() (item interface{}, ok bool) { + item1, ok1 := next1() + item2, ok2 := next2() + + if ok1 && ok2 { + return resultSelector(item1, item2), true + } + + return nil, false + } + }, + } +} + +// ZipT is the typed version of Zip. +// +// - resultSelectorFn is of type "func(TFirst,TSecond)TResult" +// +// NOTE: Zip has better performance than ZipT. +func (q Query) ZipT(q2 Query, + resultSelectorFn interface{}) Query { + resultSelectorGenericFunc, err := newGenericFunc( + "ZipT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(item1 interface{}, item2 interface{}) interface{} { + return resultSelectorGenericFunc.Call(item1, item2) + } + + return q.Zip(q2, resultSelectorFunc) +}