github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/seq.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package grumpy
    16  
    17  // This file contains common code and helpers for sequence types.
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  	"sync"
    24  )
    25  
    26  var (
    27  	seqIteratorType = newBasisType("iterator", reflect.TypeOf(seqIterator{}), toSeqIteratorUnsafe, ObjectType)
    28  )
    29  
    30  func seqAdd(f *Frame, elems1, elems2 []*Object) ([]*Object, *BaseException) {
    31  	if len(elems1)+len(elems2) < 0 {
    32  		// This indicates an int overflow.
    33  		return nil, f.RaiseType(OverflowErrorType, errResultTooLarge)
    34  	}
    35  	return append(elems1, elems2...), nil
    36  }
    37  
    38  func seqCompare(f *Frame, elems1, elems2 []*Object, cmp binaryOpFunc) (*Object, *BaseException) {
    39  	n1 := len(elems1)
    40  	n2 := len(elems2)
    41  	for i := 0; i < n1 && i < n2; i++ {
    42  		eq, raised := Eq(f, elems1[i], elems2[i])
    43  		if raised != nil {
    44  			return nil, raised
    45  		}
    46  		if ret, raised := IsTrue(f, eq); raised != nil {
    47  			return nil, raised
    48  		} else if !ret {
    49  			// We encountered an unequal element before the end of
    50  			// either sequence so perform the comparison on the two
    51  			// elements.
    52  			return cmp(f, elems1[i], elems2[i])
    53  		}
    54  	}
    55  	// One sequence is longer than the other, so do the comparison on the
    56  	// lengths of the two sequences.
    57  	return cmp(f, NewInt(n1).ToObject(), NewInt(n2).ToObject())
    58  }
    59  
    60  // seqApply calls fun with a slice of objects contained in the sequence object
    61  // seq. If the second callback parameter is true, the slice is borrowed and the
    62  // function must not modify the provided slice. Otherwise the slice is scratch
    63  // and it may freely be used in any way. It will raise if seq is not a sequence
    64  // object.
    65  func seqApply(f *Frame, seq *Object, fun func([]*Object, bool) *BaseException) *BaseException {
    66  	switch {
    67  	// Don't use fast path referencing the underlying slice directly for
    68  	// list and tuple subtypes. See comment in listextend in listobject.c.
    69  	case seq.typ == ListType:
    70  		l := toListUnsafe(seq)
    71  		l.mutex.RLock()
    72  		raised := fun(l.elems, true)
    73  		l.mutex.RUnlock()
    74  		return raised
    75  	case seq.typ == TupleType:
    76  		return fun(toTupleUnsafe(seq).elems, true)
    77  	default:
    78  		elems := []*Object{}
    79  		raised := seqForEach(f, seq, func(elem *Object) *BaseException {
    80  			elems = append(elems, elem)
    81  			return nil
    82  		})
    83  		if raised != nil {
    84  			return raised
    85  		}
    86  		return fun(elems, false)
    87  	}
    88  }
    89  
    90  func seqCheckedIndex(f *Frame, seqLen, index int) (int, *BaseException) {
    91  	if index < 0 {
    92  		index = seqLen + index
    93  	}
    94  	if index < 0 || index >= seqLen {
    95  		return 0, f.RaiseType(IndexErrorType, "index out of range")
    96  	}
    97  	return index, nil
    98  }
    99  
   100  func seqClampIndex(i, seqLen int) int {
   101  	if i < 0 {
   102  		i += seqLen
   103  		if i < 0 {
   104  			i = 0
   105  		}
   106  	}
   107  	if i > seqLen {
   108  		i = seqLen
   109  	}
   110  	return i
   111  }
   112  
   113  func seqContains(f *Frame, iterable *Object, v *Object) (*Object, *BaseException) {
   114  	pred := func(o *Object) (bool, *BaseException) {
   115  		eq, raised := Eq(f, v, o)
   116  		if raised != nil {
   117  			return false, raised
   118  		}
   119  		ret, raised := IsTrue(f, eq)
   120  		if raised != nil {
   121  			return false, raised
   122  		}
   123  		return ret, nil
   124  	}
   125  	foundEqItem, raised := seqFindFirst(f, iterable, pred)
   126  	if raised != nil {
   127  		return nil, raised
   128  	}
   129  	return GetBool(foundEqItem).ToObject(), raised
   130  }
   131  
   132  func seqCount(f *Frame, iterable *Object, v *Object) (*Object, *BaseException) {
   133  	count := 0
   134  	raised := seqForEach(f, iterable, func(o *Object) *BaseException {
   135  		eq, raised := Eq(f, o, v)
   136  		if raised != nil {
   137  			return raised
   138  		}
   139  		t, raised := IsTrue(f, eq)
   140  		if raised != nil {
   141  			return raised
   142  		}
   143  		if t {
   144  			count++
   145  		}
   146  		return nil
   147  	})
   148  	if raised != nil {
   149  		return nil, raised
   150  	}
   151  	return NewInt(count).ToObject(), nil
   152  }
   153  
   154  func seqFindFirst(f *Frame, iterable *Object, pred func(*Object) (bool, *BaseException)) (bool, *BaseException) {
   155  	iter, raised := Iter(f, iterable)
   156  	if raised != nil {
   157  		return false, raised
   158  	}
   159  	item, raised := Next(f, iter)
   160  	for ; raised == nil; item, raised = Next(f, iter) {
   161  		ret, raised := pred(item)
   162  		if raised != nil {
   163  			return false, raised
   164  		}
   165  		if ret {
   166  			return true, nil
   167  		}
   168  	}
   169  	if !raised.isInstance(StopIterationType) {
   170  		return false, raised
   171  	}
   172  	f.RestoreExc(nil, nil)
   173  	return false, nil
   174  }
   175  
   176  func seqFindElem(f *Frame, elems []*Object, o *Object) (int, *BaseException) {
   177  	for i, elem := range elems {
   178  		eq, raised := Eq(f, elem, o)
   179  		if raised != nil {
   180  			return -1, raised
   181  		}
   182  		found, raised := IsTrue(f, eq)
   183  		if raised != nil {
   184  			return -1, raised
   185  		}
   186  		if found {
   187  			return i, nil
   188  		}
   189  	}
   190  	return -1, nil
   191  }
   192  
   193  func seqForEach(f *Frame, iterable *Object, callback func(*Object) *BaseException) *BaseException {
   194  	iter, raised := Iter(f, iterable)
   195  	if raised != nil {
   196  		return raised
   197  	}
   198  	item, raised := Next(f, iter)
   199  	for ; raised == nil; item, raised = Next(f, iter) {
   200  		if raised := callback(item); raised != nil {
   201  			return raised
   202  		}
   203  	}
   204  	if !raised.isInstance(StopIterationType) {
   205  		return raised
   206  	}
   207  	f.RestoreExc(nil, nil)
   208  	return nil
   209  }
   210  
   211  // seqGetItem returns a single element or a slice of elements of elems
   212  // depending on whether index is an integer or a slice. If index is neither of
   213  // those types then a TypeError is returned.
   214  func seqGetItem(f *Frame, elems []*Object, index *Object) (*Object, []*Object, *BaseException) {
   215  	switch {
   216  	case index.typ.slots.Index != nil:
   217  		i, raised := IndexInt(f, index)
   218  		if raised != nil {
   219  			return nil, nil, raised
   220  		}
   221  		i, raised = seqCheckedIndex(f, len(elems), i)
   222  		if raised != nil {
   223  			return nil, nil, raised
   224  		}
   225  		return elems[i], nil, nil
   226  	case index.isInstance(SliceType):
   227  		s := toSliceUnsafe(index)
   228  		start, stop, step, sliceLen, raised := s.calcSlice(f, len(elems))
   229  		if raised != nil {
   230  			return nil, nil, raised
   231  		}
   232  		result := make([]*Object, sliceLen)
   233  		i := 0
   234  		for j := start; j != stop; j += step {
   235  			result[i] = elems[j]
   236  			i++
   237  		}
   238  		return nil, result, nil
   239  	}
   240  	return nil, nil, f.RaiseType(TypeErrorType, fmt.Sprintf("sequence indices must be integers, not %s", index.typ.Name()))
   241  }
   242  
   243  func seqMul(f *Frame, elems []*Object, n int) ([]*Object, *BaseException) {
   244  	if n <= 0 {
   245  		return nil, nil
   246  	}
   247  	numElems := len(elems)
   248  	if numElems > MaxInt/n {
   249  		return nil, f.RaiseType(OverflowErrorType, errResultTooLarge)
   250  	}
   251  	newNumElems := numElems * n
   252  	resultElems := make([]*Object, newNumElems)
   253  	for i := 0; i < newNumElems; i++ {
   254  		resultElems[i] = elems[i%numElems]
   255  	}
   256  	return resultElems, nil
   257  }
   258  
   259  func seqNew(f *Frame, args Args) ([]*Object, *BaseException) {
   260  	if len(args) == 0 {
   261  		return nil, nil
   262  	}
   263  	if raised := checkMethodArgs(f, "__new__", args, ObjectType); raised != nil {
   264  		return nil, raised
   265  	}
   266  	var result []*Object
   267  	raised := seqApply(f, args[0], func(elems []*Object, borrowed bool) *BaseException {
   268  		if borrowed {
   269  			result = make([]*Object, len(elems))
   270  			copy(result, elems)
   271  		} else {
   272  			result = elems
   273  		}
   274  		return nil
   275  	})
   276  	if raised != nil {
   277  		return nil, raised
   278  	}
   279  	return result, nil
   280  }
   281  
   282  type seqRangeResult int
   283  
   284  const (
   285  	seqRangeOK seqRangeResult = iota
   286  	seqRangeOverflow
   287  	seqRangeZeroStep
   288  )
   289  
   290  // seqRange takes the bounds and stride defining a Python range (e.g.
   291  // xrange(start, stop, step)) and returns three things:
   292  //
   293  // 1. The terminal value for the range when iterating
   294  // 2. The length of the range (i.e. the number of iterations)
   295  // 3. A status indicating whether the range is valid
   296  //
   297  // The terminal value can be used to iterate over the range as follows:
   298  //
   299  // for i := start; i != term; i += step { ... }
   300  func seqRange(start, stop, step int) (int, int, seqRangeResult) {
   301  	if step == 0 {
   302  		return 0, 0, seqRangeZeroStep
   303  	}
   304  	if stop == start || (stop > start) != (step > 0) {
   305  		// The step doesn't make progress towards the goal,
   306  		// so return an empty range.
   307  		return start, 0, seqRangeOK
   308  	}
   309  	if step > 0 {
   310  		stop--
   311  	} else {
   312  		stop++
   313  	}
   314  	n := (stop-start)/step + 1
   315  	if n < 0 {
   316  		return 0, 0, seqRangeOverflow
   317  	}
   318  	return start + n*step, n, seqRangeOK
   319  }
   320  
   321  func seqRepr(f *Frame, elems []*Object) (string, *BaseException) {
   322  	var buf bytes.Buffer
   323  	for i, o := range elems {
   324  		if i > 0 {
   325  			buf.WriteString(", ")
   326  		}
   327  		s, raised := Repr(f, o)
   328  		if raised != nil {
   329  			return "", raised
   330  		}
   331  		buf.WriteString(s.Value())
   332  		i++
   333  	}
   334  	return buf.String(), nil
   335  }
   336  
   337  func seqWrapEach(f *Frame, elems ...interface{}) ([]*Object, *BaseException) {
   338  	result := make([]*Object, len(elems))
   339  	for i, elem := range elems {
   340  		var raised *BaseException
   341  		if result[i], raised = WrapNative(f, reflect.ValueOf(elem)); raised != nil {
   342  			return nil, raised
   343  		}
   344  	}
   345  	return result, nil
   346  }
   347  
   348  type seqIterator struct {
   349  	Object
   350  	seq   *Object
   351  	mutex sync.Mutex
   352  	index int
   353  }
   354  
   355  func newSeqIterator(seq *Object) *Object {
   356  	iter := &seqIterator{Object: Object{typ: seqIteratorType}, seq: seq}
   357  	return &iter.Object
   358  }
   359  
   360  func toSeqIteratorUnsafe(o *Object) *seqIterator {
   361  	return (*seqIterator)(o.toPointer())
   362  }
   363  
   364  func seqIteratorIter(f *Frame, o *Object) (*Object, *BaseException) {
   365  	return o, nil
   366  }
   367  
   368  func seqIteratorNext(f *Frame, o *Object) (item *Object, raised *BaseException) {
   369  	i := toSeqIteratorUnsafe(o)
   370  	i.mutex.Lock()
   371  	if i.seq == nil {
   372  		raised = f.Raise(StopIterationType.ToObject(), nil, nil)
   373  	} else if item, raised = GetItem(f, i.seq, NewInt(i.index).ToObject()); raised == nil {
   374  		i.index++
   375  	} else if raised.isInstance(IndexErrorType) {
   376  		i.seq = nil
   377  		raised = f.Raise(StopIterationType.ToObject(), nil, nil)
   378  	}
   379  	i.mutex.Unlock()
   380  	return item, raised
   381  }
   382  
   383  func initSeqIteratorType(map[string]*Object) {
   384  	seqIteratorType.flags &= ^(typeFlagBasetype | typeFlagInstantiable)
   385  	seqIteratorType.slots.Iter = &unaryOpSlot{seqIteratorIter}
   386  	seqIteratorType.slots.Next = &unaryOpSlot{seqIteratorNext}
   387  }