1#include "pyobjc.h" 2#import "OC_PythonArray.h" 3 4static PyObject* mapTypes = NULL; 5 6@implementation OC_PythonArray 7 8+ (OC_PythonArray*)depythonifyObject:(PyObject*)object 9{ 10 Py_ssize_t i, len; 11 12 if (mapTypes == NULL) return NULL; 13 14 len = PyList_GET_SIZE(mapTypes); 15 16 for (i = 0; i < len; i++) { 17 PyObject* tp = PyList_GET_ITEM(mapTypes, i); 18 int r = PyObject_IsInstance(object, tp); 19 if (r == -1) { 20 return nil; 21 } 22 23 if (!r) continue; 24 25 /* Instance of this type should be pythonifyed as a sequence */ 26 return [[[OC_PythonArray alloc] initWithPythonObject:object] autorelease]; 27 } 28 29 return nil; 30} 31 32+ (id)depythonifyTable 33{ 34 NSObject* result; 35 36 PyObjC_BEGIN_WITH_GIL 37 38 if (mapTypes == NULL) { 39 mapTypes = PyList_New(0); 40 if (mapTypes == NULL) { 41 PyObjC_GIL_FORWARD_EXC(); 42 } 43 } 44 result = PyObjC_PythonToId(mapTypes); 45 if (result == NULL) { 46 PyObjC_GIL_FORWARD_EXC(); 47 } 48 49 PyObjC_END_WITH_GIL 50 51 return result; 52} 53 54+ (OC_PythonArray*)arrayWithPythonObject:(PyObject*)v 55{ 56 OC_PythonArray* res; 57 58 res = [[OC_PythonArray alloc] initWithPythonObject:v]; 59 [res autorelease]; 60 return res; 61} 62 63- (id)initWithPythonObject:(PyObject*)v 64{ 65 self = [super init]; 66 if (unlikely(self == nil)) return nil; 67 68 Py_INCREF(v); 69 Py_XDECREF(value); 70 value = v; 71 return self; 72} 73 74-(PyObject*)__pyobjc_PythonObject__ 75{ 76 Py_INCREF(value); 77 return value; 78} 79 80-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 81{ 82 *cookie = 0; 83 Py_INCREF(value); 84 return value; 85} 86 87-(BOOL)supportsWeakPointers { return YES; } 88 89-(oneway void)release 90{ 91 /* See comment in OC_PythonUnicode */ 92 PyObjC_BEGIN_WITH_GIL 93 [super release]; 94 PyObjC_END_WITH_GIL 95} 96 97-(void)dealloc 98{ 99 PyObjC_BEGIN_WITH_GIL 100 PyObjC_UnregisterObjCProxy(value, self); 101 Py_XDECREF(value); 102 103 PyObjC_END_WITH_GIL 104 105 [super dealloc]; 106} 107 108-(NSUInteger)count 109{ 110 Py_ssize_t result; 111 112 PyObjC_BEGIN_WITH_GIL 113 result = PySequence_Length(value); 114 115 PyObjC_END_WITH_GIL 116 117 if (result > INT_MAX) { 118 return INT_MAX; 119 } 120 121 return result; 122} 123 124-(id)objectAtIndex:(NSUInteger)idx 125{ 126 PyObject* v; 127 id result; 128 int err; 129 130 PyObjC_BEGIN_WITH_GIL 131 if (idx > PY_SSIZE_T_MAX) { 132 PyErr_SetString(PyExc_IndexError, "out of range"); 133 PyObjC_GIL_FORWARD_EXC(); 134 } 135 136 v = PySequence_GetItem(value, idx); 137 if (unlikely(v == NULL)) { 138 PyObjC_GIL_FORWARD_EXC(); 139 } 140 141 err = depythonify_c_value(@encode(id), v, &result); 142 if (unlikely(err == -1)) { 143 PyObjC_GIL_FORWARD_EXC(); 144 } 145 Py_CLEAR(v); 146 147 PyObjC_END_WITH_GIL 148 149 if (!result) { 150 result = [NSNull null]; 151 } 152 return result; 153} 154 155 156-(void)replaceObjectAtIndex:(NSUInteger)idx withObject:newValue 157{ 158 PyObject* v; 159 160 PyObjC_BEGIN_WITH_GIL 161 if (idx > PY_SSIZE_T_MAX) { 162 PyErr_SetString(PyExc_IndexError, "out of range"); 163 PyObjC_GIL_FORWARD_EXC(); 164 } 165 166 if (unlikely(newValue == [NSNull null])) { 167 Py_INCREF(Py_None); 168 v = Py_None; 169 170 } else { 171 v = PyObjC_IdToPython(newValue); 172 if (v == NULL) { 173 PyObjC_GIL_FORWARD_EXC(); 174 } 175 } 176 177 if (PySequence_SetItem(value, idx, v) < 0) { 178 Py_DECREF(v); 179 PyObjC_GIL_FORWARD_EXC(); 180 } 181 Py_DECREF(v); 182 183 PyObjC_END_WITH_GIL; 184} 185 186-(void)getObjects:(id*)buffer inRange:(NSRange)range 187{ 188 unsigned int i; 189 190 for (i = 0; i < range.length; i++) { 191 buffer[i] = [self objectAtIndex:i+range.location]; 192 } 193} 194 195-(void)addObject:(id)anObject 196{ 197 PyObject* v; 198 PyObject* w; 199 200 PyObjC_BEGIN_WITH_GIL 201 202 if (unlikely(anObject == [NSNull null])) { 203 Py_INCREF(Py_None); 204 v = Py_None; 205 206 } else { 207 v = PyObjC_IdToPython(anObject); 208 if (v == NULL) { 209 PyObjC_GIL_FORWARD_EXC(); 210 } 211 } 212 213 w = PyObject_CallMethod(value, "append", "O", v); 214 if (unlikely(w == NULL)) { 215 Py_DECREF(v); 216 PyObjC_GIL_FORWARD_EXC(); 217 } 218 Py_DECREF(v); 219 Py_DECREF(w); 220 221 PyObjC_END_WITH_GIL; 222} 223 224-(void)insertObject:(id)anObject atIndex:(NSUInteger)idx 225{ 226 Py_ssize_t theIndex; 227 PyObject* v; 228 PyObject* w; 229 230 if (idx > PY_SSIZE_T_MAX) { 231 PyObjC_BEGIN_WITH_GIL 232 PyErr_SetString(PyExc_IndexError, "No such index"); 233 PyObjC_GIL_FORWARD_EXC(); 234 PyObjC_END_WITH_GIL 235 } 236 theIndex = idx; 237 238 PyObjC_BEGIN_WITH_GIL 239 if (unlikely(anObject == [NSNull null])) { 240 Py_INCREF(Py_None); 241 v = Py_None; 242 } else { 243 v = PyObjC_IdToPython(anObject); 244 if (v == NULL) { 245 PyObjC_GIL_FORWARD_EXC(); 246 } 247 } 248 249 w = PyObject_CallMethod(value, "insert", Py_ARG_SIZE_T "O", theIndex, v); 250 if (unlikely(w == NULL)) { 251 Py_DECREF(v); 252 PyObjC_GIL_FORWARD_EXC(); 253 } 254 Py_DECREF(v); 255 Py_DECREF(w); 256 257 PyObjC_END_WITH_GIL; 258} 259 260-(void)removeLastObject 261{ 262 int r; 263 Py_ssize_t idx; 264 265 PyObjC_BEGIN_WITH_GIL 266 idx = PySequence_Length(value); 267 if (unlikely(idx == -1)) { 268 PyObjC_GIL_FORWARD_EXC(); 269 } 270 271 if (unlikely(idx == 0)) { 272 PyErr_SetString(PyExc_ValueError, "pop empty sequence"); 273 PyObjC_GIL_FORWARD_EXC(); 274 } 275 276 r = PySequence_DelItem(value, idx-1); 277 if (unlikely(r == -1)) { 278 PyObjC_GIL_FORWARD_EXC(); 279 } 280 281 PyObjC_END_WITH_GIL; 282} 283 284-(void)removeObjectAtIndex:(NSUInteger)idx 285{ 286 int r; 287 288 PyObjC_BEGIN_WITH_GIL 289 if (unlikely(idx > PY_SSIZE_T_MAX)) { 290 PyErr_SetString(PyExc_IndexError, "No such index"); 291 PyObjC_GIL_FORWARD_EXC(); 292 } 293 294 r = PySequence_DelItem(value, (Py_ssize_t)idx); 295 if (unlikely(r == -1)) { 296 PyObjC_GIL_FORWARD_EXC(); 297 } 298 299 PyObjC_END_WITH_GIL; 300} 301 302-(void)encodeWithCoder:(NSCoder*)coder 303{ 304 /* 305 * Instances of 'list' and 'tuple' are encoded directly, 306 * for other sequences use the generic pickle support code. 307 */ 308 if (PyTuple_CheckExact(value)) { 309 /* Encode tuples as type 4 with an explicit length, this allows 310 * us to create the tuple during decoding instead of having to 311 * create a temporary list. This is needed to get full support 312 * for encoding all datastructures, and is needed to pass the 313 * unittests for pickle in python2.7. 314 * 315 * NOTE: older versions used type 1 and no length. 316 */ 317 if ([coder allowsKeyedCoding]) { 318 [coder encodeInt32:4 forKey:@"pytype"]; 319 [coder encodeInt32:PyTuple_Size(value) forKey:@"pylength"]; 320 } else { 321 int v = 4; 322 [coder encodeValueOfObjCType:@encode(int) at:&v]; 323 v = (int)PyTuple_Size(value); 324 [coder encodeValueOfObjCType:@encode(int) at:&v]; 325 } 326 [super encodeWithCoder:coder]; 327 } else if (PyList_CheckExact(value)) { 328 if ([coder allowsKeyedCoding]) { 329 [coder encodeInt32:2 forKey:@"pytype"]; 330 } else { 331 int v = 2; 332 [coder encodeValueOfObjCType:@encode(int) at:&v]; 333 } 334 [super encodeWithCoder:coder]; 335 } else { 336 if ([coder allowsKeyedCoding]) { 337 [coder encodeInt32:3 forKey:@"pytype"]; 338 } else { 339 int v = 3; 340 [coder encodeValueOfObjCType:@encode(int) at:&v]; 341 } 342 PyObjC_encodeWithCoder(value, coder); 343 344 } 345} 346 347/* 348 * A basic implementation of -initWithObjects:count:. This method is needed 349 * to support NSCoding for Python sequences. 350 */ 351-(Class)classForCoder 352{ 353 return [OC_PythonArray class]; 354} 355 356-(id)initWithObjects:(NSObject**)objects count:(NSUInteger)count 357{ 358 NSUInteger i; 359 PyObjC_BEGIN_WITH_GIL 360 if (PyTuple_CheckExact(value) && (NSUInteger)PyTuple_Size(value) == count) { 361 for (i = 0; i < count; i++) { 362 PyObject* v; 363 if (objects[i] == [NSNull null]) { 364 v = Py_None; Py_INCREF(Py_None); 365 } else { 366 v = PyObjC_IdToPython(objects[i]); 367 } 368 if (v == NULL) { 369 PyObjC_GIL_FORWARD_EXC(); 370 } 371 if (PyTuple_GET_ITEM(value, i) != NULL) { 372 /* use temporary option to avoid race condition */ 373 PyObject* t = PyTuple_GET_ITEM(value, i); 374 PyTuple_SET_ITEM(value, i, NULL); 375 Py_DECREF(t); 376 } 377 PyTuple_SET_ITEM(value, i, v); 378 /* Don't DECREF v; SetItem stole a reference */ 379 } 380 } else { 381 382 for (i = 0; i < count; i++) { 383 PyObject* v; 384 int r; 385 if (objects[i] == [NSNull null]) { 386 v = Py_None; Py_INCREF(Py_None); 387 } else { 388 v = PyObjC_IdToPython(objects[i]); 389 } 390 if (v == NULL) { 391 PyObjC_GIL_FORWARD_EXC(); 392 } 393 r = PyList_Append(value, v); 394 if (r == -1) { 395 PyObjC_GIL_FORWARD_EXC(); 396 } 397 Py_DECREF(v); 398 } 399 } 400 401 PyObjC_END_WITH_GIL 402 return self; 403} 404 405/* 406 * Helper method for initWithCoder, needed to deal with 407 * recursive objects (e.g. o.value = o) 408 */ 409-(void)pyobjcSetValue:(NSObject*)other 410{ 411 PyObjC_BEGIN_WITH_GIL 412 PyObject* v = PyObjC_IdToPython(other); 413 Py_XDECREF(value); 414 value = v; 415 PyObjC_END_WITH_GIL 416} 417 418-(id)initWithCoder:(NSCoder*)coder 419{ 420 PyObject* t; 421 int code; 422 int size; 423 424 425 if ([coder allowsKeyedCoding]) { 426 code = [coder decodeInt32ForKey:@"pytype"]; 427 } else { 428 [coder decodeValueOfObjCType:@encode(int) at:&code]; 429 } 430 431 switch (code) { 432 case 4: 433 if ([coder allowsKeyedCoding]) { 434 size = [coder decodeInt32ForKey:@"pylength"]; 435 } else { 436 [coder decodeValueOfObjCType:@encode(int) at:&size]; 437 } 438 439 PyObjC_BEGIN_WITH_GIL 440 value = PyTuple_New(size); 441 if (value == NULL){ 442 PyObjC_GIL_FORWARD_EXC(); 443 } 444 PyObjC_END_WITH_GIL 445 [super initWithCoder:coder]; 446 return self; 447 448 449 case 1: 450 /* This code was created by some previous versions of PyObjC 451 * (before 2.2) and is kept around for backward compatibilty. 452 */ 453 PyObjC_BEGIN_WITH_GIL 454 value = PyList_New(0); 455 if (value == NULL){ 456 PyObjC_GIL_FORWARD_EXC(); 457 } 458 PyObjC_END_WITH_GIL 459 460 [super initWithCoder:coder]; 461 PyObjC_BEGIN_WITH_GIL 462 t = value; 463 value = PyList_AsTuple(t); 464 Py_DECREF(t); 465 if (value == NULL) { 466 PyObjC_GIL_FORWARD_EXC(); 467 } 468 PyObjC_END_WITH_GIL 469 return self; 470 471 case 2: 472 PyObjC_BEGIN_WITH_GIL 473 value = PyList_New(0); 474 if (value == NULL) { 475 PyObjC_GIL_FORWARD_EXC(); 476 } 477 PyObjC_END_WITH_GIL 478 [super initWithCoder:coder]; 479 return self; 480 481 case 3: 482 PyObjC_BEGIN_WITH_GIL 483 value = PyList_New(0); 484 if (value == NULL) { 485 PyObjC_GIL_FORWARD_EXC(); 486 } 487 PyObjC_END_WITH_GIL 488 489 if (PyObjC_Decoder != NULL) { 490 PyObjC_BEGIN_WITH_GIL 491 PyObject* cdr = PyObjC_IdToPython(coder); 492 if (cdr == NULL) { 493 PyObjC_GIL_FORWARD_EXC(); 494 } 495 496 PyObject* setValue; 497 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 498 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 499 500 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 501 Py_DECREF(cdr); 502 Py_DECREF(setValue); 503 Py_DECREF(selfAsPython); 504 505 if (v == NULL) { 506 PyObjC_GIL_FORWARD_EXC(); 507 } 508 509 Py_XDECREF(value); 510 value = v; 511 512 NSObject* proxy = PyObjC_FindObjCProxy(value); 513 if (proxy == NULL) { 514 PyObjC_RegisterObjCProxy(value, self); 515 } else { 516 [proxy retain]; 517 [self release]; 518 self = (OC_PythonArray*)proxy; 519 } 520 521 522 PyObjC_END_WITH_GIL 523 524 return self; 525 } 526 } 527 528 [NSException raise:NSInvalidArgumentException 529 format:@"decoding Python objects is not supported"]; 530 [self release]; 531 return nil; 532} 533 534 535-(id)copyWithZone:(NSZone*)zone 536{ 537 if (PyObjC_CopyFunc) { 538 PyObjC_BEGIN_WITH_GIL 539 PyObject* copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc, 540 value, NULL); 541 542 if (copy == NULL) { 543 PyObjC_GIL_FORWARD_EXC(); 544 } 545 546 NSObject* result = PyObjC_PythonToId(copy); 547 Py_DECREF(copy); 548 549 if (PyErr_Occurred()) { 550 PyObjC_GIL_FORWARD_EXC(); 551 } 552 553 [result retain]; 554 555 PyObjC_GIL_RETURN(result); 556 557 PyObjC_END_WITH_GIL 558 } else { 559 return [super copyWithZone:zone]; 560 } 561} 562 563-(id)mutableCopyWithZone:(NSZone*)zone 564{ 565 if (PyObjC_CopyFunc) { 566 PyObjC_BEGIN_WITH_GIL 567 PyObject* copy = PySequence_List(value); 568 if (copy == NULL) { 569 PyObjC_GIL_FORWARD_EXC(); 570 } 571 572 NSObject* result = PyObjC_PythonToId(copy); 573 Py_DECREF(copy); 574 575 if (PyErr_Occurred()) { 576 PyObjC_GIL_FORWARD_EXC(); 577 } 578 579 [result retain]; 580 PyObjC_GIL_RETURN(result); 581 582 PyObjC_END_WITH_GIL 583 } else { 584 return [super mutableCopyWithZone:zone]; 585 } 586} 587@end /* implementation OC_PythonArray */ 588