github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/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 }