123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- package jet
- import (
- "errors"
- "fmt"
- "reflect"
- "sync"
- )
- // Ranger describes an interface for types that iterate over something.
- // Implementing this interface means the ranger will be used when it's
- // encountered on the right hand side of a range's "let" expression.
- type Ranger interface {
- // Range calls should return a key, a value and a done bool to indicate
- // whether there are more values to be generated.
- //
- // When the done flag is true, then the loop ends.
- Range() (reflect.Value, reflect.Value, bool)
- // ProvidesIndex should return true if keys are produced during Range()
- // calls. This call should be idempotent across Range() calls (i.e.
- // its return value must not change during an iteration).
- ProvidesIndex() bool
- }
- type intsRanger struct {
- i, val, to int64
- }
- var _ Ranger = &intsRanger{}
- func (r *intsRanger) Range() (index, value reflect.Value, end bool) {
- r.i++
- r.val++
- end = r.val == r.to
- // The indirection in the ValueOf calls avoids an allocation versus
- // using the concrete value of 'i' and 'val'. The downside is having
- // to interpret 'r.i' as "the current value" after Range() returns,
- // and so it needs to be initialized as -1.
- index = reflect.ValueOf(&r.i).Elem()
- value = reflect.ValueOf(&r.val).Elem()
- return
- }
- func (r *intsRanger) ProvidesIndex() bool { return true }
- func newIntsRanger(from, to int64) *intsRanger {
- r := &intsRanger{
- to: to,
- i: -1,
- val: from - 1,
- }
- return r
- }
- type pooledRanger interface {
- Ranger
- Setup(reflect.Value)
- }
- type sliceRanger struct {
- v reflect.Value
- i int
- }
- var _ Ranger = &sliceRanger{}
- var _ pooledRanger = &sliceRanger{}
- func (r *sliceRanger) Setup(v reflect.Value) {
- r.i = 0
- r.v = v
- }
- func (r *sliceRanger) Range() (index, value reflect.Value, end bool) {
- if r.i == r.v.Len() {
- end = true
- return
- }
- index = reflect.ValueOf(r.i)
- value = r.v.Index(r.i)
- r.i++
- return
- }
- func (r *sliceRanger) ProvidesIndex() bool { return true }
- type mapRanger struct {
- iter *reflect.MapIter
- hasMore bool
- }
- var _ Ranger = &mapRanger{}
- var _ pooledRanger = &mapRanger{}
- func (r *mapRanger) Setup(v reflect.Value) {
- r.iter = v.MapRange()
- r.hasMore = r.iter.Next()
- }
- func (r *mapRanger) Range() (key, value reflect.Value, end bool) {
- if !r.hasMore {
- end = true
- return
- }
- key, value = r.iter.Key(), r.iter.Value()
- r.hasMore = r.iter.Next()
- return
- }
- func (r *mapRanger) ProvidesIndex() bool { return true }
- type chanRanger struct {
- v reflect.Value
- }
- var _ Ranger = &chanRanger{}
- var _ pooledRanger = &chanRanger{}
- func (r *chanRanger) Setup(v reflect.Value) {
- r.v = v
- }
- func (r *chanRanger) Range() (_, value reflect.Value, end bool) {
- v, ok := r.v.Recv()
- value, end = v, !ok
- return
- }
- func (r *chanRanger) ProvidesIndex() bool { return false }
- // ranger pooling
- var (
- poolSliceRanger = &sync.Pool{
- New: func() interface{} {
- return new(sliceRanger)
- },
- }
- poolsByKind = map[reflect.Kind]*sync.Pool{
- reflect.Slice: poolSliceRanger,
- reflect.Array: poolSliceRanger,
- reflect.Map: &sync.Pool{
- New: func() interface{} {
- return new(mapRanger)
- },
- },
- reflect.Chan: &sync.Pool{
- New: func() interface{} {
- return new(chanRanger)
- },
- },
- }
- )
- func getRanger(v reflect.Value) (r Ranger, cleanup func(), err error) {
- if !v.IsValid() {
- return nil, nil, errors.New("can't range over invalid value")
- }
- t := v.Type()
- if t.Implements(rangerType) {
- return v.Interface().(Ranger), func() { /* no cleanup needed */ }, nil
- }
- v, isNil := indirect(v)
- if isNil {
- return nil, nil, fmt.Errorf("cannot range over nil pointer/interface (%s)", t)
- }
- pool, ok := poolsByKind[v.Kind()]
- if !ok {
- return nil, nil, fmt.Errorf("value %v (type %s) is not rangeable", v, t)
- }
- pr := pool.Get().(pooledRanger)
- pr.Setup(v)
- return pr, func() { pool.Put(pr) }, nil
- }
|