1
1
use std:: cell:: { Cell , RefCell } ;
2
2
use std:: fmt;
3
3
4
- use std:: ops:: DerefMut ;
4
+ use std:: ops:: Range ;
5
5
6
- use num_traits:: ToPrimitive ;
6
+ use num_bigint:: BigInt ;
7
+ use num_traits:: { One , Signed , ToPrimitive , Zero } ;
7
8
8
9
use crate :: function:: { OptionalArg , PyFuncArgs } ;
9
10
use crate :: pyobject:: { IdProtocol , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TypeProtocol } ;
@@ -13,9 +14,10 @@ use super::objbool;
13
14
use super :: objint;
14
15
use super :: objiter;
15
16
use super :: objsequence:: {
16
- del_item , get_elements, get_elements_cell, get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt,
17
- seq_mul , PySliceableSequence ,
17
+ get_elements, get_elements_cell, get_item, seq_equal, seq_ge, seq_gt, seq_le, seq_lt, seq_mul ,
18
+ PySliceableSequence , SequenceIndex ,
18
19
} ;
20
+ use super :: objslice:: PySliceRef ;
19
21
use super :: objtype;
20
22
use crate :: obj:: objtype:: PyClassRef ;
21
23
@@ -46,6 +48,54 @@ impl PyValue for PyList {
46
48
}
47
49
}
48
50
51
+ impl PyList {
52
+ pub fn get_len ( & self ) -> usize {
53
+ self . elements . borrow ( ) . len ( )
54
+ }
55
+
56
+ pub fn get_pos ( & self , p : i32 ) -> Option < usize > {
57
+ // convert a (potentially negative) positon into a real index
58
+ if p < 0 {
59
+ if -p as usize > self . get_len ( ) {
60
+ None
61
+ } else {
62
+ Some ( self . get_len ( ) - ( ( -p) as usize ) )
63
+ }
64
+ } else if p as usize >= self . get_len ( ) {
65
+ None
66
+ } else {
67
+ Some ( p as usize )
68
+ }
69
+ }
70
+
71
+ pub fn get_slice_pos ( & self , slice_pos : & BigInt ) -> usize {
72
+ if let Some ( pos) = slice_pos. to_i32 ( ) {
73
+ if let Some ( index) = self . get_pos ( pos) {
74
+ // within bounds
75
+ return index;
76
+ }
77
+ }
78
+
79
+ if slice_pos. is_negative ( ) {
80
+ // slice past start bound, round to start
81
+ 0
82
+ } else {
83
+ // slice past end bound, round to end
84
+ self . get_len ( )
85
+ }
86
+ }
87
+
88
+ pub fn get_slice_range ( & self , start : & Option < BigInt > , stop : & Option < BigInt > ) -> Range < usize > {
89
+ let start = start. as_ref ( ) . map ( |x| self . get_slice_pos ( x) ) . unwrap_or ( 0 ) ;
90
+ let stop = stop
91
+ . as_ref ( )
92
+ . map ( |x| self . get_slice_pos ( x) )
93
+ . unwrap_or_else ( || self . get_len ( ) ) ;
94
+
95
+ start..stop
96
+ }
97
+ }
98
+
49
99
pub type PyListRef = PyRef < PyList > ;
50
100
51
101
impl PyListRef {
@@ -313,9 +363,123 @@ impl PyListRef {
313
363
}
314
364
}
315
365
316
- fn delitem ( self , key : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
366
+ fn delitem ( self , subscript : SequenceIndex , vm : & VirtualMachine ) -> PyResult {
367
+ match subscript {
368
+ SequenceIndex :: Int ( index) => self . delindex ( index, vm) ,
369
+ SequenceIndex :: Slice ( slice) => self . delslice ( slice, vm) ,
370
+ }
371
+ }
372
+
373
+ fn delindex ( self , index : i32 , vm : & VirtualMachine ) -> PyResult {
374
+ if let Some ( pos_index) = self . get_pos ( index) {
375
+ self . elements . borrow_mut ( ) . remove ( pos_index) ;
376
+ Ok ( vm. get_none ( ) )
377
+ } else {
378
+ Err ( vm. new_index_error ( "Index out of bounds!" . to_string ( ) ) )
379
+ }
380
+ }
381
+
382
+ fn delslice ( self , slice : PySliceRef , vm : & VirtualMachine ) -> PyResult {
383
+ let start = & slice. start ;
384
+ let stop = & slice. stop ;
385
+ let step = slice. step . clone ( ) . unwrap_or_else ( BigInt :: one) ;
386
+
387
+ if step. is_zero ( ) {
388
+ Err ( vm. new_value_error ( "slice step cannot be zero" . to_string ( ) ) )
389
+ } else if step. is_positive ( ) {
390
+ let range = self . get_slice_range ( & start, & stop) ;
391
+ if range. start < range. end {
392
+ #[ allow( clippy:: range_plus_one) ]
393
+ match step. to_i32 ( ) {
394
+ Some ( 1 ) => {
395
+ self . _del_slice ( range) ;
396
+ Ok ( vm. get_none ( ) )
397
+ }
398
+ Some ( num) => {
399
+ self . _del_stepped_slice ( range, num as usize ) ;
400
+ Ok ( vm. get_none ( ) )
401
+ }
402
+ None => {
403
+ self . _del_slice ( range. start ..range. start + 1 ) ;
404
+ Ok ( vm. get_none ( ) )
405
+ }
406
+ }
407
+ } else {
408
+ // no del to do
409
+ Ok ( vm. get_none ( ) )
410
+ }
411
+ } else {
412
+ // calculate the range for the reverse slice, first the bounds needs to be made
413
+ // exclusive around stop, the lower number
414
+ let start = start. as_ref ( ) . map ( |x| x + 1 ) ;
415
+ let stop = stop. as_ref ( ) . map ( |x| x + 1 ) ;
416
+ let range = self . get_slice_range ( & stop, & start) ;
417
+ if range. start < range. end {
418
+ match ( -step) . to_i32 ( ) {
419
+ Some ( 1 ) => {
420
+ self . _del_slice ( range) ;
421
+ Ok ( vm. get_none ( ) )
422
+ }
423
+ Some ( num) => {
424
+ self . _del_stepped_slice_reverse ( range, num as usize ) ;
425
+ Ok ( vm. get_none ( ) )
426
+ }
427
+ None => {
428
+ self . _del_slice ( range. end - 1 ..range. end ) ;
429
+ Ok ( vm. get_none ( ) )
430
+ }
431
+ }
432
+ } else {
433
+ // no del to do
434
+ Ok ( vm. get_none ( ) )
435
+ }
436
+ }
437
+ }
438
+
439
+ fn _del_slice ( self , range : Range < usize > ) {
440
+ self . elements . borrow_mut ( ) . drain ( range) ;
441
+ }
442
+
443
+ fn _del_stepped_slice ( self , range : Range < usize > , step : usize ) {
444
+ // no easy way to delete stepped indexes so here is what we'll do
445
+ let mut deleted = 0 ;
446
+ let mut elements = self . elements . borrow_mut ( ) ;
447
+ let mut indexes = range. clone ( ) . step_by ( step) . peekable ( ) ;
448
+
449
+ for i in range. clone ( ) {
450
+ // is this an index to delete?
451
+ if indexes. peek ( ) == Some ( & i) {
452
+ // record and move on
453
+ indexes. next ( ) ;
454
+ deleted += 1 ;
455
+ } else {
456
+ // swap towards front
457
+ elements. swap ( i - deleted, i) ;
458
+ }
459
+ }
460
+ // then drain (the values to delete should now be contiguous at the end of the range)
461
+ elements. drain ( ( range. end - deleted) ..range. end ) ;
462
+ }
463
+
464
+ fn _del_stepped_slice_reverse ( self , range : Range < usize > , step : usize ) {
465
+ // no easy way to delete stepped indexes so here is what we'll do
466
+ let mut deleted = 0 ;
317
467
let mut elements = self . elements . borrow_mut ( ) ;
318
- del_item ( vm, self . as_object ( ) , elements. deref_mut ( ) , key)
468
+ let mut indexes = range. clone ( ) . rev ( ) . step_by ( step) . peekable ( ) ;
469
+
470
+ for i in range. clone ( ) . rev ( ) {
471
+ // is this an index to delete?
472
+ if indexes. peek ( ) == Some ( & i) {
473
+ // record and move on
474
+ indexes. next ( ) ;
475
+ deleted += 1 ;
476
+ } else {
477
+ // swap towards back
478
+ elements. swap ( i + deleted, i) ;
479
+ }
480
+ }
481
+ // then drain (the values to delete should now be contiguous at teh start of the range)
482
+ elements. drain ( range. start ..( range. start + deleted) ) ;
319
483
}
320
484
}
321
485
0 commit comments