1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* List object implementation */
27 #include "allobjects.h"
28 #include "modsupport.h"
33 #include <sys/types.h> /* For size_t */
36 #define ROUNDUP(n, block) ((((n)+(block)-1)/(block))*(block))
43 return ROUNDUP(n
, 10);
45 return ROUNDUP(n
, 100);
48 #define NRESIZE(var, type, nitems) RESIZE(var, type, roundup(nitems))
61 nbytes
= size
* sizeof(object
*);
62 /* Check for overflow */
63 if (nbytes
/ sizeof(object
*) != size
) {
66 op
= (listobject
*) malloc(sizeof(listobject
));
74 op
->ob_item
= (object
**) malloc(nbytes
);
75 if (op
->ob_item
== NULL
) {
80 op
->ob_type
= &Listtype
;
82 for (i
= 0; i
< size
; i
++)
83 op
->ob_item
[i
] = NULL
;
92 if (!is_listobject(op
)) {
97 return ((listobject
*)op
) -> ob_size
;
105 if (!is_listobject(op
)) {
109 if (i
< 0 || i
>= ((listobject
*)op
) -> ob_size
) {
110 err_setstr(IndexError
, "list index out of range");
113 return ((listobject
*)op
) -> ob_item
[i
];
117 setlistitem(op
, i
, newitem
)
120 register object
*newitem
;
122 register object
*olditem
;
124 if (!is_listobject(op
)) {
129 if (i
< 0 || i
>= ((listobject
*)op
) -> ob_size
) {
131 err_setstr(IndexError
, "list assignment index out of range");
134 p
= ((listobject
*)op
) -> ob_item
+ i
;
153 items
= self
->ob_item
;
154 NRESIZE(items
, object
*, self
->ob_size
+1);
161 if (where
> self
->ob_size
)
162 where
= self
->ob_size
;
163 for (i
= self
->ob_size
; --i
>= where
; )
164 items
[i
+1] = items
[i
];
167 self
->ob_item
= items
;
173 inslistitem(op
, where
, newitem
)
178 if (!is_listobject(op
)) {
182 return ins1((listobject
*)op
, where
, newitem
);
186 addlistitem(op
, newitem
)
190 if (!is_listobject(op
)) {
194 return ins1((listobject
*)op
,
195 (int) ((listobject
*)op
)->ob_size
, newitem
);
205 if (op
->ob_item
!= NULL
) {
206 for (i
= 0; i
< op
->ob_size
; i
++) {
207 XDECREF(op
->ob_item
[i
]);
209 free((ANY
*)op
->ob_item
);
215 list_print(op
, fp
, flags
)
222 for (i
= 0; i
< op
->ob_size
; i
++) {
225 if (printobject(op
->ob_item
[i
], fp
, 0) != 0)
238 s
= newstringobject("[");
239 comma
= newstringobject(", ");
240 for (i
= 0; i
< v
->ob_size
&& s
!= NULL
; i
++) {
242 joinstring(&s
, comma
);
243 joinstring_decref(&s
, reprobject(v
->ob_item
[i
]));
246 joinstring_decref(&s
, newstringobject("]"));
254 int len
= (v
->ob_size
< w
->ob_size
) ? v
->ob_size
: w
->ob_size
;
256 for (i
= 0; i
< len
; i
++) {
257 int cmp
= cmpobject(v
->ob_item
[i
], w
->ob_item
[i
]);
261 return v
->ob_size
- w
->ob_size
;
276 if (i
< 0 || i
>= a
->ob_size
) {
277 err_setstr(IndexError
, "list index out of range");
280 INCREF(a
->ob_item
[i
]);
281 return a
->ob_item
[i
];
285 list_slice(a
, ilow
, ihigh
)
293 else if (ilow
> a
->ob_size
)
299 else if (ihigh
> a
->ob_size
)
301 np
= (listobject
*) newlistobject(ihigh
- ilow
);
304 for (i
= ilow
; i
< ihigh
; i
++) {
305 object
*v
= a
->ob_item
[i
];
307 np
->ob_item
[i
- ilow
] = v
;
313 getlistslice(a
, ilow
, ihigh
)
317 if (!is_listobject(a
)) {
321 return list_slice((listobject
*)a
, ilow
, ihigh
);
332 if (!is_listobject(bb
)) {
336 #define b ((listobject *)bb)
337 size
= a
->ob_size
+ b
->ob_size
;
338 np
= (listobject
*) newlistobject(size
);
342 for (i
= 0; i
< a
->ob_size
; i
++) {
343 object
*v
= a
->ob_item
[i
];
347 for (i
= 0; i
< b
->ob_size
; i
++) {
348 object
*v
= b
->ob_item
[i
];
350 np
->ob_item
[i
+ a
->ob_size
] = v
;
367 size
= a
->ob_size
* n
;
368 np
= (listobject
*) newlistobject(size
);
372 for (i
= 0; i
< n
; i
++) {
373 for (j
= 0; j
< a
->ob_size
; j
++) {
379 return (object
*) np
;
383 list_ass_slice(a
, ilow
, ihigh
, v
)
388 /* Because [X]DECREF can recursively invoke list operations on
389 this list, we must postpone all [X]DECREF activity until
390 after the list is back in its canonical shape. Therefore
391 we must allocate an additional array, 'recycle', into which
392 we temporarily copy the items that are deleted from the
394 object
**recycle
, **p
;
396 int n
; /* Size of replacement list */
397 int d
; /* Change in size */
398 int k
; /* Loop index */
399 #define b ((listobject *)v)
402 else if (is_listobject(v
)) {
405 /* Special case "a[i:j] = a" -- copy b first */
407 v
= list_slice(b
, 0, n
);
408 ret
= list_ass_slice(a
, ilow
, ihigh
, v
);
419 else if (ilow
> a
->ob_size
)
425 else if (ihigh
> a
->ob_size
)
428 d
= n
- (ihigh
-ilow
);
430 p
= recycle
= NEW(object
*, (ihigh
-ilow
));
433 if (d
<= 0) { /* Delete -d items; recycle ihigh-ilow items */
434 for (k
= ilow
; k
< ihigh
; k
++)
437 for (/*k = ihigh*/; k
< a
->ob_size
; k
++)
440 NRESIZE(item
, object
*, a
->ob_size
); /* Can't fail */
444 else { /* Insert d items; recycle ihigh-ilow items */
445 NRESIZE(item
, object
*, a
->ob_size
+ d
);
451 for (k
= a
->ob_size
; --k
>= ihigh
; )
453 for (/*k = ihigh-1*/; k
>= ilow
; --k
)
458 for (k
= 0; k
< n
; k
++, ilow
++) {
459 object
*w
= b
->ob_item
[k
];
464 while (--p
>= recycle
)
473 setlistslice(a
, ilow
, ihigh
, v
)
478 if (!is_listobject(a
)) {
482 return list_ass_slice((listobject
*)a
, ilow
, ihigh
, v
);
486 list_ass_item(a
, i
, v
)
492 if (i
< 0 || i
>= a
->ob_size
) {
493 err_setstr(IndexError
, "list assignment index out of range");
497 return list_ass_slice(a
, i
, i
+1, v
);
499 old_value
= a
->ob_item
[i
];
511 if (ins1(self
, where
, v
) != 0)
518 listinsert(self
, args
)
524 if (!getargs(args
, "(iO)", &i
, &v
))
526 return ins(self
, i
, v
);
530 listappend(self
, args
)
535 if (!getargs(args
, "O", &v
))
537 return ins(self
, (int) self
->ob_size
, v
);
540 static object
*comparefunc
;
552 if (comparefunc
== NULL
)
553 return cmpobject(* (object
**) v
, * (object
**) w
);
555 /* Call the user-supplied comparison function */
556 t
= mkvalue("(OO)", * (object
**) v
, * (object
**) w
);
559 res
= call_object(comparefunc
, t
);
563 if (!is_intobject(res
)) {
564 err_setstr(TypeError
, "comparison function should return int");
568 i
= getintvalue(res
);
583 object
*save_comparefunc
;
584 if (self
->ob_size
<= 1) {
588 save_comparefunc
= comparefunc
;
590 if (comparefunc
!= NULL
) {
591 /* Test the comparison function for obvious errors */
592 (void) cmp((ANY
*)&self
->ob_item
[0], (ANY
*)&self
->ob_item
[1]);
593 if (err_occurred()) {
594 comparefunc
= save_comparefunc
;
598 qsort((char *)self
->ob_item
,
599 (int) self
->ob_size
, sizeof(object
*), cmp
);
600 comparefunc
= save_comparefunc
;
608 listreverse(self
, args
)
612 register object
**p
, **q
;
613 register object
*tmp
;
620 if (self
->ob_size
> 1) {
621 for (p
= self
->ob_item
, q
= self
->ob_item
+ self
->ob_size
- 1;
637 if (v
== NULL
|| !is_listobject(v
)) {
641 v
= listreverse((listobject
*)v
, (object
*)NULL
);
652 if (v
== NULL
|| !is_listobject(v
)) {
656 v
= listsort((listobject
*)v
, (object
*)NULL
);
670 if (v
== NULL
|| !is_listobject(v
)) {
674 n
= ((listobject
*)v
)->ob_size
;
675 w
= newtupleobject(n
);
678 p
= ((tupleobject
*)w
)->ob_item
;
680 (ANY
*)((listobject
*)v
)->ob_item
,
690 listindex(self
, args
)
700 for (i
= 0; i
< self
->ob_size
; i
++) {
701 if (cmpobject(self
->ob_item
[i
], args
) == 0)
702 return newintobject((long)i
);
704 err_setstr(ValueError
, "list.index(x): x not in list");
709 listcount(self
, args
)
720 for (i
= 0; i
< self
->ob_size
; i
++) {
721 if (cmpobject(self
->ob_item
[i
], args
) == 0)
724 return newintobject((long)count
);
728 listremove(self
, args
)
738 for (i
= 0; i
< self
->ob_size
; i
++) {
739 if (cmpobject(self
->ob_item
[i
], args
) == 0) {
740 if (list_ass_slice(self
, i
, i
+1, (object
*)NULL
) != 0)
747 err_setstr(ValueError
, "list.remove(x): x not in list");
751 static struct methodlist list_methods
[] = {
752 {"append", (method
)listappend
},
753 {"count", (method
)listcount
},
754 {"index", (method
)listindex
},
755 {"insert", (method
)listinsert
},
756 {"sort", (method
)listsort
, 0},
757 {"remove", (method
)listremove
},
758 {"reverse", (method
)listreverse
},
759 {NULL
, NULL
} /* sentinel */
763 list_getattr(f
, name
)
767 return findmethod(list_methods
, (object
*)f
, name
);
770 static sequence_methods list_as_sequence
= {
771 (inquiry
)list_length
, /*sq_length*/
772 (binaryfunc
)list_concat
, /*sq_concat*/
773 (intargfunc
)list_repeat
, /*sq_repeat*/
774 (intargfunc
)list_item
, /*sq_item*/
775 (intintargfunc
)list_slice
, /*sq_slice*/
776 (intobjargproc
)list_ass_item
, /*sq_ass_item*/
777 (intintobjargproc
)list_ass_slice
, /*sq_ass_slice*/
780 typeobject Listtype
= {
781 OB_HEAD_INIT(&Typetype
)
786 (destructor
)list_dealloc
, /*tp_dealloc*/
787 (printfunc
)list_print
, /*tp_print*/
788 (getattrfunc
)list_getattr
, /*tp_getattr*/
790 (cmpfunc
)list_compare
, /*tp_compare*/
791 (reprfunc
)list_repr
, /*tp_repr*/
793 &list_as_sequence
, /*tp_as_sequence*/