4
4
#include <stddef.h> /* for offsetof */
5
5
6
6
#ifndef ARRAYDEQUE_VERSION
7
- #define ARRAYDEQUE_VERSION "1.2.3 "
7
+ #define ARRAYDEQUE_VERSION "1.2.4 "
8
8
#endif
9
9
10
- /* The ArrayDeque object structure.
11
- A new field weakreflist is added to support weak references */
10
+ /* The ArrayDeque object structure. */
12
11
typedef struct {
13
12
PyObject_HEAD
14
- PyObject * weakreflist ; /* For weak reference support */
15
- PyObject * * array ; /* Pointer to array of PyObject* */
16
- Py_ssize_t capacity ; /* Allocated length of array */
17
- Py_ssize_t size ; /* Number of elements stored */
18
- Py_ssize_t head ; /* Index of first element */
19
- Py_ssize_t tail ; /* Index one past the last element */
20
- Py_ssize_t maxlen ; /* Maximum allowed size (if < 0 then unbounded) */
13
+ PyObject * * array ; /* pointer to array of PyObject* */
14
+ Py_ssize_t capacity ; /* allocated length of array */
15
+ Py_ssize_t size ; /* number of elements stored */
16
+ Py_ssize_t head ; /* index of first element */
17
+ Py_ssize_t tail ; /* index one past the last element */
18
+ Py_ssize_t maxlen ; /* maximum allowed size (if < 0 then unbounded) */
21
19
} ArrayDequeObject ;
22
20
23
21
/* Forward declaration of type for iterator */
24
22
typedef struct {
25
23
PyObject_HEAD
26
- ArrayDequeObject * deque ; /* Reference to the deque */
27
- Py_ssize_t index ; /* Current index into the deque (0 .. size) */
24
+ ArrayDequeObject * deque ; /* reference to the deque */
25
+ Py_ssize_t index ; /* current index into the deque (0 .. size) */
28
26
} ArrayDequeIter ;
29
27
30
28
/* Resize the backing array to new_capacity and recenter the data.
@@ -61,16 +59,21 @@ arraydeque_resize(ArrayDequeObject *self, Py_ssize_t new_capacity)
61
59
static PyObject *
62
60
ArrayDeque_append (ArrayDequeObject * self , PyObject * arg )
63
61
{
62
+ /* If maxlen is 0, do nothing. */
64
63
if (self -> maxlen == 0 ) {
65
64
Py_RETURN_NONE ;
66
65
}
66
+
67
+ /* If bounded and full, drop the leftmost element. */
67
68
if (self -> maxlen >= 0 && self -> size == self -> maxlen ) {
68
69
PyObject * old = self -> array [self -> head ];
69
70
Py_DECREF (old );
70
71
self -> array [self -> head ] = NULL ;
71
72
self -> head ++ ;
72
73
self -> size -- ;
73
74
}
75
+
76
+ /* Grow the internal array if needed */
74
77
if (self -> tail >= self -> capacity ) {
75
78
if (arraydeque_resize (self , self -> capacity * 2 ) < 0 )
76
79
return NULL ;
@@ -92,12 +95,16 @@ ArrayDeque_appendleft(ArrayDequeObject *self, PyObject *arg)
92
95
if (self -> maxlen == 0 ) {
93
96
Py_RETURN_NONE ;
94
97
}
98
+
99
+ /* If bounded and full, drop the rightmost element */
95
100
if (self -> maxlen >= 0 && self -> size == self -> maxlen ) {
96
101
self -> tail -- ;
97
102
Py_DECREF (self -> array [self -> tail ]);
98
103
self -> array [self -> tail ] = NULL ;
99
104
self -> size -- ;
100
105
}
106
+
107
+ /* Grow the internal array if necessary */
101
108
if (self -> head <= 0 ) {
102
109
if (arraydeque_resize (self , self -> capacity * 2 ) < 0 )
103
110
return NULL ;
@@ -146,17 +153,19 @@ ArrayDeque_popleft(ArrayDequeObject *self, PyObject *Py_UNUSED(ignored))
146
153
static PyObject *
147
154
ArrayDeque_clear (ArrayDequeObject * self , PyObject * Py_UNUSED (ignored ))
148
155
{
149
- for (Py_ssize_t i = self -> head ; i < self -> tail ; i ++ ) {
156
+ Py_ssize_t i ;
157
+ for (i = self -> head ; i < self -> tail ; i ++ ) {
150
158
Py_CLEAR (self -> array [i ]);
151
159
}
152
160
self -> size = 0 ;
161
+ /* Reset head and tail to the center of the current allocation */
153
162
self -> head = self -> capacity / 2 ;
154
163
self -> tail = self -> head ;
155
164
Py_RETURN_NONE ;
156
165
}
157
166
158
167
/* Method: extend(iterable)
159
- Extend the right side with elements from an iterable. */
168
+ Extend the right side of the deque by appending elements from the iterable. */
160
169
static PyObject *
161
170
ArrayDeque_extend (ArrayDequeObject * self , PyObject * iterable )
162
171
{
@@ -179,8 +188,8 @@ ArrayDeque_extend(ArrayDequeObject *self, PyObject *iterable)
179
188
}
180
189
181
190
/* Method: extendleft(iterable)
182
- Extend the left side with elements from an iterable.
183
- Note the order is reversed relative to the input. */
191
+ Extend the left side of the deque by appending elements from the iterable.
192
+ Note that left appends reverse the order relative to the input. */
184
193
static PyObject *
185
194
ArrayDeque_extendleft (ArrayDequeObject * self , PyObject * iterable )
186
195
{
@@ -191,6 +200,8 @@ ArrayDeque_extendleft(ArrayDequeObject *self, PyObject *iterable)
191
200
if (list == NULL )
192
201
return NULL ;
193
202
len = PyList_Size (list );
203
+ /* Iterate in forward order: each call to appendleft will
204
+ insert the item before the previous ones, thus reversing the input order. */
194
205
for (i = 0 ; i < len ; i ++ ) {
195
206
PyObject * item = PyList_GET_ITEM (list , i );
196
207
if (ArrayDeque_appendleft (self , item ) == NULL ) {
@@ -203,8 +214,9 @@ ArrayDeque_extendleft(ArrayDequeObject *self, PyObject *iterable)
203
214
}
204
215
205
216
/* Method: rotate(n=1)
206
- Rotate the deque n steps to the right (n negative rotates left).
207
- Each rotation uses pop/popleft and append/appendleft. */
217
+ Rotate the deque n steps to the right. If n is negative, rotate left.
218
+ Each individual rotation is implemented using pop/popleft and append/appendleft.
219
+ */
208
220
static PyObject *
209
221
ArrayDeque_rotate (ArrayDequeObject * self , PyObject * args )
210
222
{
@@ -244,7 +256,8 @@ ArrayDeque_rotate(ArrayDequeObject *self, PyObject *args)
244
256
}
245
257
246
258
/* Method: remove(value)
247
- Remove the first occurrence of value. */
259
+ Remove the first occurrence of value.
260
+ */
248
261
static PyObject *
249
262
ArrayDeque_remove (ArrayDequeObject * self , PyObject * value )
250
263
{
@@ -262,7 +275,7 @@ ArrayDeque_remove(ArrayDequeObject *self, PyObject *value)
262
275
}
263
276
Py_DECREF (self -> array [i ]);
264
277
for (Py_ssize_t j = i ; j < self -> tail - 1 ; j ++ ) {
265
- self -> array [j ] = self -> array [j + 1 ];
278
+ self -> array [j ] = self -> array [j + 1 ];
266
279
}
267
280
self -> array [self -> tail - 1 ] = NULL ;
268
281
self -> tail -- ;
@@ -271,7 +284,8 @@ ArrayDeque_remove(ArrayDequeObject *self, PyObject *value)
271
284
}
272
285
273
286
/* Method: count(value)
274
- Count the number of occurrences of value. */
287
+ Count the number of occurrences of value.
288
+ */
275
289
static PyObject *
276
290
ArrayDeque_count (ArrayDequeObject * self , PyObject * value )
277
291
{
@@ -293,7 +307,7 @@ ArrayDeque_length(ArrayDequeObject *self)
293
307
return self -> size ;
294
308
}
295
309
296
- /* Sequence protocol: __getitem__ (only integer indices) */
310
+ /* Sequence protocol: __getitem__ support (only for integer indices) */
297
311
static PyObject *
298
312
ArrayDeque_seq_getitem (ArrayDequeObject * self , Py_ssize_t index )
299
313
{
@@ -308,7 +322,7 @@ ArrayDeque_seq_getitem(ArrayDequeObject *self, Py_ssize_t index)
308
322
return item ;
309
323
}
310
324
311
- /* Mapping protocol: __getitem__ (same as sequence) */
325
+ /* Mapping protocol: __getitem__ support (same as sequence) */
312
326
static PyObject *
313
327
ArrayDeque_getitem (ArrayDequeObject * self , PyObject * key )
314
328
{
@@ -322,10 +336,11 @@ ArrayDeque_getitem(ArrayDequeObject *self, PyObject *key)
322
336
return ArrayDeque_seq_getitem (self , index );
323
337
}
324
338
325
- /* Sequence protocol: __setitem__ (only integer indices) */
339
+ /* Sequence protocol: __setitem__ support (only for integer indices) */
326
340
static int
327
341
ArrayDeque_seq_setitem (ArrayDequeObject * self , Py_ssize_t index , PyObject * value )
328
342
{
343
+ /* If value is NULL, this signals deletion which is not supported. */
329
344
if (value == NULL ) {
330
345
PyErr_SetString (PyExc_TypeError , "deque deletion not supported" );
331
346
return -1 ;
@@ -343,7 +358,7 @@ ArrayDeque_seq_setitem(ArrayDequeObject *self, Py_ssize_t index, PyObject *value
343
358
return 0 ;
344
359
}
345
360
346
- /* Mapping protocol: __setitem__ */
361
+ /* Mapping protocol: __setitem__ support */
347
362
static int
348
363
ArrayDeque_setitem (ArrayDequeObject * self , PyObject * key , PyObject * value )
349
364
{
@@ -371,7 +386,7 @@ ArrayDeque_contains(ArrayDequeObject *self, PyObject *value)
371
386
return 0 ;
372
387
}
373
388
374
- /* Rich comparison support: only equality and inequality */
389
+ /* Rich comparison support: only equality and inequality are implemented */
375
390
static PyObject *
376
391
ArrayDeque_richcompare (PyObject * self , PyObject * other , int op )
377
392
{
@@ -454,6 +469,7 @@ ArrayDequeIter_next(ArrayDequeIter *it)
454
469
Py_INCREF (item );
455
470
return item ;
456
471
}
472
+ /* End of iteration */
457
473
return NULL ;
458
474
}
459
475
@@ -468,7 +484,7 @@ static PyTypeObject ArrayDequeIter_Type = {
468
484
.tp_iternext = (iternextfunc )ArrayDequeIter_next ,
469
485
};
470
486
471
- /* __iter__ method for ArrayDeque */
487
+ /* __iter__ method for ArrayDeque: return a new iterator */
472
488
static PyObject *
473
489
ArrayDeque_iter (ArrayDequeObject * self )
474
490
{
@@ -482,19 +498,17 @@ ArrayDeque_iter(ArrayDequeObject *self)
482
498
return (PyObject * )it ;
483
499
}
484
500
485
- /* __new__ method: allocate a new ArrayDeque.
486
- This version uses PyObject_GC_New to ensure that the object
487
- is not already tracked by the garbage collector (fixing issues on macOS). */
501
+ /* __new__ method: allocate a new ArrayDeque */
488
502
static PyObject *
489
503
ArrayDeque_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
490
504
{
491
505
ArrayDequeObject * self ;
492
- self = PyObject_GC_New (ArrayDequeObject , type );
506
+ self = (ArrayDequeObject * ) type -> tp_alloc ( type , 0 );
493
507
if (self == NULL )
494
508
return NULL ;
495
- self -> weakreflist = NULL ;
496
509
self -> capacity = 8 ; /* initial capacity */
497
510
self -> size = 0 ;
511
+ /* Start in the middle so that both ends have some space */
498
512
self -> head = self -> capacity / 2 ;
499
513
self -> tail = self -> head ;
500
514
self -> array = PyMem_New (PyObject * , self -> capacity );
@@ -508,13 +522,12 @@ ArrayDeque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
508
522
}
509
523
/* Default: unbounded deque */
510
524
self -> maxlen = -1 ;
511
- PyObject_GC_Track ((PyObject * )self );
512
525
return (PyObject * )self ;
513
526
}
514
527
515
528
/* __init__ method: optionally initialize the deque with an iterable and a maxlen.
516
529
Signature: ArrayDeque([iterable[, maxlen]])
517
- If maxlen is provided ( and not None) it must be a non-negative integer.
530
+ If maxlen is provided and not None, it must be a non-negative integer.
518
531
When iterable is longer than maxlen, only the rightmost elements are retained.
519
532
*/
520
533
static int
@@ -563,35 +576,13 @@ ArrayDeque_init(ArrayDequeObject *self, PyObject *args, PyObject *kwds)
563
576
static void
564
577
ArrayDeque_dealloc (ArrayDequeObject * self )
565
578
{
566
- PyObject_GC_UnTrack (self );
567
- PyObject_ClearWeakRefs ((PyObject * )self );
568
579
for (Py_ssize_t i = self -> head ; i < self -> tail ; i ++ ) {
569
- Py_CLEAR (self -> array [i ]);
580
+ Py_XDECREF (self -> array [i ]);
570
581
}
571
582
PyMem_Free (self -> array );
572
583
Py_TYPE (self )-> tp_free ((PyObject * )self );
573
584
}
574
585
575
- /* GC traverse function */
576
- static int
577
- ArrayDeque_traverse (ArrayDequeObject * self , visitproc visit , void * arg )
578
- {
579
- for (Py_ssize_t i = self -> head ; i < self -> tail ; i ++ ) {
580
- Py_VISIT (self -> array [i ]);
581
- }
582
- return 0 ;
583
- }
584
-
585
- /* GC clear function */
586
- static int
587
- ArrayDeque_clear_func (ArrayDequeObject * self )
588
- {
589
- for (Py_ssize_t i = self -> head ; i < self -> tail ; i ++ ) {
590
- Py_CLEAR (self -> array [i ]);
591
- }
592
- return 0 ;
593
- }
594
-
595
586
/* Getter for the maxlen attribute.
596
587
Returns None if unbounded; otherwise a Python integer. */
597
588
static PyObject *
@@ -625,10 +616,11 @@ ArrayDeque_reduce(ArrayDequeObject *self)
625
616
return NULL ;
626
617
}
627
618
}
619
+ /* Build args tuple as (iterable, maxlen) */
628
620
PyObject * args = Py_BuildValue ("(OO)" , list , maxlen );
629
621
Py_DECREF (list );
630
622
Py_DECREF (maxlen );
631
- Py_INCREF ( Py_TYPE ( self ));
623
+ /* Return a two-tuple: (constructor, args) */
632
624
return Py_BuildValue ("OO" , Py_TYPE (self ), args );
633
625
}
634
626
@@ -666,7 +658,7 @@ static PyMethodDef ArrayDeque_methods[] = {
666
658
{NULL } /* Sentinel */
667
659
};
668
660
669
- /* Sequence methods */
661
+ /* Define sequence methods (supporting __len__, __getitem__, __setitem__, and __contains__) */
670
662
static PySequenceMethods ArrayDeque_as_sequence = {
671
663
(lenfunc )ArrayDeque_length , /* sq_length */
672
664
0 , /* sq_concat */
@@ -680,7 +672,7 @@ static PySequenceMethods ArrayDeque_as_sequence = {
680
672
0 /* sq_inplace_repeat */
681
673
};
682
674
683
- /* Mapping methods */
675
+ /* Define mapping methods so that deque[index] works as expected. */
684
676
static PyMappingMethods ArrayDeque_as_mapping = {
685
677
(lenfunc )ArrayDeque_length , /* mp_length */
686
678
(binaryfunc )ArrayDeque_getitem , /* mp_subscript */
@@ -695,7 +687,7 @@ static PyTypeObject ArrayDequeType = {
695
687
.tp_basicsize = sizeof (ArrayDequeObject ),
696
688
.tp_itemsize = 0 ,
697
689
.tp_dealloc = (destructor )ArrayDeque_dealloc ,
698
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC ,
690
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ,
699
691
.tp_new = ArrayDeque_new ,
700
692
.tp_init = (initproc )ArrayDeque_init ,
701
693
.tp_iter = (getiterfunc )ArrayDeque_iter ,
@@ -706,9 +698,6 @@ static PyTypeObject ArrayDequeType = {
706
698
.tp_str = (reprfunc )ArrayDeque_str ,
707
699
.tp_repr = (reprfunc )ArrayDeque_repr ,
708
700
.tp_richcompare = ArrayDeque_richcompare ,
709
- .tp_weaklistoffset = offsetof(ArrayDequeObject , weakreflist ),
710
- .tp_traverse = (traverseproc )ArrayDeque_traverse ,
711
- .tp_clear = (inquiry )ArrayDeque_clear_func ,
712
701
};
713
702
714
703
/* Module definition */
0 commit comments