1use super::{
2 PositionIterInternal, PyGenericAlias, PyTupleRef, PyType, PyTypeRef,
3 iter::{builtins_iter, builtins_reversed},
4 locked_next, locked_rev_next,
5};
6use crate::atomic_func;
7use crate::common::lock::{
8 PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
9};
10use crate::object::{Traverse, TraverseFn};
11use crate::{
12 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
13 builtins::{PyFloat, PyInt, PyStr, PyTuple},
14 class::{PyClassDef, PyClassImpl},
15 convert::ToPyObject,
16 function::{Either, FuncArgs, OptionalArg, PyComparisonValue, PySsize},
17 protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
18 recursion::ReprGuard,
19 sequence::{MutObjectSequenceOp, OptionalRangeArgs, SequenceExt, SequenceMutExt},
20 sliceable::{SaturatedSlice, SequenceIndex, SliceableSequenceOp},
21 sorting::timsort,
22 types::{
23 AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable,
24 PyComparisonOp, Representable, RichCompareFunc, SelfIter,
25 },
26 vm::VirtualMachine,
27};
28use rustpython_common::wtf8::Wtf8Buf;
29
30use alloc::fmt;
31use core::cell::Cell;
32use core::ops::DerefMut;
33use core::ptr::NonNull;
34use core::sync::atomic::{AtomicU32, Ordering};
35
36#[pyclass(module = false, name = "list", unhashable = true, traverse = "manual")]
37#[derive(Default)]
38pub struct PyList {
39 elements: PyRwLock<Vec<PyObjectRef>>,
40 mutation_counter: AtomicU32,
41}
42
43impl fmt::Debug for PyList {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.write_str("list")
47 }
48}
49
50impl From<Vec<PyObjectRef>> for PyList {
51 fn from(elements: Vec<PyObjectRef>) -> Self {
52 Self {
53 elements: PyRwLock::new(elements),
54 mutation_counter: AtomicU32::new(0),
55 }
56 }
57}
58
59impl FromIterator<PyObjectRef> for PyList {
60 fn from_iter<T: IntoIterator<Item = PyObjectRef>>(iter: T) -> Self {
61 Vec::from_iter(iter).into()
62 }
63}
64
65unsafe impl Traverse for PyList {
67 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
68 self.elements.traverse(traverse_fn);
69 }
70
71 fn clear(&mut self, out: &mut Vec<PyObjectRef>) {
72 if let Some(mut guard) = self.elements.try_write() {
76 if out.is_empty() {
77 *out = core::mem::take(&mut *guard);
79 } else {
80 out.extend(guard.drain(..));
81 }
82 }
83 }
84}
85
86thread_local! {
87 static LIST_FREELIST: Cell<crate::object::FreeList<PyList>> = const { Cell::new(crate::object::FreeList::new()) };
88}
89
90impl PyPayload for PyList {
91 const MAX_FREELIST: usize = 80;
92 const HAS_FREELIST: bool = true;
93
94 #[inline]
95 fn class(ctx: &Context) -> &'static Py<PyType> {
96 ctx.types.list_type
97 }
98
99 #[inline]
100 unsafe fn freelist_push(obj: *mut PyObject) -> bool {
101 LIST_FREELIST
102 .try_with(|fl| {
103 let mut list = fl.take();
104 let stored = if list.len() < Self::MAX_FREELIST {
105 list.push(obj);
106 true
107 } else {
108 false
109 };
110 fl.set(list);
111 stored
112 })
113 .unwrap_or(false)
114 }
115
116 #[inline]
117 unsafe fn freelist_pop(_payload: &Self) -> Option<NonNull<PyObject>> {
118 LIST_FREELIST
119 .try_with(|fl| {
120 let mut list = fl.take();
121 let result = list.pop().map(|p| unsafe { NonNull::new_unchecked(p) });
122 fl.set(list);
123 result
124 })
125 .ok()
126 .flatten()
127 }
128}
129
130impl ToPyObject for Vec<PyObjectRef> {
131 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
132 PyList::from(self).into_ref(&vm.ctx).into()
133 }
134}
135
136impl Py<PyList> {
137 #[inline]
138 pub fn borrow_vec(&self) -> PyMappedRwLockReadGuard<'_, [PyObjectRef]> {
139 self.payload().borrow_vec()
140 }
141
142 #[inline]
143 pub fn borrow_vec_mut(&self) -> PyRwLockWriteGuard<'_, Vec<PyObjectRef>> {
144 self.payload().borrow_vec_mut()
145 }
146}
147
148impl PyList {
149 #[deprecated(note = "use PyList::from(...).into_ref() instead")]
150 pub fn new_ref(elements: Vec<PyObjectRef>, ctx: &Context) -> PyRef<Self> {
151 Self::from(elements).into_ref(ctx)
152 }
153
154 pub fn borrow_vec(&self) -> PyMappedRwLockReadGuard<'_, [PyObjectRef]> {
155 PyRwLockReadGuard::map(self.elements.read(), |v| &**v)
156 }
157
158 pub fn borrow_vec_mut(&self) -> PyRwLockWriteGuard<'_, Vec<PyObjectRef>> {
159 let guard = self.elements.write();
160 self.mutation_counter.fetch_add(1, Ordering::Relaxed);
161 guard
162 }
163
164 fn repeat(&self, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
165 let elements = &*self.borrow_vec();
166 let v = elements.mul(vm, n)?;
167 Ok(Self::from(v).into_ref(&vm.ctx))
168 }
169
170 fn irepeat(zelf: PyRef<Self>, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
171 if n <= 0 {
172 Py::<Self>::clear(&zelf);
173 } else {
174 zelf.borrow_vec_mut().imul(vm, n)?;
175 }
176 Ok(zelf)
177 }
178}
179
180#[derive(FromArgs, Default, Traverse)]
181pub(crate) struct SortOptions {
182 #[pyarg(named, optional)]
183 key: Option<PyObjectRef>,
184 #[pytraverse(skip)]
185 #[pyarg(named, default)]
186 reverse: bool,
187}
188
189pub type PyListRef = PyRef<PyList>;
190
191#[derive(FromArgs)]
192struct PopArgs {
193 #[pyarg(positional, default = -1)]
194 index: isize,
195}
196
197impl PyList {
198 pub(crate) fn append(&self, object: PyObjectRef) {
199 self.borrow_vec_mut().push(object);
200 }
201
202 pub(crate) fn sort(&self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
203 let (mut elements, version_before) = {
207 let mut guard = self.elements.write();
208 let version_before = self.mutation_counter.load(Ordering::Relaxed);
209 (core::mem::take(&mut *guard), version_before)
210 };
211 let res = do_sort(vm, &mut elements, options.key.as_deref(), options.reverse);
212 let mutated = {
213 let mut guard = self.elements.write();
214 let mutated = self.mutation_counter.load(Ordering::Relaxed) != version_before;
215 core::mem::swap(&mut *guard, &mut elements);
216 mutated
217 };
218 res?;
219
220 if mutated {
221 return Err(vm.new_value_error("list modified during sort"));
222 }
223
224 Ok(())
225 }
226
227 fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
228 let other = other.downcast_ref::<Self>().ok_or_else(|| {
229 vm.new_type_error(format!(
230 "Cannot add {} and {}",
231 Self::class(&vm.ctx).name(),
232 other.class().name()
233 ))
234 })?;
235 let mut elements = self.borrow_vec().to_vec();
236 elements.extend(other.borrow_vec().iter().cloned());
237 Ok(Self::from(elements).into_ref(&vm.ctx))
238 }
239
240 fn __add__(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
241 self.concat(other, vm)
242 }
243
244 fn inplace_concat(
245 zelf: &Py<Self>,
246 other: &PyObject,
247 vm: &VirtualMachine,
248 ) -> PyResult<PyObjectRef> {
249 zelf.extend(other.to_owned(), vm)?;
250 Ok(zelf.to_owned().into())
251 }
252
253 fn __iadd__(
254 zelf: PyRef<Self>,
255 other: PyObjectRef,
256 vm: &VirtualMachine,
257 ) -> PyResult<PyRef<Self>> {
258 zelf.extend(other, vm)?;
259 Ok(zelf)
260 }
261
262 pub fn __len__(&self) -> usize {
263 self.borrow_vec().len()
264 }
265
266 fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
267 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
268 SequenceIndex::Int(i) => {
269 let vec = self.borrow_vec();
270 let pos = vec
271 .wrap_index(i)
272 .ok_or_else(|| vm.new_index_error("list index out of range"))?;
273 Ok(vec.do_get(pos))
274 }
275 SequenceIndex::Slice(slice) => self
276 .borrow_vec()
277 .getitem_by_slice(vm, slice)
278 .map(|x| vm.ctx.new_list(x).into()),
279 }
280 }
281
282 fn assign_item(
283 &self,
284 index: isize,
285 value: Option<PyObjectRef>,
286 vm: &VirtualMachine,
287 ) -> PyResult<()> {
288 let removed = {
289 let mut elements = self.borrow_vec_mut();
290 let index = elements
291 .wrap_index(index)
292 .ok_or_else(|| vm.new_index_error("list assignment index out of range"))?;
293 if let Some(value) = value {
294 core::mem::replace(&mut elements[index], value)
295 } else {
296 elements.remove(index)
297 }
298 };
299 drop(removed);
300 Ok(())
301 }
302
303 fn assign_slice(
304 &self,
305 slice: SaturatedSlice,
306 items: Option<&[PyObjectRef]>,
307 vm: &VirtualMachine,
308 ) -> PyResult<()> {
309 let removed = {
310 let mut elements = self.borrow_vec_mut();
311 let (range, step, slice_len) = slice.adjust_indices(elements.len());
312 if step != 1
313 && let Some(items) = &items
314 && items.len() != slice_len
315 {
316 return Err(vm.new_value_error(format!(
317 "attempt to assign sequence of size {} to extended slice of size {}",
318 items.len(),
319 slice_len
320 )));
321 }
322 let new_len = items.map_or(0, <[PyObjectRef]>::len);
323 if step == 1 && slice_len == elements.len() && new_len == 0 {
324 core::mem::take(&mut *elements)
325 } else {
326 let mut removed = Vec::new();
329 removed
330 .try_reserve_exact(slice_len)
331 .map_err(|_| vm.no_memory_error())?;
332 if step == 1 {
333 elements
334 .try_reserve(new_len.saturating_sub(slice_len))
335 .map_err(|_| vm.no_memory_error())?;
336 removed
337 .extend(elements.splice(range, items.unwrap_or_default().iter().cloned()));
338 } else if let Some(items) = items {
339 for (index, item) in slice.iter(elements.len()).zip(items) {
340 removed.push(core::mem::replace(&mut elements[index], item.clone()));
341 }
342 } else {
343 let mut indexes = slice.iter(elements.len()).positive_order().peekable();
344 let mut index = range.start;
345 removed.extend(elements.extract_if(range, |_| {
346 let remove = indexes.peek() == Some(&index);
347 if remove {
348 indexes.next();
349 }
350 index += 1;
351 remove
352 }));
353 }
354 removed
355 }
356 };
357 if slice.step() == 1 {
358 removed.into_iter().rev().for_each(drop);
359 } else {
360 drop(removed);
361 }
362 Ok(())
363 }
364
365 fn _setitem(&self, needle: &PyObject, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
366 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
367 SequenceIndex::Int(index) => self.assign_item(index, Some(value), vm),
368 SequenceIndex::Slice(slice) => {
369 let items = extract_cloned(&value, self, vm)?;
370 let result = self.assign_slice(slice, Some(&items), vm);
371 items.into_iter().rev().for_each(drop);
372 result
373 }
374 }
375 }
376
377 fn __setitem__(
378 &self,
379 needle: &PyObject,
380 value: PyObjectRef,
381 vm: &VirtualMachine,
382 ) -> PyResult<()> {
383 self._setitem(needle, value, vm)
384 }
385
386 fn __mul__(&self, n: PySsize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
387 self.repeat(n, vm)
388 }
389
390 fn __imul__(zelf: PyRef<Self>, n: PySsize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
391 Self::irepeat(zelf, n, vm)
392 }
393
394 pub(crate) fn __contains__(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
395 self.mut_contains(vm, needle)
396 }
397
398 fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
399 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
400 SequenceIndex::Int(i) => self.assign_item(i, None, vm),
401 SequenceIndex::Slice(slice) => self.assign_slice(slice, None, vm),
402 }
403 }
404
405 fn __delitem__(&self, subscript: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
406 self._delitem(subscript, vm)
407 }
408}
409
410#[pyclass(
411 with(
412 Constructor,
413 Initializer,
414 AsMapping,
415 Iterable,
416 Comparable,
417 AsSequence,
418 Representable
419 ),
420 flags(BASETYPE, SEQUENCE, _MATCH_SELF)
421)]
422impl Py<PyList> {
423 #[pymethod]
424 pub(crate) fn append(&self, object: PyObjectRef) {
425 self.payload.append(object)
426 }
427
428 #[pymethod]
429 pub(crate) fn extend(&self, iterable: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
430 if let Some(list) = iterable.downcast_ref::<PyList>()
431 && core::ptr::eq(self, list)
432 {
433 return self.borrow_vec_mut().imul(vm, 2);
434 }
435 if let Some(tuple) = iterable.downcast_ref_if_exact::<PyTuple>(vm) {
436 let mut elements = self.borrow_vec_mut();
437 elements
438 .try_reserve(tuple.len())
439 .map_err(|_| vm.no_memory_error())?;
440 elements.extend_from_slice(tuple.as_slice());
441 return Ok(());
442 }
443 let cls = iterable.class();
444 if cls.is(vm.ctx.types.list_type)
445 || cls.is(vm.ctx.types.set_type)
446 || cls.is(vm.ctx.types.frozenset_type)
447 || cls.is(vm.ctx.types.dict_type)
448 || cls.is(vm.ctx.types.dict_keys_type)
449 || cls.is(vm.ctx.types.dict_values_type)
450 || cls.is(vm.ctx.types.dict_items_type)
451 {
452 let mut new_elements =
454 vm.extract_elements_sized(&iterable, &|| self.borrow_vec().len(), Ok)?;
455 let mut elements = self.borrow_vec_mut();
456 elements
457 .try_reserve(new_elements.len())
458 .map_err(|_| vm.no_memory_error())?;
459 elements.append(&mut new_elements);
460 return Ok(());
461 }
462
463 let iter = iterable.clone().get_iter(vm)?;
464 let hint = vm.length_hint_opt(iterable.clone())?.unwrap_or(8);
466 {
467 let mut elements = self.borrow_vec_mut();
468 if elements.len() <= (isize::MAX as usize) - hint {
469 elements
470 .try_reserve_exact(hint)
471 .map_err(|_| vm.no_memory_error())?;
472 }
473 }
474 for item in iter.iter::<PyObjectRef>(vm)? {
475 let item = item?;
476 let mut elements = self.borrow_vec_mut();
477 if elements.len() == elements.capacity() {
478 elements.try_reserve(1).map_err(|_| vm.no_memory_error())?;
479 }
480 elements.push(item);
481 }
482 {
483 let mut elements = self.elements.write();
486 if elements.len() < elements.capacity().div_ceil(2) {
487 elements.shrink_to_fit();
488 }
489 }
490 Ok(())
491 }
492
493 #[pymethod]
494 pub(crate) fn insert(&self, index: PySsize, object: PyObjectRef) {
495 let mut elements = self.borrow_vec_mut();
496 let index = elements.saturate_index(index);
497 elements.insert(index, object);
498 }
499
500 #[pymethod]
501 fn clear(&self) {
502 let removed = core::mem::take(self.borrow_vec_mut().deref_mut());
503 removed.into_iter().rev().for_each(drop);
504 }
505
506 #[pymethod]
507 fn copy(&self, vm: &VirtualMachine) -> PyRef<PyList> {
508 PyList::from(self.borrow_vec().to_vec()).into_ref(&vm.ctx)
509 }
510
511 #[pymethod]
512 fn __sizeof__(&self) -> usize {
513 core::mem::size_of::<PyList>()
514 + self.elements.read().capacity() * core::mem::size_of::<PyObjectRef>()
515 }
516
517 #[pymethod]
518 fn reverse(&self) {
519 self.borrow_vec_mut().reverse();
520 }
521
522 #[pymethod]
523 fn __reversed__(zelf: PyRef<PyList>) -> PyListReverseIterator {
524 let position = zelf.__len__().saturating_sub(1);
525 PyListReverseIterator {
526 internal: PyMutex::new(PositionIterInternal::new(zelf, position)),
527 }
528 }
529
530 #[pymethod(coexist)]
531 fn __getitem__(&self, index: PyObjectRef, vm: &VirtualMachine) -> PyResult {
532 self._getitem(&index, vm)
533 }
534
535 #[pymethod]
536 fn count(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
537 self.mut_count(vm, &value)
538 }
539
540 #[pymethod]
541 fn index(
542 &self,
543 value: PyObjectRef,
544 range: OptionalRangeArgs,
545 vm: &VirtualMachine,
546 ) -> PyResult<usize> {
547 let (start, stop) = range.saturate(self.__len__(), vm)?;
548 let index = self.mut_index_range(vm, &value, start..stop)?;
549 if let Some(index) = index.into() {
550 Ok(index)
551 } else {
552 Err(vm.new_value_error(format!("'{}' is not in list", value.str(vm)?)))
553 }
554 }
555
556 #[pymethod]
557 fn pop(&self, args: PopArgs, vm: &VirtualMachine) -> PyResult {
558 let mut index = args.index;
559 let mut elements = self.borrow_vec_mut();
560 if index < 0 {
561 index += elements.len() as isize;
562 }
563 if elements.is_empty() {
564 Err(vm.new_index_error("pop from empty list"))
565 } else if index < 0 || index as usize >= elements.len() {
566 Err(vm.new_index_error("pop index out of range"))
567 } else {
568 Ok(elements.remove(index as usize))
569 }
570 }
571
572 #[pymethod]
573 fn remove(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
574 let index = self.mut_index(vm, &value)?;
575
576 if let Some(index) = index.into() {
577 let removed = {
579 let mut elements = self.borrow_vec_mut();
580 (index < elements.len()).then(|| elements.remove(index))
581 };
582 drop(removed);
583 Ok(())
584 } else {
585 Err(vm.new_value_error(format!("'{}' is not in list", value.str(vm)?)))
586 }
587 }
588
589 #[pymethod]
590 pub(crate) fn sort(&self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
591 self.payload.sort(options, vm)
592 }
593
594 #[pyclassmethod]
595 fn __class_getitem__(
596 cls: PyTypeRef,
597 object: PyObjectRef,
598 vm: &VirtualMachine,
599 ) -> PyResult<PyGenericAlias> {
600 PyGenericAlias::from_args(cls, object, vm)
601 }
602}
603
604fn extract_cloned(
605 obj: &PyObject,
606 zelf: &PyList,
607 vm: &VirtualMachine,
608) -> PyResult<Vec<PyObjectRef>> {
609 use crate::builtins::PyTuple;
610 let mut v = Vec::new();
611 if let Some(tuple) = obj.downcast_ref_if_exact::<PyTuple>(vm) {
612 v.try_reserve_exact(tuple.len())
613 .map_err(|_| vm.no_memory_error())?;
614 v.extend_from_slice(tuple.as_slice());
615 } else if let Some(list) = obj.downcast_ref::<PyList>()
616 && (obj.class().is(vm.ctx.types.list_type) || core::ptr::eq(zelf, list.payload()))
617 {
618 let elements = list.borrow_vec();
619 v.try_reserve_exact(elements.len())
620 .map_err(|_| vm.no_memory_error())?;
621 v.extend_from_slice(&elements);
622 } else {
623 let iter = obj
624 .to_owned()
625 .get_iter(vm)?
626 .into_iter_sized::<PyObjectRef>(vm)?;
627 let len = iter.size_hint().0;
628 v.try_reserve_exact(len).map_err(|_| vm.no_memory_error())?;
629 let result = (|| {
630 for x in iter {
631 let item = x?;
632 if v.len() == v.capacity() {
633 v.try_reserve(1).map_err(|_| vm.no_memory_error())?;
634 }
635 v.push(item);
636 }
637 Ok(())
638 })();
639 if let Err(error) = result {
640 v.into_iter().rev().for_each(drop);
641 return Err(error);
642 }
643 }
644 Ok(v)
645}
646
647impl MutObjectSequenceOp for PyList {
648 type Inner = [PyObjectRef];
649
650 fn do_get(index: usize, inner: &[PyObjectRef]) -> Option<&PyObject> {
651 inner.get(index).map(|r| r.as_ref())
652 }
653
654 fn do_lock(&self) -> impl core::ops::Deref<Target = [PyObjectRef]> {
655 self.borrow_vec()
656 }
657}
658
659impl Constructor for PyList {
660 type Args = FuncArgs;
661
662 fn py_new(_cls: &Py<PyType>, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<Self> {
663 Ok(Self::default())
664 }
665}
666
667impl Initializer for PyList {
668 type Args = crate::function::PositionalIterable;
669
670 fn slot_init(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
671 let list_type = vm.ctx.types.list_type;
672 let cls = zelf.class();
673 let uses_list_new = {
674 let cls_new = cls.slots.new.load().map(crate::types::fn_addr);
675 let list_new = list_type.slots.new.load().map(crate::types::fn_addr);
676 cls_new == list_new
677 };
678 let iterable = if cls.is(list_type) || uses_list_new {
679 args.bind_for(vm, Self::NAME)?
680 } else {
681 match args.args.as_slice() {
682 [] => Self::Args {
683 iterable: OptionalArg::Missing,
684 },
685 [iterable] => Self::Args {
686 iterable: OptionalArg::Present(iterable.clone()),
687 },
688 slice => {
689 return Err(vm.new_arity_type_error(Self::NAME, 0..=1, slice.len()));
690 }
691 }
692 };
693 Self::init(zelf.try_to_ref(vm)?, iterable, vm)
694 }
695
696 fn init(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
697 zelf.clear();
698 if let OptionalArg::Present(iterable) = args.iterable {
699 zelf.extend(iterable, vm)?;
700 }
701 Ok(())
702 }
703}
704
705impl AsMapping for PyList {
706 fn as_mapping() -> &'static PyMappingMethods {
707 static AS_MAPPING: PyMappingMethods = PyMappingMethods {
708 length: atomic_func!(|mapping, _vm| Ok(PyList::mapping_downcast(mapping).__len__())),
709 subscript: atomic_func!(
710 |mapping, needle, vm| PyList::mapping_downcast(mapping)._getitem(needle, vm)
711 ),
712 ass_subscript: atomic_func!(|mapping, needle, value, vm| {
713 let zelf = PyList::mapping_downcast(mapping);
714 if let Some(value) = value {
715 zelf._setitem(needle, value, vm)
716 } else {
717 zelf._delitem(needle, vm)
718 }
719 }),
720 };
721 &AS_MAPPING
722 }
723}
724
725impl AsSequence for PyList {
726 fn as_sequence() -> &'static PySequenceMethods {
727 static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
728 length: atomic_func!(|seq, _vm| Ok(PyList::sequence_downcast(seq).__len__())),
729 concat: atomic_func!(|seq, other, vm| {
730 PyList::sequence_downcast(seq)
731 .concat(other, vm)
732 .map(|x| x.into())
733 }),
734 repeat: atomic_func!(|seq, n, vm| {
735 PyList::sequence_downcast(seq)
736 .repeat(n, vm)
737 .map(|x| x.into())
738 }),
739 item: atomic_func!(|seq, i, vm| {
740 let list = PyList::sequence_downcast(seq);
741 let vec = list.borrow_vec();
742 let pos = vec
743 .wrap_index(i)
744 .ok_or_else(|| vm.new_index_error("list index out of range"))?;
745 Ok(vec.do_get(pos))
746 }),
747 ass_item: atomic_func!(|seq, i, value, vm| {
748 PyList::sequence_downcast(seq).assign_item(i, value, vm)
749 }),
750 contains: atomic_func!(|seq, target, vm| {
751 let zelf = PyList::sequence_downcast(seq);
752 zelf.mut_contains(vm, target)
753 }),
754 inplace_concat: atomic_func!(|seq, other, vm| {
755 let zelf = PyList::sequence_downcast(seq);
756 PyList::inplace_concat(zelf, other, vm)
757 }),
758 inplace_repeat: atomic_func!(|seq, n, vm| {
759 let zelf = PyList::sequence_downcast(seq);
760 Ok(PyList::irepeat(zelf.to_owned(), n, vm)?.into())
761 }),
762 };
763 &AS_SEQUENCE
764 }
765}
766
767impl Iterable for PyList {
768 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
769 Ok(PyListIterator {
770 internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
771 }
772 .into_pyobject(vm))
773 }
774}
775
776impl Comparable for PyList {
777 fn cmp(
778 zelf: &Py<Self>,
779 other: &PyObject,
780 op: PyComparisonOp,
781 vm: &VirtualMachine,
782 ) -> PyResult<PyComparisonValue> {
783 if let Some(res) = op.identical_optimization(zelf, other) {
784 return Ok(res.into());
785 }
786 let other = class_or_notimplemented!(Self, other);
787 crate::iter::richcompare_mutating_seqs(
790 |i| {
791 let a = zelf.borrow_vec();
792 (a.len(), a.get(i).cloned())
793 },
794 |i| {
795 let b = other.borrow_vec();
796 (b.len(), b.get(i).cloned())
797 },
798 op,
799 vm,
800 )
801 .map(PyComparisonValue::Implemented)
802 }
803}
804
805impl Representable for PyList {
806 #[inline]
807 fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
808 if zelf.__len__() == 0 {
809 return Ok(vm.ctx.intern_str("[]").to_owned());
810 }
811
812 if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
813 let mut writer = Wtf8Buf::new();
817 writer.push_char('[');
818
819 let mut first = true;
820 let mut i = 0;
821 loop {
822 let item = zelf.borrow_vec().get(i).cloned();
823 let Some(item) = item else {
824 break;
825 };
826
827 if first {
828 first = false;
829 } else {
830 writer.push_str(", ");
831 }
832
833 writer.push_wtf8(item.repr(vm)?.as_wtf8());
834
835 i += 1;
836 }
837
838 writer.push_char(']');
839 Ok(vm.ctx.new_str(writer))
840 } else {
841 Ok(vm.ctx.intern_str("[...]").to_owned())
842 }
843 }
844
845 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
846 unreachable!("repr() is overridden directly")
847 }
848}
849
850enum Elem {
851 Str,
852 Int,
853 Float,
854 Object(RichCompareFunc),
855 Generic,
856}
857
858enum PreSort {
859 Str,
860 Int,
861 Float,
862 Object(RichCompareFunc),
863 Tuple(Elem),
864 Generic,
865}
866
867impl From<Elem> for PreSort {
868 fn from(e: Elem) -> Self {
869 match e {
870 Elem::Str => Self::Str,
871 Elem::Int => Self::Int,
872 Elem::Float => Self::Float,
873 Elem::Object(f) => Self::Object(f),
874 Elem::Generic => Self::Generic,
875 }
876 }
877}
878
879fn classify(class: &Py<PyType>, vm: &VirtualMachine) -> Elem {
880 if class.is(vm.ctx.types.str_type) {
881 Elem::Str
882 } else if class.is(vm.ctx.types.int_type) {
883 Elem::Int
884 } else if class.is(vm.ctx.types.float_type) {
885 Elem::Float
886 } else if let Some(f) = class.slots.richcompare.load() {
887 Elem::Object(f)
888 } else {
889 Elem::Generic
890 }
891}
892
893fn pre_sort_check<'a>(
894 mut keys: impl Iterator<Item = &'a PyObject>,
895 vm: &VirtualMachine,
896) -> PreSort {
897 let Some(first) = keys.next() else {
898 return PreSort::Generic;
899 };
900
901 if let Some(t) = first
902 .downcast_ref_if_exact::<PyTuple>(vm)
903 .filter(|t| !t.as_slice().is_empty())
904 {
905 pre_sort_check_tuples(&t.as_slice()[0], keys, vm)
906 } else {
907 let class = first.class();
908 if keys.all(|k| k.class().is(class)) {
909 classify(class, vm).into()
910 } else {
911 PreSort::Generic
912 }
913 }
914}
915
916fn pre_sort_check_tuples<'a>(
917 first_elem: &PyObject,
918 keys: impl Iterator<Item = &'a PyObject>,
919 vm: &VirtualMachine,
920) -> PreSort {
921 let class = first_elem.class();
922 let mut all_same_type = true;
923
924 for k in keys {
925 let Some(t) = k
926 .downcast_ref_if_exact::<PyTuple>(vm)
927 .filter(|t| !t.as_slice().is_empty())
928 else {
929 return PreSort::Generic;
930 };
931 if all_same_type && !t.as_slice()[0].class().is(class) {
932 all_same_type = false;
933 }
934 }
935
936 let elem = if !all_same_type || class.is(vm.ctx.types.tuple_type) {
937 Elem::Generic
938 } else {
939 classify(class, vm)
940 };
941 PreSort::Tuple(elem)
942}
943
944fn str_lt(a: &PyObject, b: &PyObject) -> bool {
945 a.downcast_ref::<PyStr>().unwrap().as_bytes() < b.downcast_ref::<PyStr>().unwrap().as_bytes()
946}
947
948fn int_lt(a: &PyObject, b: &PyObject) -> bool {
949 a.downcast_ref::<PyInt>().unwrap().as_bigint() < b.downcast_ref::<PyInt>().unwrap().as_bigint()
950}
951
952fn float_lt(a: &PyObject, b: &PyObject) -> bool {
953 a.downcast_ref::<PyFloat>().unwrap().to_f64() < b.downcast_ref::<PyFloat>().unwrap().to_f64()
954}
955
956fn object_lt(
957 cmp: RichCompareFunc,
958 a: &PyObject,
959 b: &PyObject,
960 vm: &VirtualMachine,
961) -> PyResult<bool> {
962 #[allow(unpredictable_function_pointer_comparisons)]
963 if a.class().slots().richcompare.load() != Some(cmp) {
964 return a.rich_compare_bool(b, PyComparisonOp::Lt, vm);
965 }
966 match cmp(a, b, PyComparisonOp::Lt, vm)? {
967 Either::B(PyComparisonValue::Implemented(v)) => Ok(v),
968 Either::B(PyComparisonValue::NotImplemented) => {
969 a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
970 }
971 Either::A(obj) => {
972 if obj.is(&vm.ctx.not_implemented) {
973 a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
974 } else {
975 obj.try_to_bool(vm)
976 }
977 }
978 }
979}
980
981fn elem_lt(elem: &Elem, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
982 match elem {
983 Elem::Str => Ok(str_lt(a, b)),
984 Elem::Int => Ok(int_lt(a, b)),
985 Elem::Float => Ok(float_lt(a, b)),
986 Elem::Object(f) => object_lt(*f, a, b, vm),
987 Elem::Generic => a.rich_compare_bool(b, PyComparisonOp::Lt, vm),
988 }
989}
990
991fn tuple_lt(elem: &Elem, a: &PyObject, b: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
992 let a = a.downcast_ref::<PyTuple>().unwrap().as_slice();
993 let b = b.downcast_ref::<PyTuple>().unwrap().as_slice();
994
995 let mut i = 0;
996 while i < a.len() && i < b.len() {
997 if !a[i].rich_compare_bool(&b[i], PyComparisonOp::Eq, vm)? {
998 break;
999 }
1000 i += 1;
1001 }
1002 if i >= a.len() || i >= b.len() {
1003 return Ok(a.len() < b.len());
1004 }
1005 if i == 0 {
1006 elem_lt(elem, &a[0], &b[0], vm)
1007 } else {
1008 a[i].rich_compare_bool(&b[i], PyComparisonOp::Lt, vm)
1009 }
1010}
1011
1012fn timsort_by<T, K, L>(items: &mut [T], reverse: bool, key: &K, mut lt: L) -> PyResult<()>
1013where
1014 T: Clone,
1015 K: Fn(&T) -> &PyObject,
1016 L: FnMut(&PyObject, &PyObject) -> PyResult<bool>,
1017{
1018 timsort(items, &mut |a, b| {
1019 let (a, b) = if reverse {
1020 (key(b), key(a))
1021 } else {
1022 (key(a), key(b))
1023 };
1024 lt(a, b)
1025 })
1026}
1027
1028fn timsort_specialized<T, K>(
1029 vm: &VirtualMachine,
1030 items: &mut [T],
1031 reverse: bool,
1032 key: K,
1033) -> PyResult<()>
1034where
1035 T: Clone,
1036 K: Fn(&T) -> &PyObject,
1037{
1038 match pre_sort_check(items.iter().map(&key), vm) {
1039 PreSort::Str => timsort_by(items, reverse, &key, |a, b| Ok(str_lt(a, b))),
1040 PreSort::Int => timsort_by(items, reverse, &key, |a, b| Ok(int_lt(a, b))),
1041 PreSort::Float => timsort_by(items, reverse, &key, |a, b| Ok(float_lt(a, b))),
1042 PreSort::Object(cmp) => timsort_by(items, reverse, &key, |a, b| object_lt(cmp, a, b, vm)),
1043 PreSort::Tuple(elem) => timsort_by(items, reverse, &key, |a, b| tuple_lt(&elem, a, b, vm)),
1044 PreSort::Generic => timsort_by(items, reverse, &key, |a, b| {
1045 a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
1046 }),
1047 }
1048}
1049
1050fn do_sort(
1051 vm: &VirtualMachine,
1052 values: &mut Vec<PyObjectRef>,
1053 key_func: Option<&PyObject>,
1054 reverse: bool,
1055) -> PyResult<()> {
1056 if let Some(key_func) = key_func {
1057 let mut items = values
1058 .iter()
1059 .map(|x| Ok((x.clone(), key_func.call((x.clone(),), vm)?)))
1060 .collect::<Result<Vec<_>, _>>()?;
1061 timsort_specialized(
1062 vm,
1063 &mut items,
1064 reverse,
1065 |item: &(PyObjectRef, PyObjectRef)| &*item.1,
1066 )?;
1067 *values = items.into_iter().map(|(val, _)| val).collect();
1068 } else {
1069 timsort_specialized(vm, values, reverse, |x| x)?
1070 }
1071
1072 Ok(())
1073}
1074
1075#[pyclass(module = false, name = "list_iterator", traverse)]
1076#[derive(Debug)]
1077pub(crate) struct PyListIterator {
1078 internal: PyMutex<PositionIterInternal<PyListRef>>,
1079}
1080
1081impl PyPayload for PyListIterator {
1082 #[inline]
1083 fn class(ctx: &Context) -> &'static Py<PyType> {
1084 ctx.types.list_iterator_type
1085 }
1086}
1087
1088#[pyclass(flags(DISALLOW_INSTANTIATION), with(IterNext, Iterable))]
1089impl Py<PyListIterator> {
1090 #[pymethod]
1091 fn __length_hint__(&self) -> usize {
1092 self.internal.lock().length_hint(|obj| obj.__len__())
1093 }
1094
1095 #[pymethod]
1096 fn __setstate__(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
1097 self.internal
1098 .lock()
1099 .set_state(&object, |obj, pos| pos.min(obj.__len__()), vm)
1100 }
1101
1102 #[pymethod]
1103 fn __reduce__(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
1104 let func = builtins_iter(vm)?;
1105 Ok(self.internal.lock().reduce(
1106 func,
1107 |x| x.clone().into(),
1108 |vm| vm.ctx.new_list(Vec::new()).into(),
1109 vm,
1110 ))
1111 }
1112}
1113
1114impl PyListIterator {
1115 pub(crate) fn fast_next(&self) -> Option<PyObjectRef> {
1117 locked_next(&self.internal, |list, pos| {
1118 let vec = list.borrow_vec();
1119 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
1120 })
1121 .ok()
1122 .and_then(|r| match r {
1123 PyIterReturn::Return(v) => Some(v),
1124 PyIterReturn::StopIteration(_) => None,
1125 })
1126 }
1127}
1128
1129impl SelfIter for PyListIterator {}
1130impl IterNext for PyListIterator {
1131 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
1132 locked_next(&zelf.internal, |list, pos| {
1133 let vec = list.borrow_vec();
1134 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
1135 })
1136 }
1137}
1138
1139#[pyclass(module = false, name = "list_reverseiterator", traverse)]
1140#[derive(Debug)]
1141pub(crate) struct PyListReverseIterator {
1142 internal: PyMutex<PositionIterInternal<PyListRef>>,
1143}
1144
1145impl PyPayload for PyListReverseIterator {
1146 #[inline]
1147 fn class(ctx: &Context) -> &'static Py<PyType> {
1148 ctx.types.list_reverseiterator_type
1149 }
1150}
1151
1152#[pyclass(flags(DISALLOW_INSTANTIATION), with(IterNext, Iterable))]
1153impl Py<PyListReverseIterator> {
1154 #[pymethod]
1155 fn __length_hint__(&self) -> usize {
1156 self.internal.lock().rev_length_hint(|obj| obj.__len__())
1157 }
1158
1159 #[pymethod]
1160 fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
1161 self.internal
1162 .lock()
1163 .set_state(&state, |obj, pos| pos.min(obj.__len__()), vm)
1164 }
1165
1166 #[pymethod]
1167 fn __reduce__(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
1168 let func = builtins_reversed(vm)?;
1169 Ok(self.internal.lock().reduce(
1170 func,
1171 |x| x.clone().into(),
1172 |vm| vm.ctx.new_list(Vec::new()).into(),
1173 vm,
1174 ))
1175 }
1176}
1177
1178impl SelfIter for PyListReverseIterator {}
1179impl IterNext for PyListReverseIterator {
1180 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
1181 locked_rev_next(&zelf.internal, |list, pos| {
1182 let vec = list.borrow_vec();
1183 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
1184 })
1185 }
1186}
1187
1188fn vectorcall_list(
1189 zelf_obj: &PyObject,
1190 args: Vec<PyObjectRef>,
1191 nargs: usize,
1192 kwnames: Option<&[PyObjectRef]>,
1193 vm: &VirtualMachine,
1194) -> PyResult {
1195 let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
1196 let obj = PyList::default().into_ref_with_type(vm, zelf.to_owned())?;
1197 let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
1198 PyList::slot_init(obj.as_object(), func_args, vm)?;
1199 Ok(obj.into())
1200}
1201
1202pub(crate) fn init(context: &'static Context) {
1203 let list_type = &context.types.list_type;
1204 PyList::extend_class(context, list_type);
1205 list_type.slots.vectorcall.store(Some(vectorcall_list));
1206
1207 PyListIterator::extend_class(context, context.types.list_iterator_type);
1208 PyListReverseIterator::extend_class(context, context.types.list_reverseiterator_type);
1209}