github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/tuple.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  import (
    18  	"fmt"
    19  	"reflect"
    20  )
    21  
    22  // Tuple represents Python 'tuple' objects.
    23  //
    24  // Tuples are thread safe by virtue of being immutable.
    25  type Tuple struct {
    26  	Object
    27  	elems []*Object
    28  }
    29  
    30  // NewTuple returns a tuple containing the given elements.
    31  func NewTuple(elems ...*Object) *Tuple {
    32  	if len(elems) == 0 {
    33  		return emptyTuple
    34  	}
    35  	return &Tuple{Object: Object{typ: TupleType}, elems: elems}
    36  }
    37  
    38  // Below are direct allocation versions of small Tuples. Rather than performing
    39  // two allocations, one for the tuple object and one for the slice holding the
    40  // elements, we allocate both objects at the same time in one block of memory.
    41  // This both decreases the number of allocations overall as well as increases
    42  // memory locality for tuple data. Both of which *should* improve time to
    43  // allocate as well as read performance. The methods below are used by the
    44  // compiler to create fixed size tuples when the size is known ahead of time.
    45  //
    46  // The number of specializations below were chosen first to cover all the fixed
    47  // size tuple allocations in the runtime (currently 5), then filled out to
    48  // cover the whole memory size class (see golang/src/runtime/sizeclasses.go for
    49  // the table). On a 64bit system, a tuple of length 6 occupies 96 bytes - 48
    50  // bytes for the tuple object and 6*8 (48) bytes of pointers.
    51  //
    52  // If methods are added or removed, then the constant MAX_DIRECT_TUPLE in
    53  // compiler/util.py needs to be updated as well.
    54  
    55  // NewTuple0 returns the empty tuple. This is mostly provided for the
    56  // convenience of the compiler.
    57  func NewTuple0() *Tuple { return emptyTuple }
    58  
    59  // NewTuple1 returns a tuple of length 1 containing just elem0.
    60  func NewTuple1(elem0 *Object) *Tuple {
    61  	t := struct {
    62  		tuple Tuple
    63  		elems [1]*Object
    64  	}{
    65  		tuple: Tuple{Object: Object{typ: TupleType}},
    66  		elems: [1]*Object{elem0},
    67  	}
    68  	t.tuple.elems = t.elems[:]
    69  	return &t.tuple
    70  }
    71  
    72  // NewTuple2 returns a tuple of length 2 containing just elem0 and elem1.
    73  func NewTuple2(elem0, elem1 *Object) *Tuple {
    74  	t := struct {
    75  		tuple Tuple
    76  		elems [2]*Object
    77  	}{
    78  		tuple: Tuple{Object: Object{typ: TupleType}},
    79  		elems: [2]*Object{elem0, elem1},
    80  	}
    81  	t.tuple.elems = t.elems[:]
    82  	return &t.tuple
    83  }
    84  
    85  // NewTuple3 returns a tuple of length 3 containing elem0 to elem2.
    86  func NewTuple3(elem0, elem1, elem2 *Object) *Tuple {
    87  	t := struct {
    88  		tuple Tuple
    89  		elems [3]*Object
    90  	}{
    91  		tuple: Tuple{Object: Object{typ: TupleType}},
    92  		elems: [3]*Object{elem0, elem1, elem2},
    93  	}
    94  	t.tuple.elems = t.elems[:]
    95  	return &t.tuple
    96  }
    97  
    98  // NewTuple4 returns a tuple of length 4 containing elem0 to elem3.
    99  func NewTuple4(elem0, elem1, elem2, elem3 *Object) *Tuple {
   100  	t := struct {
   101  		tuple Tuple
   102  		elems [4]*Object
   103  	}{
   104  		tuple: Tuple{Object: Object{typ: TupleType}},
   105  		elems: [4]*Object{elem0, elem1, elem2, elem3},
   106  	}
   107  	t.tuple.elems = t.elems[:]
   108  	return &t.tuple
   109  }
   110  
   111  // NewTuple5 returns a tuple of length 5 containing elem0 to elem4.
   112  func NewTuple5(elem0, elem1, elem2, elem3, elem4 *Object) *Tuple {
   113  	t := struct {
   114  		tuple Tuple
   115  		elems [5]*Object
   116  	}{
   117  		tuple: Tuple{Object: Object{typ: TupleType}},
   118  		elems: [5]*Object{elem0, elem1, elem2, elem3, elem4},
   119  	}
   120  	t.tuple.elems = t.elems[:]
   121  	return &t.tuple
   122  }
   123  
   124  // NewTuple6 returns a tuple of length 6 containing elem0 to elem5.
   125  func NewTuple6(elem0, elem1, elem2, elem3, elem4, elem5 *Object) *Tuple {
   126  	t := struct {
   127  		tuple Tuple
   128  		elems [6]*Object
   129  	}{
   130  		tuple: Tuple{Object: Object{typ: TupleType}},
   131  		elems: [6]*Object{elem0, elem1, elem2, elem3, elem4, elem5},
   132  	}
   133  	t.tuple.elems = t.elems[:]
   134  	return &t.tuple
   135  }
   136  
   137  func toTupleUnsafe(o *Object) *Tuple {
   138  	return (*Tuple)(o.toPointer())
   139  }
   140  
   141  // GetItem returns the i'th element of t. Bounds are unchecked and therefore
   142  // this method will panic unless 0 <= i < t.Len().
   143  func (t *Tuple) GetItem(i int) *Object {
   144  	return t.elems[i]
   145  }
   146  
   147  // Len returns the number of elements in t.
   148  func (t *Tuple) Len() int {
   149  	return len(t.elems)
   150  }
   151  
   152  // ToObject upcasts t to an Object.
   153  func (t *Tuple) ToObject() *Object {
   154  	return &t.Object
   155  }
   156  
   157  // TupleType is the object representing the Python 'tuple' type.
   158  var TupleType = newBasisType("tuple", reflect.TypeOf(Tuple{}), toTupleUnsafe, ObjectType)
   159  
   160  var emptyTuple = &Tuple{Object: Object{typ: TupleType}}
   161  
   162  func tupleAdd(f *Frame, v, w *Object) (*Object, *BaseException) {
   163  	if !w.isInstance(TupleType) {
   164  		return NotImplemented, nil
   165  	}
   166  	elems, raised := seqAdd(f, toTupleUnsafe(v).elems, toTupleUnsafe(w).elems)
   167  	if raised != nil {
   168  		return nil, raised
   169  	}
   170  	return NewTuple(elems...).ToObject(), nil
   171  }
   172  
   173  func tupleContains(f *Frame, t, v *Object) (*Object, *BaseException) {
   174  	return seqContains(f, t, v)
   175  }
   176  
   177  func tupleCount(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   178  	if raised := checkMethodArgs(f, "count", args, TupleType, ObjectType); raised != nil {
   179  		return nil, raised
   180  	}
   181  	return seqCount(f, args[0], args[1])
   182  }
   183  
   184  func tupleIndex(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
   185  	expectedTypes := []*Type{TupleType, ObjectType, ObjectType, ObjectType}
   186  	argc := len(args)
   187  	var raised *BaseException
   188  	if argc == 2 || argc == 3 {
   189  		expectedTypes = expectedTypes[:argc]
   190  	}
   191  	if raised = checkMethodArgs(f, "index", args, expectedTypes...); raised != nil {
   192  		return nil, raised
   193  	}
   194  	t := toTupleUnsafe(args[0])
   195  	numElems := len(t.elems)
   196  	start, stop := 0, numElems
   197  	if argc > 2 {
   198  		start, raised = IndexInt(f, args[2])
   199  		if raised != nil {
   200  			return nil, raised
   201  		}
   202  	}
   203  	if argc > 3 {
   204  		stop, raised = IndexInt(f, args[3])
   205  		if raised != nil {
   206  			return nil, raised
   207  		}
   208  	}
   209  	start, stop = adjustIndex(start, stop, numElems)
   210  	value := args[1]
   211  	index := -1
   212  	if start < numElems && start < stop {
   213  		index, raised = seqFindElem(f, t.elems[start:stop], value)
   214  	}
   215  	if raised != nil {
   216  		return nil, raised
   217  	}
   218  	if index == -1 {
   219  		return nil, f.RaiseType(ValueErrorType, fmt.Sprintf("%v is not in tuple", value))
   220  	}
   221  	return NewInt(index + start).ToObject(), nil
   222  }
   223  
   224  func tupleEq(f *Frame, v, w *Object) (*Object, *BaseException) {
   225  	return tupleCompare(f, toTupleUnsafe(v), w, Eq)
   226  }
   227  
   228  func tupleGE(f *Frame, v, w *Object) (*Object, *BaseException) {
   229  	return tupleCompare(f, toTupleUnsafe(v), w, GE)
   230  }
   231  
   232  func tupleGetItem(f *Frame, o, key *Object) (*Object, *BaseException) {
   233  	t := toTupleUnsafe(o)
   234  	item, elems, raised := seqGetItem(f, t.elems, key)
   235  	if raised != nil {
   236  		return nil, raised
   237  	}
   238  	if item != nil {
   239  		return item, nil
   240  	}
   241  	return NewTuple(elems...).ToObject(), nil
   242  }
   243  
   244  func tupleGetNewArgs(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   245  	if raised := checkMethodArgs(f, "__getnewargs__", args, TupleType); raised != nil {
   246  		return nil, raised
   247  	}
   248  	return NewTuple1(args[0]).ToObject(), nil
   249  }
   250  
   251  func tupleGT(f *Frame, v, w *Object) (*Object, *BaseException) {
   252  	return tupleCompare(f, toTupleUnsafe(v), w, GT)
   253  }
   254  
   255  func tupleIter(f *Frame, o *Object) (*Object, *BaseException) {
   256  	return newSliceIterator(reflect.ValueOf(toTupleUnsafe(o).elems)), nil
   257  }
   258  
   259  func tupleLE(f *Frame, v, w *Object) (*Object, *BaseException) {
   260  	return tupleCompare(f, toTupleUnsafe(v), w, LE)
   261  }
   262  
   263  func tupleLen(f *Frame, o *Object) (*Object, *BaseException) {
   264  	return NewInt(len(toTupleUnsafe(o).elems)).ToObject(), nil
   265  }
   266  
   267  func tupleLT(f *Frame, v, w *Object) (*Object, *BaseException) {
   268  	return tupleCompare(f, toTupleUnsafe(v), w, LT)
   269  }
   270  
   271  func tupleMul(f *Frame, v, w *Object) (*Object, *BaseException) {
   272  	if !w.isInstance(IntType) {
   273  		return NotImplemented, nil
   274  	}
   275  	elems, raised := seqMul(f, toTupleUnsafe(v).elems, toIntUnsafe(w).Value())
   276  	if raised != nil {
   277  		return nil, raised
   278  	}
   279  	return NewTuple(elems...).ToObject(), nil
   280  }
   281  
   282  func tupleNE(f *Frame, v, w *Object) (*Object, *BaseException) {
   283  	return tupleCompare(f, toTupleUnsafe(v), w, NE)
   284  }
   285  
   286  func tupleNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) {
   287  	if t == TupleType && len(args) == 1 && args[0].typ == TupleType {
   288  		// Tuples are immutable so just return the tuple provided.
   289  		return args[0], nil
   290  	}
   291  	elems, raised := seqNew(f, args)
   292  	if raised != nil {
   293  		return nil, raised
   294  	}
   295  	tup := toTupleUnsafe(newObject(t))
   296  	tup.elems = elems
   297  	return tup.ToObject(), nil
   298  }
   299  
   300  func tupleRepr(f *Frame, o *Object) (*Object, *BaseException) {
   301  	t := toTupleUnsafe(o)
   302  	if f.reprEnter(t.ToObject()) {
   303  		return NewStr("(...)").ToObject(), nil
   304  	}
   305  	s, raised := seqRepr(f, t.elems)
   306  	f.reprLeave(t.ToObject())
   307  	if raised != nil {
   308  		return nil, raised
   309  	}
   310  	if len(t.elems) == 1 {
   311  		s = fmt.Sprintf("(%s,)", s)
   312  	} else {
   313  		s = fmt.Sprintf("(%s)", s)
   314  	}
   315  	return NewStr(s).ToObject(), nil
   316  }
   317  
   318  func tupleRMul(f *Frame, v, w *Object) (*Object, *BaseException) {
   319  	if !w.isInstance(IntType) {
   320  		return NotImplemented, nil
   321  	}
   322  	elems, raised := seqMul(f, toTupleUnsafe(v).elems, toIntUnsafe(w).Value())
   323  	if raised != nil {
   324  		return nil, raised
   325  	}
   326  	return NewTuple(elems...).ToObject(), nil
   327  }
   328  
   329  func initTupleType(dict map[string]*Object) {
   330  	dict["count"] = newBuiltinFunction("count", tupleCount).ToObject()
   331  	dict["index"] = newBuiltinFunction("index", tupleIndex).ToObject()
   332  	dict["__getnewargs__"] = newBuiltinFunction("__getnewargs__", tupleGetNewArgs).ToObject()
   333  	TupleType.slots.Add = &binaryOpSlot{tupleAdd}
   334  	TupleType.slots.Contains = &binaryOpSlot{tupleContains}
   335  	TupleType.slots.Eq = &binaryOpSlot{tupleEq}
   336  	TupleType.slots.GE = &binaryOpSlot{tupleGE}
   337  	TupleType.slots.GetItem = &binaryOpSlot{tupleGetItem}
   338  	TupleType.slots.GT = &binaryOpSlot{tupleGT}
   339  	TupleType.slots.Iter = &unaryOpSlot{tupleIter}
   340  	TupleType.slots.LE = &binaryOpSlot{tupleLE}
   341  	TupleType.slots.Len = &unaryOpSlot{tupleLen}
   342  	TupleType.slots.LT = &binaryOpSlot{tupleLT}
   343  	TupleType.slots.Mul = &binaryOpSlot{tupleMul}
   344  	TupleType.slots.NE = &binaryOpSlot{tupleNE}
   345  	TupleType.slots.New = &newSlot{tupleNew}
   346  	TupleType.slots.Repr = &unaryOpSlot{tupleRepr}
   347  	TupleType.slots.RMul = &binaryOpSlot{tupleRMul}
   348  }
   349  
   350  func tupleCompare(f *Frame, v *Tuple, w *Object, cmp binaryOpFunc) (*Object, *BaseException) {
   351  	if !w.isInstance(TupleType) {
   352  		return NotImplemented, nil
   353  	}
   354  	return seqCompare(f, v.elems, toTupleUnsafe(w).elems, cmp)
   355  }