1 /***********************************************************
2 Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
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 /* Array object implementation */
27 /* An array is a uniform list -- all items have the same type.
28 The item type is restricted to simple C types like int or float */
30 #include "allobjects.h"
31 #include "modsupport.h"
35 /* Cray APP doesn't have memmove */
37 extern char *memcpy();
40 #if defined(sun) && !defined(__STDC__)
41 /* SunOS doesn't have memmove */
43 extern char *memcpy();
47 extern char *memmove();
50 struct arrayobject
; /* Forward */
55 object
* (*getitem
) FPROTO((struct arrayobject
*, int));
56 int (*setitem
) FPROTO((struct arrayobject
*, int, object
*));
59 typedef struct arrayobject
{
62 struct arraydescr
*ob_descr
;
65 extern typeobject Arraytype
;
67 #define is_arrayobject(op) ((op)->ob_type == &Arraytype)
70 extern object
*newarrayobject
PROTO((int, struct arraydescr
*));
71 extern int getarraysize
PROTO((object
*));
72 extern object
*getarrayitem
PROTO((object
*, int));
73 static int setarrayitem
PROTO((object
*, int, object
*));
74 extern int insarrayitem
PROTO((object
*, int, object
*));
75 extern int addarrayitem
PROTO((object
*, object
*));
82 return newsizedstringobject(&((char *)ap
->ob_item
)[i
], 1);
92 if (!getargs(v
, "c;array item must be char", &x
))
95 ((char *)ap
->ob_item
)[i
] = x
;
104 long x
= ((char *)ap
->ob_item
)[i
];
107 return newintobject(x
);
117 if (!getargs(v
, "b;array item must be integer", &x
))
120 ((char *)ap
->ob_item
)[i
] = x
;
129 return newintobject((long) ((short *)ap
->ob_item
)[i
]);
139 if (!getargs(v
, "h;array item must be integer", &x
))
142 ((short *)ap
->ob_item
)[i
] = x
;
151 return newintobject((long) ((int *)ap
->ob_item
)[i
]);
161 if (!getargs(v
, "i;array item must be integer", &x
))
164 ((int *)ap
->ob_item
)[i
] = x
;
173 return newintobject(((long *)ap
->ob_item
)[i
]);
183 if (!getargs(v
, "l;array item must be integer", &x
))
186 ((long *)ap
->ob_item
)[i
] = x
;
195 return newfloatobject((double) ((float *)ap
->ob_item
)[i
]);
205 if (!getargs(v
, "f;array item must be float", &x
))
208 ((float *)ap
->ob_item
)[i
] = x
;
217 return newfloatobject(((double *)ap
->ob_item
)[i
]);
227 if (!getargs(v
, "d;array item must be float", &x
))
230 ((double *)ap
->ob_item
)[i
] = x
;
234 /* Description of types */
235 static struct arraydescr descriptors
[] = {
236 {'c', sizeof(char), c_getitem
, c_setitem
},
237 {'b', sizeof(char), b_getitem
, b_setitem
},
238 {'h', sizeof(short), h_getitem
, h_setitem
},
239 {'i', sizeof(int), i_getitem
, i_setitem
},
240 {'l', sizeof(long), l_getitem
, l_setitem
},
241 {'f', sizeof(float), f_getitem
, f_setitem
},
242 {'d', sizeof(double), d_getitem
, d_setitem
},
243 {'\0', 0, 0, 0} /* Sentinel */
245 /* If we ever allow items larger than double, we must change reverse()! */
249 newarrayobject(size
, descr
)
251 struct arraydescr
*descr
;
261 nbytes
= size
* descr
->itemsize
;
262 /* Check for overflow */
263 if (nbytes
/ descr
->itemsize
!= size
) {
266 op
= NEW(arrayobject
, 1);
274 op
->ob_item
= NEW(char, nbytes
);
275 if (op
->ob_item
== NULL
) {
280 op
->ob_type
= &Arraytype
;
282 op
->ob_descr
= descr
;
284 return (object
*) op
;
291 if (!is_arrayobject(op
)) {
295 return ((arrayobject
*)op
) -> ob_size
;
303 register arrayobject
*ap
;
304 if (!is_arrayobject(op
)) {
308 ap
= (arrayobject
*)op
;
309 if (i
< 0 || i
>= ap
->ob_size
) {
310 err_setstr(IndexError
, "array index out of range");
313 return (*ap
->ob_descr
->getitem
)(ap
, i
);
328 if ((*self
->ob_descr
->setitem
)(self
, -1, v
) < 0)
330 items
= self
->ob_item
;
331 RESIZE(items
, char, (self
->ob_size
+1) * self
->ob_descr
->itemsize
);
338 if (where
> self
->ob_size
)
339 where
= self
->ob_size
;
340 memmove(items
+ (where
+1)*self
->ob_descr
->itemsize
,
341 items
+ where
*self
->ob_descr
->itemsize
,
342 (self
->ob_size
-where
)*self
->ob_descr
->itemsize
);
343 self
->ob_item
= items
;
345 return (*self
->ob_descr
->setitem
)(self
, where
, v
);
349 insarrayitem(op
, where
, newitem
)
354 if (!is_arrayobject(op
)) {
358 return ins1((arrayobject
*)op
, where
, newitem
);
362 addarrayitem(op
, newitem
)
366 if (!is_arrayobject(op
)) {
370 return ins1((arrayobject
*)op
,
371 (int) ((arrayobject
*)op
)->ob_size
, newitem
);
381 if (op
->ob_item
!= NULL
)
390 int len
= (v
->ob_size
< w
->ob_size
) ? v
->ob_size
: w
->ob_size
;
392 for (i
= 0; i
< len
; i
++) {
395 ai
= getarrayitem((object
*)v
, i
);
396 bi
= getarrayitem((object
*)w
, i
);
398 cmp
= cmpobject(ai
, bi
);
404 err_clear(); /* XXX Can't report errors here */
408 return v
->ob_size
- w
->ob_size
;
423 if (i
< 0 || i
>= a
->ob_size
) {
424 err_setstr(IndexError
, "array index out of range");
427 return getarrayitem((object
*)a
, i
);
431 array_slice(a
, ilow
, ihigh
)
439 else if (ilow
> a
->ob_size
)
445 else if (ihigh
> a
->ob_size
)
447 np
= (arrayobject
*) newarrayobject(ihigh
- ilow
, a
->ob_descr
);
450 memcpy(np
->ob_item
, a
->ob_item
+ ilow
* a
->ob_descr
->itemsize
,
451 (ihigh
-ilow
) * a
->ob_descr
->itemsize
);
463 if (!is_arrayobject(bb
)) {
467 #define b ((arrayobject *)bb)
468 if (a
->ob_descr
!= b
->ob_descr
) {
472 size
= a
->ob_size
+ b
->ob_size
;
473 np
= (arrayobject
*) newarrayobject(size
, a
->ob_descr
);
477 memcpy(np
->ob_item
, a
->ob_item
, a
->ob_size
*a
->ob_descr
->itemsize
);
478 memcpy(np
->ob_item
+ a
->ob_size
*a
->ob_descr
->itemsize
,
479 b
->ob_item
, b
->ob_size
*b
->ob_descr
->itemsize
);
496 size
= a
->ob_size
* n
;
497 np
= (arrayobject
*) newarrayobject(size
, a
->ob_descr
);
501 nbytes
= a
->ob_size
* a
->ob_descr
->itemsize
;
502 for (i
= 0; i
< n
; i
++) {
503 memcpy(p
, a
->ob_item
, nbytes
);
506 return (object
*) np
;
510 array_ass_slice(a
, ilow
, ihigh
, v
)
516 int n
; /* Size of replacement array */
517 int d
; /* Change in size */
518 int k
; /* Loop index */
519 #define b ((arrayobject *)v)
522 else if (is_arrayobject(v
)) {
525 /* Special case "a[i:j] = a" -- copy b first */
527 v
= array_slice(b
, 0, n
);
528 ret
= array_ass_slice(a
, ilow
, ihigh
, v
);
532 if (b
->ob_descr
!= a
->ob_descr
) {
543 else if (ilow
> a
->ob_size
)
549 else if (ihigh
> a
->ob_size
)
552 d
= n
- (ihigh
-ilow
);
553 if (d
< 0) { /* Delete -d items */
554 memmove(item
+ (ihigh
+d
)*a
->ob_descr
->itemsize
,
555 item
+ ihigh
*a
->ob_descr
->itemsize
,
556 (a
->ob_size
-ihigh
)*a
->ob_descr
->itemsize
);
558 RESIZE(item
, char, a
->ob_size
*a
->ob_descr
->itemsize
);
562 else if (d
> 0) { /* Insert d items */
563 RESIZE(item
, char, (a
->ob_size
+ d
)*a
->ob_descr
->itemsize
);
568 memmove(item
+ (ihigh
+d
)*a
->ob_descr
->itemsize
,
569 item
+ ihigh
*a
->ob_descr
->itemsize
,
570 (a
->ob_size
-ihigh
)*a
->ob_descr
->itemsize
);
575 memcpy(item
+ ilow
*a
->ob_descr
->itemsize
, b
->ob_item
,
576 n
*b
->ob_descr
->itemsize
);
582 array_ass_item(a
, i
, v
)
587 if (i
< 0 || i
>= a
->ob_size
) {
588 err_setstr(IndexError
, "array assignment index out of range");
592 return array_ass_slice(a
, i
, i
+1, v
);
593 return (*a
->ob_descr
->setitem
)(a
, i
, v
);
597 setarrayitem(a
, i
, v
)
602 if (!is_arrayobject(a
)) {
606 return array_ass_item((arrayobject
*)a
, i
, v
);
615 if (ins1(self
, where
, v
) != 0)
622 array_insert(self
, args
)
628 if (!getargs(args
, "(iO)", &i
, &v
))
630 return ins(self
, i
, v
);
634 array_append(self
, args
)
639 if (!getargs(args
, "O", &v
))
641 return ins(self
, (int) self
->ob_size
, v
);
645 array_byteswap(self
, args
)
651 switch (self
->ob_descr
->itemsize
) {
655 for (p
= self
->ob_item
, i
= self
->ob_size
; --i
>= 0; p
+= 2) {
662 for (p
= self
->ob_item
, i
= self
->ob_size
; --i
>= 0; p
+= 4) {
672 for (p
= self
->ob_item
, i
= self
->ob_size
; --i
>= 0; p
+= 8) {
688 err_setstr(RuntimeError
,
689 "don't know how to byteswap this array type");
697 array_reverse(self
, args
)
701 register int itemsize
= self
->ob_descr
->itemsize
;
702 register char *p
, *q
;
703 char tmp
[sizeof(double)]; /* Assume that's the max item size */
710 if (self
->ob_size
> 1) {
711 for (p
= self
->ob_item
,
712 q
= self
->ob_item
+ (self
->ob_size
- 1)*itemsize
;
714 p
+= itemsize
, q
-= itemsize
) {
715 memmove(tmp
, p
, itemsize
);
716 memmove(p
, q
, itemsize
);
717 memmove(q
, tmp
, itemsize
);
725 /* The following routines were adapted from listobject.c but not converted.
726 To make them work you will have to work! */
730 array_index(self
, args
)
740 for (i
= 0; i
< self
->ob_size
; i
++) {
741 if (cmpobject(self
->ob_item
[i
], args
) == 0)
742 return newintobject((long)i
);
744 err_setstr(ValueError
, "array.index(x): x not in array");
751 array_count(self
, args
)
762 for (i
= 0; i
< self
->ob_size
; i
++) {
763 if (cmpobject(self
->ob_item
[i
], args
) == 0)
766 return newintobject((long)count
);
772 array_remove(self
, args
)
782 for (i
= 0; i
< self
->ob_size
; i
++) {
783 if (cmpobject(self
->ob_item
[i
], args
) == 0) {
784 if (array_ass_slice(self
, i
, i
+1, (object
*)NULL
) != 0)
791 err_setstr(ValueError
, "array.remove(x): x not in array");
797 array_fromfile(self
, args
)
804 if (!getargs(args
, "(Oi)", &f
, &n
))
808 err_setstr(TypeError
, "arg1 must be open file");
812 char *item
= self
->ob_item
;
813 int itemsize
= self
->ob_descr
->itemsize
;
815 RESIZE(item
, char, (self
->ob_size
+ n
) * itemsize
);
820 self
->ob_item
= item
;
822 nread
= fread(item
+ (self
->ob_size
- n
) * itemsize
,
825 self
->ob_size
-= (n
- nread
);
826 RESIZE(item
, char, self
->ob_size
*itemsize
);
827 self
->ob_item
= item
;
828 err_setstr(EOFError
, "not enough items in file");
837 array_tofile(self
, args
)
843 if (!getargs(args
, "O", &f
))
847 err_setstr(TypeError
, "arg must be open file");
850 if (self
->ob_size
> 0) {
851 if (fwrite(self
->ob_item
, self
->ob_descr
->itemsize
,
852 self
->ob_size
, fp
) != self
->ob_size
) {
863 array_fromlist(self
, args
)
869 int itemsize
= self
->ob_descr
->itemsize
;
870 if (!getargs(args
, "O", &list
))
872 if (!is_listobject(list
)) {
873 err_setstr(TypeError
, "arg must be list");
876 n
= getlistsize(list
);
878 char *item
= self
->ob_item
;
880 RESIZE(item
, char, (self
->ob_size
+ n
) * itemsize
);
885 self
->ob_item
= item
;
887 for (i
= 0; i
< n
; i
++) {
888 object
*v
= getlistitem(list
, i
);
889 if ((*self
->ob_descr
->setitem
)(self
,
890 self
->ob_size
- n
+ i
, v
) != 0) {
892 RESIZE(item
, char, self
->ob_size
* itemsize
);
893 self
->ob_item
= item
;
903 array_tolist(self
, args
)
907 object
*list
= newlistobject(self
->ob_size
);
911 for (i
= 0; i
< self
->ob_size
; i
++) {
912 object
*v
= getarrayitem((object
*)self
, i
);
917 setlistitem(list
, i
, v
);
923 array_fromstring(self
, args
)
929 int itemsize
= self
->ob_descr
->itemsize
;
930 if (!getargs(args
, "s#", &str
, &n
))
932 if (n
% itemsize
!= 0) {
933 err_setstr(ValueError
,
934 "string length not a multiple of item size");
939 char *item
= self
->ob_item
;
940 RESIZE(item
, char, (self
->ob_size
+ n
) * itemsize
);
945 self
->ob_item
= item
;
947 memcpy(item
+ (self
->ob_size
- n
) * itemsize
, str
, itemsize
*n
);
954 array_tostring(self
, args
)
958 if (!getargs(args
, ""))
960 return newsizedstringobject(self
->ob_item
,
961 self
->ob_size
* self
->ob_descr
->itemsize
);
964 static struct methodlist array_methods
[] = {
965 {"append", array_append
},
966 {"byteswap", array_byteswap
},
967 /* {"count", array_count},*/
968 {"fromfile", array_fromfile
},
969 {"fromlist", array_fromlist
},
970 {"fromstring", array_fromstring
},
971 /* {"index", array_index},*/
972 {"insert", array_insert
},
973 {"read", array_fromfile
},
974 /* {"remove", array_remove},*/
975 {"reverse", array_reverse
},
976 /* {"sort", array_sort},*/
977 {"tofile", array_tofile
},
978 {"tolist", array_tolist
},
979 {"tostring", array_tostring
},
980 {"write", array_tofile
},
981 {NULL
, NULL
} /* sentinel */
985 array_getattr(a
, name
)
989 if (strcmp(name
, "typecode") == 0) {
990 char tc
= a
->ob_descr
->typecode
;
991 return newsizedstringobject(&tc
, 1);
993 if (strcmp(name
, "itemsize") == 0) {
994 return newintobject((long)a
->ob_descr
->itemsize
);
996 if (strcmp(name
, "__members__") == 0) {
997 object
*list
= newlistobject(2);
999 setlistitem(list
, 0, newstringobject("typecode"));
1000 setlistitem(list
, 1, newstringobject("itemsize"));
1001 if (err_occurred()) {
1008 return findmethod(array_methods
, (object
*)a
, name
);
1012 array_print(a
, fp
, flags
)
1022 fprintf(fp
, "array('%c')", a
->ob_descr
->typecode
);
1025 if (a
->ob_descr
->typecode
== 'c') {
1026 fprintf(fp
, "array('c', ");
1027 v
= array_tostring(a
, (object
*)NULL
);
1028 ok
= printobject(v
, fp
, 0);
1033 fprintf(fp
, "array('%c', [", a
->ob_descr
->typecode
);
1034 for (i
= 0; i
< len
&& ok
== 0; i
++) {
1037 v
= (a
->ob_descr
->getitem
)(a
, i
);
1038 ok
= printobject(v
, fp
, 0);
1050 object
*s
, *t
, *comma
, *v
;
1054 sprintf(buf
, "array('%c')", a
->ob_descr
->typecode
);
1055 return newstringobject(buf
);
1057 if (a
->ob_descr
->typecode
== 'c') {
1058 sprintf(buf
, "array('c', ");
1059 s
= newstringobject(buf
);
1060 v
= array_tostring(a
, (object
*)NULL
);
1065 t
= newstringobject(")");
1068 if (err_occurred()) {
1074 sprintf(buf
, "array('%c', [", a
->ob_descr
->typecode
);
1075 s
= newstringobject(buf
);
1076 comma
= newstringobject(", ");
1077 for (i
= 0; i
< len
&& !err_occurred(); i
++) {
1078 v
= (a
->ob_descr
->getitem
)(a
, i
);
1082 joinstring(&s
, comma
);
1087 t
= newstringobject("])");
1090 if (err_occurred()) {
1097 static sequence_methods array_as_sequence
= {
1098 array_length
, /*sq_length*/
1099 array_concat
, /*sq_concat*/
1100 array_repeat
, /*sq_repeat*/
1101 array_item
, /*sq_item*/
1102 array_slice
, /*sq_slice*/
1103 array_ass_item
, /*sq_ass_item*/
1104 array_ass_slice
, /*sq_ass_slice*/
1107 typeobject Arraytype
= {
1108 OB_HEAD_INIT(&Typetype
)
1111 sizeof(arrayobject
),
1113 array_dealloc
, /*tp_dealloc*/
1114 array_print
, /*tp_print*/
1115 array_getattr
, /*tp_getattr*/
1117 array_compare
, /*tp_compare*/
1118 array_repr
, /*tp_repr*/
1120 &array_as_sequence
, /*tp_as_sequence*/
1121 0, /*tp_as_mapping*/
1131 object
*initial
= NULL
;
1132 struct arraydescr
*descr
;
1133 if (!getargs(args
, "c", &c
)) {
1135 if (!getargs(args
, "(cO)", &c
, &initial
))
1137 if (!is_listobject(initial
) && !is_stringobject(initial
)) {
1138 err_setstr(TypeError
,
1139 "array initializer must be list or string");
1143 for (descr
= descriptors
; descr
->typecode
!= '\0'; descr
++) {
1144 if (descr
->typecode
== c
) {
1147 if (initial
== NULL
|| !is_listobject(initial
))
1150 len
= getlistsize(initial
);
1151 a
= newarrayobject(len
, descr
);
1156 for (i
= 0; i
< len
; i
++) {
1157 object
*v
= getlistitem(initial
, i
);
1158 if (setarrayitem(a
, i
, v
) != 0) {
1164 if (initial
!= NULL
&& is_stringobject(initial
)) {
1166 array_fromstring((arrayobject
*)a
, initial
);
1176 err_setstr(ValueError
, "bad typecode (must be c, b, h, l, f or d)");
1180 static struct methodlist a_methods
[] = {
1182 {NULL
, NULL
} /* sentinel */
1188 initmodule("array", a_methods
);
1194 /* A perhaps slow but I hope correct implementation of memmove */
1196 char *memmove(dst
, src
, n
)
1201 char *realdst
= dst
;
1204 if (src
>= dst
+n
|| dst
>= src
+n
)
1205 return memcpy(dst
, src
, n
);
1210 else if (src
< dst
) {