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  }