github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/list.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 "sort" 21 "sync" 22 ) 23 24 // List represents Python 'list' objects. 25 // 26 // Lists are thread safe, however read operations are not necessarily atomic. 27 // E.g. given the list l = [1, 2, 3] executing del l[1] in one thread may give 28 // repr(l) == [1, 2] in another which is never correct. 29 type List struct { 30 Object 31 mutex sync.RWMutex 32 elems []*Object 33 } 34 35 // NewList returns a list containing the given elements. 36 func NewList(elems ...*Object) *List { 37 l := &List{Object: Object{typ: ListType}} 38 numElems := len(elems) 39 l.resize(numElems) 40 for i := 0; i < numElems; i++ { 41 l.elems[i] = elems[i] 42 } 43 return l 44 } 45 46 func toListUnsafe(o *Object) *List { 47 return (*List)(o.toPointer()) 48 } 49 50 // ToObject upcasts l to an Object. 51 func (l *List) ToObject() *Object { 52 return &l.Object 53 } 54 55 // Append adds o to the end of l. 56 func (l *List) Append(o *Object) { 57 l.mutex.Lock() 58 newLen := len(l.elems) + 1 59 l.resize(newLen) 60 l.elems[newLen-1] = o 61 l.mutex.Unlock() 62 } 63 64 // DelItem removes the index'th element of l. 65 func (l *List) DelItem(f *Frame, index int) *BaseException { 66 l.mutex.Lock() 67 numElems := len(l.elems) 68 i, raised := seqCheckedIndex(f, numElems, index) 69 if raised == nil { 70 copy(l.elems[i:numElems-1], l.elems[i+1:numElems]) 71 l.elems = l.elems[:numElems-1] 72 } 73 l.mutex.Unlock() 74 return raised 75 } 76 77 // DelSlice removes the slice of l specified by s. 78 func (l *List) DelSlice(f *Frame, s *Slice) *BaseException { 79 l.mutex.Lock() 80 numListElems := len(l.elems) 81 start, stop, step, numSliceElems, raised := s.calcSlice(f, numListElems) 82 if raised == nil { 83 if step == 1 { 84 copy(l.elems[start:numListElems-numSliceElems], l.elems[stop:numListElems]) 85 } else { 86 j := 0 87 for i := start; i != stop; i += step { 88 next := i + step 89 if next > numListElems { 90 next = numListElems 91 } 92 dest := l.elems[i-j : next-j-1] 93 src := l.elems[i+1 : next] 94 copy(dest, src) 95 j++ 96 } 97 } 98 l.elems = l.elems[:numListElems-numSliceElems] 99 } 100 l.mutex.Unlock() 101 return raised 102 } 103 104 // SetItem sets the index'th element of l to value. 105 func (l *List) SetItem(f *Frame, index int, value *Object) *BaseException { 106 l.mutex.Lock() 107 i, raised := seqCheckedIndex(f, len(l.elems), index) 108 if raised == nil { 109 l.elems[i] = value 110 } 111 l.mutex.Unlock() 112 return raised 113 } 114 115 // SetSlice replaces the slice of l specified by s with the contents of value 116 // (an iterable). 117 func (l *List) SetSlice(f *Frame, s *Slice, value *Object) *BaseException { 118 l.mutex.Lock() 119 numListElems := len(l.elems) 120 start, stop, step, numSliceElems, raised := s.calcSlice(f, numListElems) 121 if raised == nil { 122 raised = seqApply(f, value, func(elems []*Object, _ bool) *BaseException { 123 numElems := len(elems) 124 if step == 1 { 125 tailElems := l.elems[stop:numListElems] 126 l.resize(numListElems - numSliceElems + numElems) 127 copy(l.elems[start+numElems:], tailElems) 128 copy(l.elems[start:start+numElems], elems) 129 } else if numSliceElems == numElems { 130 i := 0 131 for j := start; j != stop; j += step { 132 l.elems[j] = elems[i] 133 i++ 134 } 135 } else { 136 format := "attempt to assign sequence of size %d to extended slice of size %d" 137 return f.RaiseType(ValueErrorType, fmt.Sprintf(format, numElems, numSliceElems)) 138 } 139 return nil 140 }) 141 } 142 l.mutex.Unlock() 143 return raised 144 } 145 146 // Sort reorders l so that its elements are in sorted order. 147 func (l *List) Sort(f *Frame) (raised *BaseException) { 148 l.mutex.RLock() 149 sorter := &listSorter{f, l, nil} 150 defer func() { 151 l.mutex.RUnlock() 152 if val := recover(); val == nil { 153 return 154 } else if s, ok := val.(*listSorter); !ok || s != sorter { 155 panic(val) 156 } 157 raised = sorter.raised 158 }() 159 // Python guarantees stability. See note (9) in: 160 // https://docs.python.org/2/library/stdtypes.html#mutable-sequence-types 161 sort.Stable(sorter) 162 return nil 163 } 164 165 // resize ensures that len(l.elems) == newLen, reallocating if necessary. 166 // NOTE: l.mutex must be locked when calling resize. 167 func (l *List) resize(newLen int) { 168 if cap(l.elems) < newLen { 169 // Borrowed from CPython's list_resize() in listobject.c. 170 newCap := (newLen >> 3) + 3 + newLen 171 if newLen >= 9 { 172 newCap += 3 173 } 174 newElems := make([]*Object, len(l.elems), newCap) 175 copy(newElems, l.elems) 176 l.elems = newElems 177 } 178 l.elems = l.elems[:newLen] 179 } 180 181 // ListType is the object representing the Python 'list' type. 182 var ListType = newBasisType("list", reflect.TypeOf(List{}), toListUnsafe, ObjectType) 183 184 func listAdd(f *Frame, v, w *Object) (ret *Object, raised *BaseException) { 185 if !w.isInstance(ListType) { 186 return NotImplemented, nil 187 } 188 listV, listW := toListUnsafe(v), toListUnsafe(w) 189 listV.mutex.RLock() 190 listW.mutex.RLock() 191 elems, raised := seqAdd(f, listV.elems, listW.elems) 192 if raised == nil { 193 ret = NewList(elems...).ToObject() 194 } 195 listW.mutex.RUnlock() 196 listV.mutex.RUnlock() 197 return ret, raised 198 } 199 200 func listAppend(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 201 if raised := checkMethodArgs(f, "append", args, ListType, ObjectType); raised != nil { 202 return nil, raised 203 } 204 toListUnsafe(args[0]).Append(args[1]) 205 return None, nil 206 } 207 208 func listCount(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 209 if raised := checkMethodArgs(f, "count", args, ListType, ObjectType); raised != nil { 210 return nil, raised 211 } 212 return seqCount(f, args[0], args[1]) 213 } 214 215 func listDelItem(f *Frame, o *Object, key *Object) *BaseException { 216 l := toListUnsafe(o) 217 if key.isInstance(SliceType) { 218 return l.DelSlice(f, toSliceUnsafe(key)) 219 } 220 if key.typ.slots.Index == nil { 221 format := "list indices must be integers, not %s" 222 return f.RaiseType(TypeErrorType, fmt.Sprintf(format, key.Type().Name())) 223 } 224 index, raised := IndexInt(f, key) 225 if raised != nil { 226 return raised 227 } 228 return l.DelItem(f, index) 229 } 230 231 func listRemove(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 232 if raised := checkMethodArgs(f, "remove", args, ListType, ObjectType); raised != nil { 233 return nil, raised 234 } 235 value := args[1] 236 l := toListUnsafe(args[0]) 237 l.mutex.Lock() 238 index, raised := seqFindElem(f, l.elems, value) 239 if raised == nil { 240 if index != -1 { 241 l.elems = append(l.elems[:index], l.elems[index+1:]...) 242 } else { 243 raised = f.RaiseType(ValueErrorType, "list.remove(x): x not in list") 244 } 245 } 246 l.mutex.Unlock() 247 if raised != nil { 248 return nil, raised 249 } 250 return None, nil 251 } 252 253 func listExtend(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 254 argc := len(args) 255 if argc != 2 { 256 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("extend() takes exactly one argument (%d given)", argc)) 257 } 258 return listIAdd(f, args[0], args[1]) 259 } 260 261 func listContains(f *Frame, l, v *Object) (*Object, *BaseException) { 262 return seqContains(f, l, v) 263 } 264 265 func listEq(f *Frame, v, w *Object) (*Object, *BaseException) { 266 return listCompare(f, toListUnsafe(v), w, Eq) 267 } 268 269 func listGE(f *Frame, v, w *Object) (*Object, *BaseException) { 270 return listCompare(f, toListUnsafe(v), w, GE) 271 } 272 273 func listGetItem(f *Frame, o, key *Object) (*Object, *BaseException) { 274 l := toListUnsafe(o) 275 if key.typ.slots.Index == nil && !key.isInstance(SliceType) { 276 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("list indices must be integers, not %s", key.typ.Name())) 277 } 278 l.mutex.RLock() 279 item, elems, raised := seqGetItem(f, l.elems, key) 280 l.mutex.RUnlock() 281 if raised != nil { 282 return nil, raised 283 } 284 if item != nil { 285 return item, nil 286 } 287 return NewList(elems...).ToObject(), nil 288 } 289 290 func listGT(f *Frame, v, w *Object) (*Object, *BaseException) { 291 return listCompare(f, toListUnsafe(v), w, GT) 292 } 293 294 func listIAdd(f *Frame, v, w *Object) (*Object, *BaseException) { 295 l := toListUnsafe(v) 296 raised := seqForEach(f, w, func(o *Object) *BaseException { 297 l.Append(o) 298 return nil 299 }) 300 if raised != nil { 301 return nil, raised 302 } 303 return v, nil 304 } 305 306 func listIMul(f *Frame, v, w *Object) (*Object, *BaseException) { 307 if !w.isInstance(IntType) { 308 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("can't multiply sequence by non-int of type '%s'", w.typ.Name())) 309 } 310 l, n := toListUnsafe(v), toIntUnsafe(w).Value() 311 l.mutex.Lock() 312 elems, raised := seqMul(f, l.elems, n) 313 if raised == nil { 314 l.elems = elems 315 } 316 l.mutex.Unlock() 317 if raised != nil { 318 return nil, raised 319 } 320 return v, nil 321 } 322 323 func listInsert(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 324 if raised := checkMethodArgs(f, "insert", args, ListType, IntType, ObjectType); raised != nil { 325 return nil, raised 326 } 327 l := toListUnsafe(args[0]) 328 l.mutex.Lock() 329 elems := l.elems 330 numElems := len(elems) 331 i := seqClampIndex(toIntUnsafe(args[1]).Value(), numElems) 332 l.resize(numElems + 1) 333 // TODO: The resize() above may have done a copy so we're doing a lot 334 // of extra work here. Optimize this. 335 copy(l.elems[i+1:], elems[i:]) 336 l.elems[i] = args[2] 337 l.mutex.Unlock() 338 return None, nil 339 } 340 341 func listIter(f *Frame, o *Object) (*Object, *BaseException) { 342 return newListIterator(toListUnsafe(o)), nil 343 } 344 345 func listLE(f *Frame, v, w *Object) (*Object, *BaseException) { 346 return listCompare(f, toListUnsafe(v), w, LE) 347 } 348 349 func listLen(f *Frame, o *Object) (*Object, *BaseException) { 350 l := toListUnsafe(o) 351 l.mutex.RLock() 352 ret := NewInt(len(l.elems)).ToObject() 353 l.mutex.RUnlock() 354 return ret, nil 355 } 356 357 func listNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) { 358 elems, raised := seqNew(f, args) 359 if raised != nil { 360 return nil, raised 361 } 362 l := toListUnsafe(newObject(t)) 363 l.elems = elems 364 return l.ToObject(), nil 365 } 366 367 func listLT(f *Frame, v, w *Object) (*Object, *BaseException) { 368 return listCompare(f, toListUnsafe(v), w, LT) 369 } 370 371 func listMul(f *Frame, v, w *Object) (*Object, *BaseException) { 372 if !w.isInstance(IntType) { 373 return NotImplemented, nil 374 } 375 l, n := toListUnsafe(v), toIntUnsafe(w).Value() 376 l.mutex.RLock() 377 elems, raised := seqMul(f, l.elems, n) 378 l.mutex.RUnlock() 379 if raised != nil { 380 return nil, raised 381 } 382 return NewList(elems...).ToObject(), nil 383 } 384 385 func listNE(f *Frame, v, w *Object) (*Object, *BaseException) { 386 return listCompare(f, toListUnsafe(v), w, NE) 387 } 388 389 func listIndex(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 390 expectedTypes := []*Type{ListType, ObjectType, ObjectType, ObjectType} 391 argc := len(args) 392 var raised *BaseException 393 if argc == 2 || argc == 3 { 394 expectedTypes = expectedTypes[:argc] 395 } 396 if raised = checkMethodArgs(f, "index", args, expectedTypes...); raised != nil { 397 return nil, raised 398 } 399 l := toListUnsafe(args[0]) 400 l.mutex.RLock() 401 numElems := len(l.elems) 402 start, stop := 0, numElems 403 if argc > 2 { 404 start, raised = IndexInt(f, args[2]) 405 if raised != nil { 406 l.mutex.RUnlock() 407 return nil, raised 408 } 409 } 410 if argc > 3 { 411 stop, raised = IndexInt(f, args[3]) 412 if raised != nil { 413 l.mutex.RUnlock() 414 return nil, raised 415 } 416 } 417 start, stop = adjustIndex(start, stop, numElems) 418 value := args[1] 419 index := -1 420 if start < numElems && start < stop { 421 index, raised = seqFindElem(f, l.elems[start:stop], value) 422 } 423 l.mutex.RUnlock() 424 if raised != nil { 425 return nil, raised 426 } 427 if index == -1 { 428 return nil, f.RaiseType(ValueErrorType, fmt.Sprintf("%v is not in list", value)) 429 } 430 return NewInt(index + start).ToObject(), nil 431 } 432 433 func listPop(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 434 argc := len(args) 435 expectedTypes := []*Type{ListType, ObjectType} 436 if argc == 1 { 437 expectedTypes = expectedTypes[:1] 438 } 439 if raised := checkMethodArgs(f, "pop", args, expectedTypes...); raised != nil { 440 return nil, raised 441 } 442 i := -1 443 if argc == 2 { 444 var raised *BaseException 445 i, raised = ToIntValue(f, args[1]) 446 if raised != nil { 447 return nil, raised 448 } 449 } 450 l := toListUnsafe(args[0]) 451 l.mutex.Lock() 452 numElems := len(l.elems) 453 if i < 0 { 454 i += numElems 455 } 456 var item *Object 457 var raised *BaseException 458 if i >= numElems || i < 0 { 459 raised = f.RaiseType(IndexErrorType, "list index out of range") 460 } else { 461 item = l.elems[i] 462 l.elems = append(l.elems[:i], l.elems[i+1:]...) 463 } 464 l.mutex.Unlock() 465 return item, raised 466 } 467 468 func listRepr(f *Frame, o *Object) (*Object, *BaseException) { 469 l := toListUnsafe(o) 470 if f.reprEnter(l.ToObject()) { 471 return NewStr("[...]").ToObject(), nil 472 } 473 l.mutex.RLock() 474 repr, raised := seqRepr(f, l.elems) 475 l.mutex.RUnlock() 476 f.reprLeave(l.ToObject()) 477 if raised != nil { 478 return nil, raised 479 } 480 return NewStr(fmt.Sprintf("[%s]", repr)).ToObject(), nil 481 } 482 483 func listReverse(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 484 if raised := checkMethodArgs(f, "reverse", args, ListType); raised != nil { 485 return nil, raised 486 } 487 l := toListUnsafe(args[0]) 488 l.mutex.Lock() 489 halfLen := len(l.elems) / 2 490 for i := 0; i < halfLen; i++ { 491 j := len(l.elems) - i - 1 492 l.elems[i], l.elems[j] = l.elems[j], l.elems[i] 493 } 494 l.mutex.Unlock() 495 return None, nil 496 } 497 498 func listSetItem(f *Frame, o, key, value *Object) *BaseException { 499 l := toListUnsafe(o) 500 if key.typ.slots.Index != nil { 501 i, raised := IndexInt(f, key) 502 if raised != nil { 503 return raised 504 } 505 return l.SetItem(f, i, value) 506 } 507 if key.isInstance(SliceType) { 508 return l.SetSlice(f, toSliceUnsafe(key), value) 509 } 510 return f.RaiseType(TypeErrorType, fmt.Sprintf("list indices must be integers, not %s", key.Type().Name())) 511 } 512 513 func listSort(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 514 // TODO: Support (cmp=None, key=None, reverse=False) 515 if raised := checkMethodArgs(f, "sort", args, ListType); raised != nil { 516 return nil, raised 517 } 518 l := toListUnsafe(args[0]) 519 l.Sort(f) 520 return None, nil 521 } 522 523 func initListType(dict map[string]*Object) { 524 dict["append"] = newBuiltinFunction("append", listAppend).ToObject() 525 dict["count"] = newBuiltinFunction("count", listCount).ToObject() 526 dict["extend"] = newBuiltinFunction("extend", listExtend).ToObject() 527 dict["index"] = newBuiltinFunction("index", listIndex).ToObject() 528 dict["insert"] = newBuiltinFunction("insert", listInsert).ToObject() 529 dict["pop"] = newBuiltinFunction("pop", listPop).ToObject() 530 dict["remove"] = newBuiltinFunction("remove", listRemove).ToObject() 531 dict["reverse"] = newBuiltinFunction("reverse", listReverse).ToObject() 532 dict["sort"] = newBuiltinFunction("sort", listSort).ToObject() 533 ListType.slots.Add = &binaryOpSlot{listAdd} 534 ListType.slots.Contains = &binaryOpSlot{listContains} 535 ListType.slots.DelItem = &delItemSlot{listDelItem} 536 ListType.slots.Eq = &binaryOpSlot{listEq} 537 ListType.slots.GE = &binaryOpSlot{listGE} 538 ListType.slots.GetItem = &binaryOpSlot{listGetItem} 539 ListType.slots.GT = &binaryOpSlot{listGT} 540 ListType.slots.Hash = &unaryOpSlot{hashNotImplemented} 541 ListType.slots.IAdd = &binaryOpSlot{listIAdd} 542 ListType.slots.IMul = &binaryOpSlot{listIMul} 543 ListType.slots.Iter = &unaryOpSlot{listIter} 544 ListType.slots.LE = &binaryOpSlot{listLE} 545 ListType.slots.Len = &unaryOpSlot{listLen} 546 ListType.slots.LT = &binaryOpSlot{listLT} 547 ListType.slots.Mul = &binaryOpSlot{listMul} 548 ListType.slots.NE = &binaryOpSlot{listNE} 549 ListType.slots.New = &newSlot{listNew} 550 ListType.slots.Repr = &unaryOpSlot{listRepr} 551 ListType.slots.RMul = &binaryOpSlot{listMul} 552 ListType.slots.SetItem = &setItemSlot{listSetItem} 553 } 554 555 type listIterator struct { 556 Object 557 list *List 558 mutex sync.Mutex 559 index int 560 } 561 562 func newListIterator(l *List) *Object { 563 iter := &listIterator{Object: Object{typ: listIteratorType}, list: l} 564 return &iter.Object 565 } 566 567 func toListIteratorUnsafe(o *Object) *listIterator { 568 return (*listIterator)(o.toPointer()) 569 } 570 571 var listIteratorType = newBasisType("listiterator", reflect.TypeOf(listIterator{}), toListIteratorUnsafe, ObjectType) 572 573 func listIteratorIter(f *Frame, o *Object) (*Object, *BaseException) { 574 return o, nil 575 } 576 577 func listIteratorNext(f *Frame, o *Object) (ret *Object, raised *BaseException) { 578 i := toListIteratorUnsafe(o) 579 // Ensure that no mutations happen to the list. 580 i.list.mutex.RLock() 581 i.mutex.Lock() 582 if i.index < len(i.list.elems) { 583 ret = i.list.elems[i.index] 584 i.index++ 585 } else { 586 // Ensure that we raise StopIteration henceforth even if the 587 // sequence grows subsequently. 588 i.index = MaxInt 589 raised = f.Raise(StopIterationType.ToObject(), nil, nil) 590 } 591 i.mutex.Unlock() 592 i.list.mutex.RUnlock() 593 return ret, raised 594 } 595 596 func initListIteratorType(map[string]*Object) { 597 listIteratorType.flags &= ^(typeFlagBasetype | typeFlagInstantiable) 598 listIteratorType.slots.Iter = &unaryOpSlot{listIteratorIter} 599 listIteratorType.slots.Next = &unaryOpSlot{listIteratorNext} 600 } 601 602 func listCompare(f *Frame, v *List, w *Object, cmp binaryOpFunc) (*Object, *BaseException) { 603 if !w.isInstance(ListType) { 604 return NotImplemented, nil 605 } 606 listw := toListUnsafe(w) 607 // Order of locking doesn't matter since we're doing a read lock. 608 v.mutex.RLock() 609 listw.mutex.RLock() 610 ret, raised := seqCompare(f, v.elems, listw.elems, cmp) 611 listw.mutex.RUnlock() 612 v.mutex.RUnlock() 613 return ret, raised 614 } 615 616 type listSorter struct { 617 f *Frame 618 l *List 619 raised *BaseException 620 } 621 622 func (s *listSorter) Len() int { 623 return len(s.l.elems) 624 } 625 626 func (s *listSorter) Less(i, j int) bool { 627 lt, raised := LT(s.f, s.l.elems[i], s.l.elems[j]) 628 if raised != nil { 629 s.raised = raised 630 panic(s) 631 } 632 ret, raised := IsTrue(s.f, lt) 633 if raised != nil { 634 s.raised = raised 635 panic(s) 636 } 637 return ret 638 } 639 640 func (s *listSorter) Swap(i, j int) { 641 s.l.elems[i], s.l.elems[j] = s.l.elems[j], s.l.elems[i] 642 }