Mercurial > cpython-lru_cache-weakref
comparison Modules/arraymodule.c @ 1235:87ed00a62d31 legacy-trunk
Added new module "array" (for now optional) defining array objects.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Fri, 19 Feb 1993 15:55:02 +0000 |
| parents | |
| children | 2919b448e385 |
comparison
equal
deleted
inserted
replaced
| 1234:586c928c65d3 | 1235:87ed00a62d31 |
|---|---|
| 1 /*********************************************************** | |
| 2 Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, | |
| 3 Amsterdam, The Netherlands. | |
| 4 | |
| 5 All Rights Reserved | |
| 6 | |
| 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. | |
| 14 | |
| 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. | |
| 22 | |
| 23 ******************************************************************/ | |
| 24 | |
| 25 /* Array object implementation */ | |
| 26 | |
| 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 */ | |
| 29 | |
| 30 #include "allobjects.h" | |
| 31 #include "modsupport.h" | |
| 32 #include "ceval.h" | |
| 33 | |
| 34 #ifdef sun | |
| 35 #define NEED_MEMMOVE | |
| 36 #endif | |
| 37 | |
| 38 #ifdef NEED_MEMMOVE | |
| 39 extern char *memmove(); | |
| 40 #endif | |
| 41 | |
| 42 struct arrayobject; /* Forward */ | |
| 43 | |
| 44 struct arraydescr { | |
| 45 int typecode; | |
| 46 int itemsize; | |
| 47 object * (*getitem) FPROTO((struct arrayobject *, int)); | |
| 48 int (*setitem) FPROTO((struct arrayobject *, int, object *)); | |
| 49 }; | |
| 50 | |
| 51 typedef struct arrayobject { | |
| 52 OB_VARHEAD | |
| 53 char *ob_item; | |
| 54 struct arraydescr *ob_descr; | |
| 55 } arrayobject; | |
| 56 | |
| 57 extern typeobject Arraytype; | |
| 58 | |
| 59 #define is_arrayobject(op) ((op)->ob_type == &Arraytype) | |
| 60 | |
| 61 extern object *newarrayobject PROTO((int, struct arraydescr *)); | |
| 62 extern int getarraysize PROTO((object *)); | |
| 63 extern object *getarrayitem PROTO((object *, int)); | |
| 64 extern int setarrayitem PROTO((object *, int, object *)); | |
| 65 extern int insarrayitem PROTO((object *, int, object *)); | |
| 66 extern int addarrayitem PROTO((object *, object *)); | |
| 67 | |
| 68 static object * | |
| 69 c_getitem(ap, i) | |
| 70 arrayobject *ap; | |
| 71 int i; | |
| 72 { | |
| 73 return newsizedstringobject(&((char *)ap->ob_item)[i], 1); | |
| 74 } | |
| 75 | |
| 76 static int | |
| 77 c_setitem(ap, i, v) | |
| 78 arrayobject *ap; | |
| 79 int i; | |
| 80 object *v; | |
| 81 { | |
| 82 char x; | |
| 83 if (!getargs(v, "c;array item must be char", &x)) | |
| 84 return -1; | |
| 85 if (i >= 0) | |
| 86 ((char *)ap->ob_item)[i] = x; | |
| 87 return 0; | |
| 88 } | |
| 89 | |
| 90 static object * | |
| 91 b_getitem(ap, i) | |
| 92 arrayobject *ap; | |
| 93 int i; | |
| 94 { | |
| 95 long x = ((char *)ap->ob_item)[i]; | |
| 96 if (x >= 128) | |
| 97 x -= 256; | |
| 98 return newintobject(x); | |
| 99 } | |
| 100 | |
| 101 static int | |
| 102 b_setitem(ap, i, v) | |
| 103 arrayobject *ap; | |
| 104 int i; | |
| 105 object *v; | |
| 106 { | |
| 107 char x; | |
| 108 if (!getargs(v, "b;array item must be integer", &x)) | |
| 109 return -1; | |
| 110 if (i >= 0) | |
| 111 ((char *)ap->ob_item)[i] = x; | |
| 112 return 0; | |
| 113 } | |
| 114 | |
| 115 static object * | |
| 116 h_getitem(ap, i) | |
| 117 arrayobject *ap; | |
| 118 int i; | |
| 119 { | |
| 120 return newintobject((long) ((short *)ap->ob_item)[i]); | |
| 121 } | |
| 122 | |
| 123 static int | |
| 124 h_setitem(ap, i, v) | |
| 125 arrayobject *ap; | |
| 126 int i; | |
| 127 object *v; | |
| 128 { | |
| 129 short x; | |
| 130 if (!getargs(v, "h;array item must be integer", &x)) | |
| 131 return -1; | |
| 132 if (i >= 0) | |
| 133 ((short *)ap->ob_item)[i] = x; | |
| 134 return 0; | |
| 135 } | |
| 136 | |
| 137 static object * | |
| 138 l_getitem(ap, i) | |
| 139 arrayobject *ap; | |
| 140 int i; | |
| 141 { | |
| 142 return newintobject(((long *)ap->ob_item)[i]); | |
| 143 } | |
| 144 | |
| 145 static int | |
| 146 l_setitem(ap, i, v) | |
| 147 arrayobject *ap; | |
| 148 int i; | |
| 149 object *v; | |
| 150 { | |
| 151 long x; | |
| 152 if (!getargs(v, "l;array item must be integer", &x)) | |
| 153 return -1; | |
| 154 if (i >= 0) | |
| 155 ((long *)ap->ob_item)[i] = x; | |
| 156 return 0; | |
| 157 } | |
| 158 | |
| 159 static object * | |
| 160 f_getitem(ap, i) | |
| 161 arrayobject *ap; | |
| 162 int i; | |
| 163 { | |
| 164 return newfloatobject((double) ((float *)ap->ob_item)[i]); | |
| 165 } | |
| 166 | |
| 167 static int | |
| 168 f_setitem(ap, i, v) | |
| 169 arrayobject *ap; | |
| 170 int i; | |
| 171 object *v; | |
| 172 { | |
| 173 float x; | |
| 174 if (!getargs(v, "f;array item must be float", &x)) | |
| 175 return -1; | |
| 176 if (i >= 0) | |
| 177 ((float *)ap->ob_item)[i] = x; | |
| 178 return 0; | |
| 179 } | |
| 180 | |
| 181 static object * | |
| 182 d_getitem(ap, i) | |
| 183 arrayobject *ap; | |
| 184 int i; | |
| 185 { | |
| 186 return newfloatobject(((double *)ap->ob_item)[i]); | |
| 187 } | |
| 188 | |
| 189 static int | |
| 190 d_setitem(ap, i, v) | |
| 191 arrayobject *ap; | |
| 192 int i; | |
| 193 object *v; | |
| 194 { | |
| 195 double x; | |
| 196 if (!getargs(v, "d;array item must be float", &x)) | |
| 197 return -1; | |
| 198 if (i >= 0) | |
| 199 ((double *)ap->ob_item)[i] = x; | |
| 200 return 0; | |
| 201 } | |
| 202 | |
| 203 /* Description of types */ | |
| 204 struct arraydescr descriptors[] = { | |
| 205 {'c', sizeof(char), c_getitem, c_setitem}, | |
| 206 {'b', sizeof(char), b_getitem, b_setitem}, | |
| 207 {'h', sizeof(short), h_getitem, h_setitem}, | |
| 208 {'l', sizeof(long), l_getitem, l_setitem}, | |
| 209 {'f', sizeof(float), f_getitem, f_setitem}, | |
| 210 {'d', sizeof(double), d_getitem, d_setitem}, | |
| 211 {'\0', 0, 0, 0} /* Sentinel */ | |
| 212 }; | |
| 213 | |
| 214 | |
| 215 object * | |
| 216 newarrayobject(size, descr) | |
| 217 int size; | |
| 218 struct arraydescr *descr; | |
| 219 { | |
| 220 int i; | |
| 221 arrayobject *op; | |
| 222 MALLARG nbytes; | |
| 223 int itemsize; | |
| 224 if (size < 0) { | |
| 225 err_badcall(); | |
| 226 return NULL; | |
| 227 } | |
| 228 nbytes = size * descr->itemsize; | |
| 229 /* Check for overflow */ | |
| 230 if (nbytes / descr->itemsize != size) { | |
| 231 return err_nomem(); | |
| 232 } | |
| 233 op = (arrayobject *) malloc(sizeof(arrayobject)); | |
| 234 if (op == NULL) { | |
| 235 return err_nomem(); | |
| 236 } | |
| 237 if (size <= 0) { | |
| 238 op->ob_item = NULL; | |
| 239 } | |
| 240 else { | |
| 241 op->ob_item = malloc(nbytes); | |
| 242 if (op->ob_item == NULL) { | |
| 243 free((ANY *)op); | |
| 244 return err_nomem(); | |
| 245 } | |
| 246 } | |
| 247 NEWREF(op); | |
| 248 op->ob_type = &Arraytype; | |
| 249 op->ob_size = size; | |
| 250 op->ob_descr = descr; | |
| 251 return (object *) op; | |
| 252 } | |
| 253 | |
| 254 int | |
| 255 getarraysize(op) | |
| 256 object *op; | |
| 257 { | |
| 258 if (!is_arrayobject(op)) { | |
| 259 err_badcall(); | |
| 260 return -1; | |
| 261 } | |
| 262 return ((arrayobject *)op) -> ob_size; | |
| 263 } | |
| 264 | |
| 265 object * | |
| 266 getarrayitem(op, i) | |
| 267 object *op; | |
| 268 int i; | |
| 269 { | |
| 270 register arrayobject *ap; | |
| 271 if (!is_arrayobject(op)) { | |
| 272 err_badcall(); | |
| 273 return NULL; | |
| 274 } | |
| 275 ap = (arrayobject *)op; | |
| 276 if (i < 0 || i >= ap->ob_size) { | |
| 277 err_setstr(IndexError, "array index out of range"); | |
| 278 return NULL; | |
| 279 } | |
| 280 return (*ap->ob_descr->getitem)(ap, i); | |
| 281 } | |
| 282 | |
| 283 static int | |
| 284 ins1(self, where, v) | |
| 285 arrayobject *self; | |
| 286 int where; | |
| 287 object *v; | |
| 288 { | |
| 289 int i; | |
| 290 char *items; | |
| 291 if (v == NULL) { | |
| 292 err_badcall(); | |
| 293 return -1; | |
| 294 } | |
| 295 if ((*self->ob_descr->setitem)(self, -1, v) < 0) | |
| 296 return -1; | |
| 297 items = self->ob_item; | |
| 298 RESIZE(items, char, (self->ob_size+1) * self->ob_descr->itemsize); | |
| 299 if (items == NULL) { | |
| 300 err_nomem(); | |
| 301 return -1; | |
| 302 } | |
| 303 if (where < 0) | |
| 304 where = 0; | |
| 305 if (where > self->ob_size) | |
| 306 where = self->ob_size; | |
| 307 memmove(items + (where+1)*self->ob_descr->itemsize, | |
| 308 items + where*self->ob_descr->itemsize, | |
| 309 (self->ob_size-where)*self->ob_descr->itemsize); | |
| 310 self->ob_item = items; | |
| 311 self->ob_size++; | |
| 312 return (*self->ob_descr->setitem)(self, where, v); | |
| 313 } | |
| 314 | |
| 315 int | |
| 316 insarrayitem(op, where, newitem) | |
| 317 object *op; | |
| 318 int where; | |
| 319 object *newitem; | |
| 320 { | |
| 321 if (!is_arrayobject(op)) { | |
| 322 err_badcall(); | |
| 323 return -1; | |
| 324 } | |
| 325 return ins1((arrayobject *)op, where, newitem); | |
| 326 } | |
| 327 | |
| 328 int | |
| 329 addarrayitem(op, newitem) | |
| 330 object *op; | |
| 331 object *newitem; | |
| 332 { | |
| 333 if (!is_arrayobject(op)) { | |
| 334 err_badcall(); | |
| 335 return -1; | |
| 336 } | |
| 337 return ins1((arrayobject *)op, | |
| 338 (int) ((arrayobject *)op)->ob_size, newitem); | |
| 339 } | |
| 340 | |
| 341 /* Methods */ | |
| 342 | |
| 343 static void | |
| 344 array_dealloc(op) | |
| 345 arrayobject *op; | |
| 346 { | |
| 347 int i; | |
| 348 if (op->ob_item != NULL) | |
| 349 free((ANY *)op->ob_item); | |
| 350 free((ANY *)op); | |
| 351 } | |
| 352 | |
| 353 static int | |
| 354 array_compare(v, w) | |
| 355 arrayobject *v, *w; | |
| 356 { | |
| 357 int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; | |
| 358 int i; | |
| 359 for (i = 0; i < len; i++) { | |
| 360 object *ai, *bi; | |
| 361 int cmp; | |
| 362 ai = getarrayitem((object *)v, i); | |
| 363 bi = getarrayitem((object *)w, i); | |
| 364 if (ai && bi) | |
| 365 cmp = cmpobject(ai, bi); | |
| 366 else | |
| 367 cmp = -1; | |
| 368 XDECREF(ai); | |
| 369 XDECREF(bi); | |
| 370 if (cmp != 0) { | |
| 371 err_clear(); /* XXX Can't report errors here */ | |
| 372 return cmp; | |
| 373 } | |
| 374 } | |
| 375 return v->ob_size - w->ob_size; | |
| 376 } | |
| 377 | |
| 378 static int | |
| 379 array_length(a) | |
| 380 arrayobject *a; | |
| 381 { | |
| 382 return a->ob_size; | |
| 383 } | |
| 384 | |
| 385 static object * | |
| 386 array_item(a, i) | |
| 387 arrayobject *a; | |
| 388 int i; | |
| 389 { | |
| 390 if (i < 0 || i >= a->ob_size) { | |
| 391 err_setstr(IndexError, "array index out of range"); | |
| 392 return NULL; | |
| 393 } | |
| 394 return getarrayitem((object *)a, i); | |
| 395 } | |
| 396 | |
| 397 static object * | |
| 398 array_slice(a, ilow, ihigh) | |
| 399 arrayobject *a; | |
| 400 int ilow, ihigh; | |
| 401 { | |
| 402 arrayobject *np; | |
| 403 int i; | |
| 404 if (ilow < 0) | |
| 405 ilow = 0; | |
| 406 else if (ilow > a->ob_size) | |
| 407 ilow = a->ob_size; | |
| 408 if (ihigh < 0) | |
| 409 ihigh = 0; | |
| 410 if (ihigh < ilow) | |
| 411 ihigh = ilow; | |
| 412 else if (ihigh > a->ob_size) | |
| 413 ihigh = a->ob_size; | |
| 414 np = (arrayobject *) newarrayobject(ihigh - ilow, a->ob_descr); | |
| 415 if (np == NULL) | |
| 416 return NULL; | |
| 417 memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize, | |
| 418 (ihigh-ilow) * a->ob_descr->itemsize); | |
| 419 return (object *)np; | |
| 420 } | |
| 421 | |
| 422 static object * | |
| 423 array_concat(a, bb) | |
| 424 arrayobject *a; | |
| 425 object *bb; | |
| 426 { | |
| 427 int size; | |
| 428 int i; | |
| 429 arrayobject *np; | |
| 430 if (!is_arrayobject(bb)) { | |
| 431 err_badarg(); | |
| 432 return NULL; | |
| 433 } | |
| 434 #define b ((arrayobject *)bb) | |
| 435 if (a->ob_descr != b->ob_descr) { | |
| 436 err_badarg(); | |
| 437 return NULL; | |
| 438 } | |
| 439 size = a->ob_size + b->ob_size; | |
| 440 np = (arrayobject *) newarrayobject(size, a->ob_descr); | |
| 441 if (np == NULL) { | |
| 442 return NULL; | |
| 443 } | |
| 444 memcpy(np->ob_item, a->ob_item, a->ob_size*a->ob_descr->itemsize); | |
| 445 memcpy(np->ob_item + a->ob_size*a->ob_descr->itemsize, | |
| 446 a->ob_item, a->ob_size*a->ob_descr->itemsize); | |
| 447 return (object *)np; | |
| 448 #undef b | |
| 449 } | |
| 450 | |
| 451 static object * | |
| 452 array_repeat(a, n) | |
| 453 arrayobject *a; | |
| 454 int n; | |
| 455 { | |
| 456 int i, j; | |
| 457 int size; | |
| 458 arrayobject *np; | |
| 459 char *p; | |
| 460 int nbytes; | |
| 461 if (n < 0) | |
| 462 n = 0; | |
| 463 size = a->ob_size * n; | |
| 464 np = (arrayobject *) newarrayobject(size, a->ob_descr); | |
| 465 if (np == NULL) | |
| 466 return NULL; | |
| 467 p = np->ob_item; | |
| 468 nbytes = a->ob_size * a->ob_descr->itemsize; | |
| 469 for (i = 0; i < n; i++) { | |
| 470 memcpy(p, a->ob_item, nbytes); | |
| 471 p += nbytes; | |
| 472 } | |
| 473 return (object *) np; | |
| 474 } | |
| 475 | |
| 476 static int | |
| 477 array_ass_slice(a, ilow, ihigh, v) | |
| 478 arrayobject *a; | |
| 479 int ilow, ihigh; | |
| 480 object *v; | |
| 481 { | |
| 482 char *item; | |
| 483 int n; /* Size of replacement array */ | |
| 484 int d; /* Change in size */ | |
| 485 int k; /* Loop index */ | |
| 486 #define b ((arrayobject *)v) | |
| 487 if (v == NULL) | |
| 488 n = 0; | |
| 489 else if (is_arrayobject(v)) { | |
| 490 n = b->ob_size; | |
| 491 if (a == b) { | |
| 492 /* Special case "a[i:j] = a" -- copy b first */ | |
| 493 int ret; | |
| 494 v = array_slice(b, 0, n); | |
| 495 ret = array_ass_slice(a, ilow, ihigh, v); | |
| 496 DECREF(v); | |
| 497 return ret; | |
| 498 } | |
| 499 if (b->ob_descr != a->ob_descr) { | |
| 500 err_badarg(); | |
| 501 return -1; | |
| 502 } | |
| 503 } | |
| 504 else { | |
| 505 err_badarg(); | |
| 506 return -1; | |
| 507 } | |
| 508 if (ilow < 0) | |
| 509 ilow = 0; | |
| 510 else if (ilow > a->ob_size) | |
| 511 ilow = a->ob_size; | |
| 512 if (ihigh < 0) | |
| 513 ihigh = 0; | |
| 514 if (ihigh < ilow) | |
| 515 ihigh = ilow; | |
| 516 else if (ihigh > a->ob_size) | |
| 517 ihigh = a->ob_size; | |
| 518 item = a->ob_item; | |
| 519 d = n - (ihigh-ilow); | |
| 520 if (d < 0) { /* Delete -d items */ | |
| 521 memmove(item + (ihigh+d)*a->ob_descr->itemsize, | |
| 522 item + ihigh*a->ob_descr->itemsize, | |
| 523 (a->ob_size-ihigh)*a->ob_descr->itemsize); | |
| 524 a->ob_size += d; | |
| 525 RESIZE(item, char, a->ob_size*a->ob_descr->itemsize); | |
| 526 /* Can't fail */ | |
| 527 a->ob_item = item; | |
| 528 } | |
| 529 else if (d > 0) { /* Insert d items */ | |
| 530 RESIZE(item, char, (a->ob_size + d)*a->ob_descr->itemsize); | |
| 531 if (item == NULL) { | |
| 532 err_nomem(); | |
| 533 return -1; | |
| 534 } | |
| 535 memmove(item + (ihigh+d)*a->ob_descr->itemsize, | |
| 536 item + ihigh*a->ob_descr->itemsize, | |
| 537 (a->ob_size-ihigh)*a->ob_descr->itemsize); | |
| 538 a->ob_item = item; | |
| 539 a->ob_size += d; | |
| 540 } | |
| 541 if (n > 0) | |
| 542 memcpy(item + ilow*a->ob_descr->itemsize, b->ob_item, | |
| 543 n*b->ob_descr->itemsize); | |
| 544 return 0; | |
| 545 #undef b | |
| 546 } | |
| 547 | |
| 548 static int | |
| 549 array_ass_item(a, i, v) | |
| 550 arrayobject *a; | |
| 551 int i; | |
| 552 object *v; | |
| 553 { | |
| 554 if (i < 0 || i >= a->ob_size) { | |
| 555 err_setstr(IndexError, "array assignment index out of range"); | |
| 556 return -1; | |
| 557 } | |
| 558 if (v == NULL) | |
| 559 return array_ass_slice(a, i, i+1, v); | |
| 560 return (*a->ob_descr->setitem)(a, i, v); | |
| 561 } | |
| 562 | |
| 563 static int | |
| 564 setarrayitem(a, i, v) | |
| 565 object *a; | |
| 566 int i; | |
| 567 object *v; | |
| 568 { | |
| 569 if (!is_arrayobject(a)) { | |
| 570 err_badcall(); | |
| 571 return -1; | |
| 572 } | |
| 573 return array_ass_item((arrayobject *)a, i, v); | |
| 574 } | |
| 575 | |
| 576 static object * | |
| 577 ins(self, where, v) | |
| 578 arrayobject *self; | |
| 579 int where; | |
| 580 object *v; | |
| 581 { | |
| 582 if (ins1(self, where, v) != 0) | |
| 583 return NULL; | |
| 584 INCREF(None); | |
| 585 return None; | |
| 586 } | |
| 587 | |
| 588 static object * | |
| 589 array_insert(self, args) | |
| 590 arrayobject *self; | |
| 591 object *args; | |
| 592 { | |
| 593 int i; | |
| 594 object *v; | |
| 595 if (!getargs(args, "(iO)", &i, &v)) | |
| 596 return NULL; | |
| 597 return ins(self, i, v); | |
| 598 } | |
| 599 | |
| 600 static object * | |
| 601 array_append(self, args) | |
| 602 arrayobject *self; | |
| 603 object *args; | |
| 604 { | |
| 605 object *v; | |
| 606 if (!getargs(args, "O", &v)) | |
| 607 return NULL; | |
| 608 return ins(self, (int) self->ob_size, v); | |
| 609 } | |
| 610 | |
| 611 static object * | |
| 612 array_byteswap(self, args) | |
| 613 arrayobject *self; | |
| 614 object *args; | |
| 615 { | |
| 616 char *p; | |
| 617 int i; | |
| 618 switch (self->ob_descr->itemsize) { | |
| 619 case 1: | |
| 620 break; | |
| 621 case 2: | |
| 622 for (p = self->ob_item, i = self->ob_size; --i >= 0; p += 2) { | |
| 623 char p0 = p[0]; | |
| 624 p[0] = p[1]; | |
| 625 p[1] = p0; | |
| 626 } | |
| 627 break; | |
| 628 case 4: | |
| 629 for (p = self->ob_item, i = self->ob_size; --i >= 0; p += 4) { | |
| 630 char p0 = p[0]; | |
| 631 char p1 = p[1]; | |
| 632 p[0] = p[3]; | |
| 633 p[1] = p[2]; | |
| 634 p[2] = p1; | |
| 635 p[3] = p0; | |
| 636 } | |
| 637 break; | |
| 638 default: | |
| 639 err_setstr(RuntimeError, | |
| 640 "don't know how to byteswap this array type"); | |
| 641 return NULL; | |
| 642 } | |
| 643 INCREF(None); | |
| 644 return None; | |
| 645 } | |
| 646 | |
| 647 #if 0 | |
| 648 static object * | |
| 649 array_reverse(self, args) | |
| 650 arrayobject *self; | |
| 651 object *args; | |
| 652 { | |
| 653 register object **p, **q; | |
| 654 register object *tmp; | |
| 655 | |
| 656 if (args != NULL) { | |
| 657 err_badarg(); | |
| 658 return NULL; | |
| 659 } | |
| 660 | |
| 661 if (self->ob_size > 1) { | |
| 662 for (p = self->ob_item, q = self->ob_item + self->ob_size - 1; | |
| 663 p < q; p++, q--) { | |
| 664 tmp = *p; | |
| 665 *p = *q; | |
| 666 *q = tmp; | |
| 667 } | |
| 668 } | |
| 669 | |
| 670 INCREF(None); | |
| 671 return None; | |
| 672 } | |
| 673 #endif | |
| 674 | |
| 675 #if 0 | |
| 676 static object * | |
| 677 array_index(self, args) | |
| 678 arrayobject *self; | |
| 679 object *args; | |
| 680 { | |
| 681 int i; | |
| 682 | |
| 683 if (args == NULL) { | |
| 684 err_badarg(); | |
| 685 return NULL; | |
| 686 } | |
| 687 for (i = 0; i < self->ob_size; i++) { | |
| 688 if (cmpobject(self->ob_item[i], args) == 0) | |
| 689 return newintobject((long)i); | |
| 690 } | |
| 691 err_setstr(ValueError, "array.index(x): x not in array"); | |
| 692 return NULL; | |
| 693 } | |
| 694 #endif | |
| 695 | |
| 696 #if 0 | |
| 697 static object * | |
| 698 array_count(self, args) | |
| 699 arrayobject *self; | |
| 700 object *args; | |
| 701 { | |
| 702 int count = 0; | |
| 703 int i; | |
| 704 | |
| 705 if (args == NULL) { | |
| 706 err_badarg(); | |
| 707 return NULL; | |
| 708 } | |
| 709 for (i = 0; i < self->ob_size; i++) { | |
| 710 if (cmpobject(self->ob_item[i], args) == 0) | |
| 711 count++; | |
| 712 } | |
| 713 return newintobject((long)count); | |
| 714 } | |
| 715 #endif | |
| 716 | |
| 717 #if 0 | |
| 718 static object * | |
| 719 array_remove(self, args) | |
| 720 arrayobject *self; | |
| 721 object *args; | |
| 722 { | |
| 723 int i; | |
| 724 | |
| 725 if (args == NULL) { | |
| 726 err_badarg(); | |
| 727 return NULL; | |
| 728 } | |
| 729 for (i = 0; i < self->ob_size; i++) { | |
| 730 if (cmpobject(self->ob_item[i], args) == 0) { | |
| 731 if (array_ass_slice(self, i, i+1, (object *)NULL) != 0) | |
| 732 return NULL; | |
| 733 INCREF(None); | |
| 734 return None; | |
| 735 } | |
| 736 | |
| 737 } | |
| 738 err_setstr(ValueError, "array.remove(x): x not in array"); | |
| 739 return NULL; | |
| 740 } | |
| 741 #endif | |
| 742 | |
| 743 static object * | |
| 744 array_read(self, args) | |
| 745 arrayobject *self; | |
| 746 object *args; | |
| 747 { | |
| 748 object *f; | |
| 749 int n; | |
| 750 FILE *fp; | |
| 751 if (!getargs(args, "(Oi)", &f, &n)) | |
| 752 return NULL; | |
| 753 fp = getfilefile(f); | |
| 754 if (fp == NULL) { | |
| 755 err_setstr(TypeError, "arg1 must be open file"); | |
| 756 return NULL; | |
| 757 } | |
| 758 if (n > 0) { | |
| 759 char *item = self->ob_item; | |
| 760 int itemsize = self->ob_descr->itemsize; | |
| 761 int nread; | |
| 762 RESIZE(item, char, (self->ob_size + n) * itemsize); | |
| 763 if (item == NULL) { | |
| 764 err_nomem(); | |
| 765 return NULL; | |
| 766 } | |
| 767 self->ob_item = item; | |
| 768 self->ob_size += n; | |
| 769 nread = fread(item + (self->ob_size - n) * itemsize, | |
| 770 itemsize, n, fp); | |
| 771 if (nread < n) { | |
| 772 self->ob_size -= (n - nread); | |
| 773 RESIZE(item, char, self->ob_size*itemsize); | |
| 774 self->ob_item = item; | |
| 775 err_setstr(EOFError, "not enough items in file"); | |
| 776 return NULL; | |
| 777 } | |
| 778 } | |
| 779 INCREF(None); | |
| 780 return None; | |
| 781 } | |
| 782 | |
| 783 static object * | |
| 784 array_write(self, args) | |
| 785 arrayobject *self; | |
| 786 object *args; | |
| 787 { | |
| 788 object *f; | |
| 789 FILE *fp; | |
| 790 if (!getargs(args, "O", &f)) | |
| 791 return NULL; | |
| 792 fp = getfilefile(f); | |
| 793 if (fp == NULL) { | |
| 794 err_setstr(TypeError, "arg must be open file"); | |
| 795 return NULL; | |
| 796 } | |
| 797 if (self->ob_size > 0) { | |
| 798 if (fwrite(self->ob_item, self->ob_descr->itemsize, | |
| 799 self->ob_size, fp) != self->ob_size) { | |
| 800 err_errno(IOError); | |
| 801 clearerr(fp); | |
| 802 return NULL; | |
| 803 } | |
| 804 } | |
| 805 INCREF(None); | |
| 806 return None; | |
| 807 } | |
| 808 | |
| 809 static object * | |
| 810 array_fromlist(self, args) | |
| 811 arrayobject *self; | |
| 812 object *args; | |
| 813 { | |
| 814 int n; | |
| 815 object *list; | |
| 816 int itemsize = self->ob_descr->itemsize; | |
| 817 if (!getargs(args, "O", &list)) | |
| 818 return NULL; | |
| 819 if (!is_listobject(list)) { | |
| 820 err_setstr(TypeError, "arg must be list"); | |
| 821 return NULL; | |
| 822 } | |
| 823 n = getlistsize(list); | |
| 824 if (n > 0) { | |
| 825 char *item = self->ob_item; | |
| 826 int i; | |
| 827 RESIZE(item, char, (self->ob_size + n) * itemsize); | |
| 828 if (item == NULL) { | |
| 829 err_nomem(); | |
| 830 return NULL; | |
| 831 } | |
| 832 self->ob_item = item; | |
| 833 self->ob_size += n; | |
| 834 for (i = 0; i < n; i++) { | |
| 835 object *v = getlistitem(list, i); | |
| 836 if ((*self->ob_descr->setitem)(self, | |
| 837 self->ob_size - n + i, v) != 0) { | |
| 838 self->ob_size -= n; | |
| 839 RESIZE(item, char, self->ob_size * itemsize); | |
| 840 self->ob_item = item; | |
| 841 return NULL; | |
| 842 } | |
| 843 } | |
| 844 } | |
| 845 INCREF(None); | |
| 846 return None; | |
| 847 } | |
| 848 | |
| 849 static object * | |
| 850 array_tolist(self, args) | |
| 851 arrayobject *self; | |
| 852 object *args; | |
| 853 { | |
| 854 object *list = newlistobject(self->ob_size); | |
| 855 int i; | |
| 856 if (list == NULL) | |
| 857 return NULL; | |
| 858 for (i = 0; i < self->ob_size; i++) { | |
| 859 object *v = getarrayitem((object *)self, i); | |
| 860 if (v == NULL) { | |
| 861 DECREF(list); | |
| 862 return NULL; | |
| 863 } | |
| 864 setlistitem(list, i, v); | |
| 865 } | |
| 866 return list; | |
| 867 } | |
| 868 | |
| 869 static object * | |
| 870 array_fromstring(self, args) | |
| 871 arrayobject *self; | |
| 872 object *args; | |
| 873 { | |
| 874 char *str; | |
| 875 int n; | |
| 876 int itemsize = self->ob_descr->itemsize; | |
| 877 if (!getargs(args, "s#", &str, &n)) | |
| 878 return NULL; | |
| 879 if (n % itemsize != 0) { | |
| 880 err_setstr(ValueError, | |
| 881 "string length not a multiple of item size"); | |
| 882 return NULL; | |
| 883 } | |
| 884 n = n / itemsize; | |
| 885 if (n > 0) { | |
| 886 char *item = self->ob_item; | |
| 887 RESIZE(item, char, (self->ob_size + n) * itemsize); | |
| 888 if (item == NULL) { | |
| 889 err_nomem(); | |
| 890 return NULL; | |
| 891 } | |
| 892 self->ob_item = item; | |
| 893 self->ob_size += n; | |
| 894 memcpy(item + (self->ob_size - n) * itemsize, str, itemsize*n); | |
| 895 } | |
| 896 INCREF(None); | |
| 897 return None; | |
| 898 } | |
| 899 | |
| 900 static object * | |
| 901 array_tostring(self, args) | |
| 902 arrayobject *self; | |
| 903 object *args; | |
| 904 { | |
| 905 if (!getargs(args, "")) | |
| 906 return NULL; | |
| 907 return newsizedstringobject(self->ob_item, | |
| 908 self->ob_size * self->ob_descr->itemsize); | |
| 909 } | |
| 910 | |
| 911 static struct methodlist array_methods[] = { | |
| 912 {"append", array_append}, | |
| 913 {"byteswap", array_byteswap}, | |
| 914 /* {"count", array_count},*/ | |
| 915 /* {"index", array_index},*/ | |
| 916 {"insert", array_insert}, | |
| 917 /* {"sort", array_sort},*/ | |
| 918 /* {"remove", array_remove},*/ | |
| 919 /* {"reverse", array_reverse},*/ | |
| 920 {"read", array_read}, | |
| 921 {"write", array_write}, | |
| 922 {"fromlist", array_fromlist}, | |
| 923 {"tolist", array_tolist}, | |
| 924 {"fromstring", array_fromstring}, | |
| 925 {"tostring", array_tostring}, | |
| 926 {NULL, NULL} /* sentinel */ | |
| 927 }; | |
| 928 | |
| 929 static object * | |
| 930 array_getattr(a, name) | |
| 931 arrayobject *a; | |
| 932 char *name; | |
| 933 { | |
| 934 if (strcmp(name, "typecode") == 0) { | |
| 935 char tc = a->ob_descr->typecode; | |
| 936 return newsizedstringobject(&tc, 1); | |
| 937 } | |
| 938 if (strcmp(name, "itemsize") == 0) { | |
| 939 return newintobject((long)a->ob_descr->itemsize); | |
| 940 } | |
| 941 return findmethod(array_methods, (object *)a, name); | |
| 942 } | |
| 943 | |
| 944 static int | |
| 945 array_print(a, fp, flags) | |
| 946 arrayobject *a; | |
| 947 FILE *fp; | |
| 948 int flags; | |
| 949 { | |
| 950 int ok = 0; | |
| 951 int i, len; | |
| 952 object *v; | |
| 953 len = a->ob_size; | |
| 954 if (len == 0) { | |
| 955 fprintf(fp, "array('%c')", a->ob_descr->typecode); | |
| 956 return ok; | |
| 957 } | |
| 958 if (a->ob_descr->typecode == 'c') { | |
| 959 fprintf(fp, "array('c', "); | |
| 960 v = array_tostring(a, (object *)NULL); | |
| 961 ok = printobject(v, fp, flags); | |
| 962 XDECREF(v); | |
| 963 fprintf(fp, ")"); | |
| 964 return ok; | |
| 965 } | |
| 966 fprintf(fp, "array('%c', [", a->ob_descr->typecode); | |
| 967 for (i = 0; i < len && ok == 0; i++) { | |
| 968 if (i > 0) | |
| 969 fprintf(fp, ", "); | |
| 970 v = (a->ob_descr->getitem)(a, i); | |
| 971 ok = printobject(v, fp, flags); | |
| 972 XDECREF(v); | |
| 973 } | |
| 974 fprintf(fp, "])"); | |
| 975 return ok; | |
| 976 } | |
| 977 | |
| 978 static object * | |
| 979 array_repr(a) | |
| 980 arrayobject *a; | |
| 981 { | |
| 982 char buf[256]; | |
| 983 object *s, *t, *comma, *v; | |
| 984 int i, len; | |
| 985 len = a->ob_size; | |
| 986 if (len == 0) { | |
| 987 sprintf(buf, "array('%c')", a->ob_descr->typecode); | |
| 988 return newstringobject(buf); | |
| 989 } | |
| 990 if (a->ob_descr->typecode == 'c') { | |
| 991 sprintf(buf, "array('c', "); | |
| 992 s = newstringobject(buf); | |
| 993 v = array_tostring(a, (object *)NULL); | |
| 994 t = reprobject(v); | |
| 995 XDECREF(v); | |
| 996 joinstring(&s, t); | |
| 997 XDECREF(t); | |
| 998 t = newstringobject(")"); | |
| 999 joinstring(&s, t); | |
| 1000 XDECREF(t); | |
| 1001 if (err_occurred()) { | |
| 1002 XDECREF(s); | |
| 1003 s = NULL; | |
| 1004 } | |
| 1005 return s; | |
| 1006 } | |
| 1007 sprintf(buf, "array('%c', [", a->ob_descr->typecode); | |
| 1008 s = newstringobject(buf); | |
| 1009 comma = newstringobject(", "); | |
| 1010 for (i = 0; i < len && !err_occurred(); i++) { | |
| 1011 v = (a->ob_descr->getitem)(a, i); | |
| 1012 t = reprobject(v); | |
| 1013 XDECREF(v); | |
| 1014 if (i > 0) | |
| 1015 joinstring(&s, comma); | |
| 1016 joinstring(&s, t); | |
| 1017 XDECREF(t); | |
| 1018 } | |
| 1019 XDECREF(comma); | |
| 1020 t = newstringobject("])"); | |
| 1021 joinstring(&s, t); | |
| 1022 XDECREF(t); | |
| 1023 if (err_occurred()) { | |
| 1024 XDECREF(s); | |
| 1025 s = NULL; | |
| 1026 } | |
| 1027 return s; | |
| 1028 } | |
| 1029 | |
| 1030 static sequence_methods array_as_sequence = { | |
| 1031 array_length, /*sq_length*/ | |
| 1032 array_concat, /*sq_concat*/ | |
| 1033 array_repeat, /*sq_repeat*/ | |
| 1034 array_item, /*sq_item*/ | |
| 1035 array_slice, /*sq_slice*/ | |
| 1036 array_ass_item, /*sq_ass_item*/ | |
| 1037 array_ass_slice, /*sq_ass_slice*/ | |
| 1038 }; | |
| 1039 | |
| 1040 typeobject Arraytype = { | |
| 1041 OB_HEAD_INIT(&Typetype) | |
| 1042 0, | |
| 1043 "array", | |
| 1044 sizeof(arrayobject), | |
| 1045 0, | |
| 1046 array_dealloc, /*tp_dealloc*/ | |
| 1047 array_print, /*tp_print*/ | |
| 1048 array_getattr, /*tp_getattr*/ | |
| 1049 0, /*tp_setattr*/ | |
| 1050 array_compare, /*tp_compare*/ | |
| 1051 array_repr, /*tp_repr*/ | |
| 1052 0, /*tp_as_number*/ | |
| 1053 &array_as_sequence, /*tp_as_sequence*/ | |
| 1054 0, /*tp_as_mapping*/ | |
| 1055 }; | |
| 1056 | |
| 1057 | |
| 1058 static object * | |
| 1059 a_array(self, args) | |
| 1060 object *self; | |
| 1061 object *args; | |
| 1062 { | |
| 1063 char c; | |
| 1064 object *initial = NULL; | |
| 1065 struct arraydescr *descr; | |
| 1066 if (!getargs(args, "c", &c)) { | |
| 1067 err_clear(); | |
| 1068 if (!getargs(args, "(cO)", &c, &initial)) | |
| 1069 return NULL; | |
| 1070 if (!is_listobject(initial) && !is_stringobject(initial)) { | |
| 1071 err_setstr(TypeError, | |
| 1072 "array initializer must be list or string"); | |
| 1073 return NULL; | |
| 1074 } | |
| 1075 } | |
| 1076 for (descr = descriptors; descr->typecode != '\0'; descr++) { | |
| 1077 if (descr->typecode == c) { | |
| 1078 object *a; | |
| 1079 int len; | |
| 1080 if (initial == NULL || !is_listobject(initial)) | |
| 1081 len = 0; | |
| 1082 else | |
| 1083 len = getlistsize(initial); | |
| 1084 a = newarrayobject(len, descr); | |
| 1085 if (a == NULL) | |
| 1086 return NULL; | |
| 1087 if (len > 0) { | |
| 1088 int i; | |
| 1089 for (i = 0; i < len; i++) { | |
| 1090 object *v = getlistitem(initial, i); | |
| 1091 if (setarrayitem(a, i, v) != 0) { | |
| 1092 DECREF(a); | |
| 1093 return NULL; | |
| 1094 } | |
| 1095 } | |
| 1096 } | |
| 1097 if (initial != NULL && is_stringobject(initial)) { | |
| 1098 object *v = | |
| 1099 array_fromstring((arrayobject *)a, initial); | |
| 1100 if (v == NULL) { | |
| 1101 DECREF(a); | |
| 1102 return NULL; | |
| 1103 } | |
| 1104 DECREF(v); | |
| 1105 } | |
| 1106 return a; | |
| 1107 } | |
| 1108 } | |
| 1109 err_setstr(ValueError, "bad typecode (must be c, b, h, l, f or d)"); | |
| 1110 return NULL; | |
| 1111 } | |
| 1112 | |
| 1113 static struct methodlist a_methods[] = { | |
| 1114 {"array", a_array}, | |
| 1115 {NULL, NULL} /* sentinel */ | |
| 1116 }; | |
| 1117 | |
| 1118 void | |
| 1119 initarray() | |
| 1120 { | |
| 1121 initmodule("array", a_methods); | |
| 1122 } | |
| 1123 | |
| 1124 | |
| 1125 #ifdef NEED_MEMMOVE | |
| 1126 | |
| 1127 /* A perhaps slow but I hope correct implementation of memmove */ | |
| 1128 | |
| 1129 char *memmove(dst, src, n) | |
| 1130 char *dst; | |
| 1131 char *src; | |
| 1132 int n; | |
| 1133 { | |
| 1134 char *realdst = dst; | |
| 1135 if (n <= 0) | |
| 1136 return dst; | |
| 1137 if (src >= dst+n || dst >= src+n) | |
| 1138 return memcpy(dst, src, n); | |
| 1139 if (src > dst) { | |
| 1140 while (--n >= 0) | |
| 1141 *dst++ = *src++; | |
| 1142 } | |
| 1143 else if (src < dst) { | |
| 1144 src += n; | |
| 1145 dst += n; | |
| 1146 while (--n >= 0) | |
| 1147 *--dst = *--src; | |
| 1148 } | |
| 1149 return realdst; | |
| 1150 } | |
| 1151 | |
| 1152 #endif |
