1#include "pyobjc.h" 2 3@implementation OC_PythonNumber 4 5+ (instancetype)numberWithPythonObject:(PyObject*)v 6{ 7 OC_PythonNumber* res; 8 9 res = [[OC_PythonNumber alloc] initWithPythonObject:v]; 10 [res autorelease]; 11 return res; 12} 13 14- (id)initWithPythonObject:(PyObject*)v 15{ 16 self = [super init]; 17 if (unlikely(self == nil)) return nil; 18 19 Py_INCREF(v); 20 Py_XDECREF(value); 21 value = v; 22 return self; 23} 24 25-(PyObject*)__pyobjc_PythonObject__ 26{ 27 Py_INCREF(value); 28 return value; 29} 30 31-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 32{ 33 *cookie = 0; 34 Py_INCREF(value); 35 return value; 36} 37 38-(BOOL)supportsWeakPointers { return YES; } 39 40-(oneway void)release 41{ 42 /* See comment in OC_PythonUnicode */ 43 PyObjC_BEGIN_WITH_GIL 44 [super release]; 45 PyObjC_END_WITH_GIL 46} 47 48-(void)dealloc 49{ 50 PyObjC_BEGIN_WITH_GIL 51 PyObjC_UnregisterObjCProxy(value, self); 52 Py_XDECREF(value); 53 54 PyObjC_END_WITH_GIL 55 56 [super dealloc]; 57} 58 59-(const char*)objCType 60{ 61 PyObjC_BEGIN_WITH_GIL 62 if (PyBool_Check(value)) { 63 PyObjC_GIL_RETURN(@encode(BOOL)); 64 } else if (PyFloat_Check(value)) { 65 PyObjC_GIL_RETURN(@encode(double)); 66#if PY_MAJOR_VERSION == 2 67 } else if (PyInt_Check(value)) { 68 PyObjC_GIL_RETURN(@encode(long)); 69#endif 70 } else if (PyLong_Check(value)) { 71 PyObjC_GIL_RETURN(@encode(long long)); 72 } 73 PyObjC_END_WITH_GIL 74 [NSException raise:NSInvalidArgumentException 75 format:@"Cannot determine objective-C type of this number"]; 76 return @encode(char); 77} 78 79-(void)getValue:(void*)buffer 80{ 81 const char* encoded = [self objCType]; 82 int r; 83 PyObjC_BEGIN_WITH_GIL 84 r = depythonify_c_value(encoded, value, buffer); 85 if (r == -1) { 86 PyObjC_GIL_FORWARD_EXC(); 87 } 88 PyObjC_END_WITH_GIL 89} 90 91/* TODO: 92-(BOOL)isEqualToValue:(NSValue*)other 93 // convert other to Python, then use python's comparison operators to 94 // check for equality. 95} 96*/ 97 98 99-(BOOL)boolValue 100{ 101 return (BOOL)PyObject_IsTrue(value); 102} 103 104-(char)charValue 105{ 106 return (char)[self longLongValue]; 107} 108 109-(NSDecimal)decimalValue 110{ 111 NSDecimal result; 112 NSDecimalNumber* num; 113 114 unsigned long long mantissa = 0; 115 unsigned short exponent = 0; 116 BOOL negative = NO; 117 118 PyObjC_BEGIN_WITH_GIL 119#if PY_MAJOR_VERSION == 2 120 if (PyInt_Check(value)) { 121 long lng = PyInt_AsLong(value); 122 if (lng < 0) { 123 mantissa = -lng; 124 exponent = 0; 125 negative = YES; 126 } else { 127 mantissa = lng; 128 exponent = 0; 129 negative = NO; 130 } 131 132 } else 133#endif 134 if (PyLong_Check(value)) { 135 mantissa = PyLong_AsUnsignedLongLong(value); 136 if (PyErr_Occurred()) { 137 long long lng; 138 PyErr_Clear(); 139 lng = PyLong_AsLongLong(value); 140 if (PyErr_Occurred()) { 141 PyObjC_GIL_FORWARD_EXC(); 142 } 143 144 if (lng < 0) { 145 mantissa = -lng; 146 exponent = 0; 147 negative = YES; 148 } else { 149 mantissa = lng; 150 exponent = 0; 151 negative = NO; 152 } 153 } else { 154 exponent = 0; 155 negative = NO; 156 } 157 158 } else if (PyFloat_Check(value)) { 159 PyObject* strVal = PyObject_Repr(value); 160 PyObject* uniVal = NULL; 161 162 if (strVal == NULL) { 163 PyObjC_GIL_FORWARD_EXC(); 164 } 165 166 uniVal = PyUnicode_FromEncodedObject(strVal, "ascii", "strict"); 167 Py_DECREF(strVal); 168 if (uniVal == NULL) { 169 PyObjC_GIL_FORWARD_EXC(); 170 } 171 172 NSString* stringVal = PyObjC_PythonToId(uniVal); 173 Py_DECREF(uniVal); 174 175 num = [[NSDecimalNumber alloc] initWithString:stringVal]; 176 result = [num decimalValue]; 177 [num release]; 178 PyObjC_GIL_RETURN(result); 179 180 } else { 181 PyErr_Format(PyExc_TypeError, "cannot convert object of %s to NSDecimal", 182 Py_TYPE(value)->tp_name); 183 PyObjC_GIL_FORWARD_EXC(); 184 } 185 186 PyObjC_END_WITH_GIL 187 188 189 190 num = [[NSDecimalNumber alloc] 191 initWithMantissa:mantissa 192 exponent:exponent 193 isNegative:negative]; 194 result = [num decimalValue]; 195 [num release]; 196 return result; 197} 198 199-(double)doubleValue 200{ 201 PyObjC_BEGIN_WITH_GIL 202 if (PyFloat_Check(value)) { 203 PyObjC_GIL_RETURN(PyFloat_AsDouble(value)); 204 } 205 PyObjC_END_WITH_GIL 206 return (double)[self longLongValue]; 207} 208 209-(float)floatValue 210{ 211 return (float)[self doubleValue]; 212} 213 214-(NSInteger)integerValue 215{ 216 return (NSInteger)[self longLongValue]; 217} 218 219-(int)intValue 220{ 221 return (int)[self longLongValue]; 222} 223 224 225-(long)longValue 226{ 227 return (long)[self longLongValue]; 228} 229 230-(short)shortValue 231{ 232 return (short)[self longLongValue]; 233} 234 235 236-(unsigned char)unsignedCharValue 237{ 238 return (unsigned char)[self unsignedLongLongValue]; 239} 240-(NSUInteger)unsignedIntegerValue 241{ 242 return (NSUInteger)[self unsignedLongLongValue]; 243} 244-(unsigned int)unsignedIntValue 245{ 246 return (unsigned int)[self unsignedLongLongValue]; 247} 248-(unsigned long)unsignedLongValue 249{ 250 return (unsigned long)[self unsignedLongLongValue]; 251} 252-(unsigned short)unsignedShortValue 253{ 254 return (unsigned short)[self unsignedLongLongValue]; 255} 256 257-(long long)longLongValue 258{ 259 long long result; 260 261 PyObjC_BEGIN_WITH_GIL 262#if PY_MAJOR_VERSION == 2 263 if (PyInt_Check(value)) { 264 result = PyInt_AsLong(value); 265 PyObjC_GIL_RETURN(result); 266 } else 267#endif 268 if (PyFloat_Check(value)) { 269 result = (long long)PyFloat_AsDouble(value); 270 PyObjC_GIL_RETURN(result); 271 } else if (PyLong_Check(value)) { 272 result = PyLong_AsUnsignedLongLongMask(value); 273 PyObjC_GIL_RETURN(result); 274 } 275 PyObjC_END_WITH_GIL 276 277 [NSException raise:NSInvalidArgumentException 278 format:@"Cannot determine objective-C type of this number"]; 279 return -1; 280} 281 282-(unsigned long long)unsignedLongLongValue 283{ 284 unsigned long long result; 285 286 PyObjC_BEGIN_WITH_GIL 287 if (PyLong_Check(value)) { 288 result = PyLong_AsUnsignedLongLongMask(value); 289 PyObjC_GIL_RETURN(result); 290#if PY_MAJOR_VERSION == 2 291 } else if (PyInt_Check(value)) { 292 result = (unsigned long long)PyInt_AsLong(value); 293 PyObjC_GIL_RETURN(result); 294#endif 295 } else if (PyFloat_Check(value)) { 296 double temp = PyFloat_AsDouble(value); 297 if (temp < 0) { 298 /* Conversion of negative numbers to 299 * unsigned long long is undefined behaviour, 300 * the code below seems to get the behaviour 301 * we'd like: casting to unsigned long long 302 * behaves simular to casting a signed integer 303 * to undefined. 304 */ 305 long long t = (long long)temp; 306 result = (unsigned long long)t; 307 } else { 308 result = (unsigned long long)temp; 309 } 310 PyObjC_GIL_RETURN(result); 311 } 312 PyObjC_END_WITH_GIL 313 314 [NSException raise:NSInvalidArgumentException 315 format:@"Cannot determine objective-C type of this number"]; 316 return -1; 317} 318 319-(NSString*)description 320{ 321 return [self stringValue]; 322} 323 324-(NSString*)descriptionWithLocale:(NSObject*)locale 325{ 326 /* FIXME: use locale information to format */ 327 /* TODO: compare with regular NSNumber */ 328 (void)locale; 329 return [self stringValue]; 330} 331 332-(NSString*)stringValue 333{ 334 PyObject* repr; 335 NSObject* result = nil; 336 337 PyObjC_BEGIN_WITH_GIL 338 repr = PyObject_Repr(value); 339 if (repr == NULL) { 340 PyObjC_GIL_FORWARD_EXC(); 341 } 342 343#if PY_MAJOR_VERSION == 2 344 PyObject* uniVal = PyUnicode_FromEncodedObject(repr, "ascii", "strict"); 345 Py_DECREF(repr); 346 if (PyErr_Occurred()) { 347 PyObjC_GIL_FORWARD_EXC(); 348 } 349 350 result = PyObjC_PythonToId(uniVal); 351 Py_DECREF(uniVal); 352 if (PyErr_Occurred()) { 353 PyObjC_GIL_FORWARD_EXC(); 354 } 355#else 356 result = PyObjC_PythonToId(repr); 357 Py_DECREF(repr); 358 if (PyErr_Occurred()) { 359 PyObjC_GIL_FORWARD_EXC(); 360 } 361#endif 362 363 364 PyObjC_END_WITH_GIL 365 return (NSString*)result; 366} 367 368/* NSCoding support */ 369 370- (void)encodeWithCoder:(NSCoder*)coder 371{ 372 int use_super = 0; 373 374 PyObjC_BEGIN_WITH_GIL 375 if (PyFloat_CheckExact(value)) { 376 /* Float is a C double and can be roundtripped using 377 * NSNumber. 378 */ 379 use_super = 1; 380 381#if PY_MAJOR_VERSION == 2 382 } else if (PyInt_CheckExact(value)) { 383 /* Int is a C double and can be roundtripped using 384 * NSNumber. 385 */ 386 use_super = 1; 387#endif 388 } else if (PyLong_CheckExact(value)) { 389 /* Long object that fits in a long long */ 390 (void)PyLong_AsLongLong(value); 391 if (PyErr_Occurred()) { 392 PyErr_Clear(); 393 use_super = 0; 394 } else { 395 use_super = 1; 396 } 397 } 398 PyObjC_END_WITH_GIL 399 400 if (use_super) { 401 [super encodeWithCoder:coder]; 402 } else { 403 PyObjC_encodeWithCoder(value, coder); 404 } 405} 406 407 408/* 409 * Helper method for initWithCoder, needed to deal with 410 * recursive objects (e.g. o.value = o) 411 */ 412-(void)pyobjcSetValue:(NSObject*)other 413{ 414 PyObjC_BEGIN_WITH_GIL 415 PyObject* v = PyObjC_IdToPython(other); 416 Py_XDECREF(value); 417 value = v; 418 PyObjC_END_WITH_GIL 419} 420 421- (id)initWithCoder:(NSCoder*)coder 422{ 423 if (PyObjC_Decoder != NULL) { 424 PyObjC_BEGIN_WITH_GIL 425 PyObject* cdr = PyObjC_IdToPython(coder); 426 if (cdr == NULL) { 427 PyObjC_GIL_FORWARD_EXC(); 428 } 429 430 PyObject* setValue; 431 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 432 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 433 434 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 435 Py_DECREF(cdr); 436 Py_DECREF(setValue); 437 Py_DECREF(selfAsPython); 438 439 if (v == NULL) { 440 PyObjC_GIL_FORWARD_EXC(); 441 } 442 443 Py_XDECREF(value); 444 value = v; 445 446 NSObject* proxy = PyObjC_FindObjCProxy(value); 447 if (proxy == NULL) { 448 PyObjC_RegisterObjCProxy(value, self); 449 } else { 450 [self release]; 451 [proxy retain]; 452 self = (OC_PythonNumber*)proxy; 453 } 454 455 456 PyObjC_END_WITH_GIL 457 458 return self; 459 460 } else { 461 [NSException raise:NSInvalidArgumentException 462 format:@"decoding Python objects is not supported"]; 463 return nil; 464 465 } 466} 467 468- (NSComparisonResult)compare:(NSNumber *)aNumber 469{ 470 /* Rely on -[NSNumber compare:] when the other value 471 * is a number and we're not a python int that doesn't 472 * fit into a 'long long'. 473 * 474 * In all other cases use Python's comparison semantics. 475 */ 476 if ([aNumber isKindOfClass:[NSNumber class]] && ![aNumber isMemberOfClass: [OC_PythonNumber class]]) { 477 if (PyLong_Check(value)) { 478 PY_LONG_LONG r; 479 r = PyLong_AsLongLong(value); 480 if (r == -1 && PyErr_Occurred()) { 481 PyErr_Print(); 482 PyErr_Clear(); 483 } else { 484 return [super compare:aNumber]; 485 } 486 } else { 487 return [super compare:aNumber]; 488 } 489 } 490 491 PyObjC_BEGIN_WITH_GIL 492 PyObject* other = PyObjC_IdToPython(aNumber); 493 if (other == NULL) { 494 PyObjC_GIL_FORWARD_EXC(); 495 } 496 497 int r; 498 int ok = PyObject_Cmp(value, other, &r); 499 Py_DECREF(other); 500 if (ok == -1) { 501 PyObjC_GIL_FORWARD_EXC(); 502 } 503 504 if (r < 0) { 505 PyObjC_GIL_RETURN(NSOrderedAscending); 506 } else if (r > 0) { 507 PyObjC_GIL_RETURN(NSOrderedDescending); 508 } else { 509 PyObjC_GIL_RETURN(NSOrderedSame); 510 } 511 512 513 PyObjC_END_WITH_GIL 514} 515 516 517#define COMPARE_METHOD(NAME, OPERATOR) \ 518 -(BOOL)NAME:(NSObject*)aNumber \ 519{ \ 520 PyObjC_BEGIN_WITH_GIL \ 521 PyObject* other = PyObjC_IdToPython(aNumber); \ 522 if (other == NULL) { \ 523 PyObjC_GIL_FORWARD_EXC(); \ 524 } \ 525 \ 526 int r = PyObject_RichCompareBool(value, other, OPERATOR); \ 527 Py_DECREF(other); \ 528 if (r == -1) { \ 529 PyObjC_GIL_FORWARD_EXC(); \ 530 } \ 531 \ 532 if (r) { \ 533 PyObjC_GIL_RETURN(YES); \ 534 } else { \ 535 PyObjC_GIL_RETURN(NO); \ 536 } \ 537 \ 538 PyObjC_END_WITH_GIL \ 539} 540 541COMPARE_METHOD(isEqualTo, Py_EQ) 542COMPARE_METHOD(isNotEqualTo, Py_NE) 543COMPARE_METHOD(isGreaterThan, Py_GT) 544COMPARE_METHOD(isGreaterThanOrEqualTo, Py_GE) 545COMPARE_METHOD(isLessThan, Py_LT) 546COMPARE_METHOD(isLessThanOrEqualTo, Py_LE) 547 548 549-(BOOL)isEqualToNumber:(NSNumber*)aNumber 550{ 551 return [self isEqualTo:aNumber]; 552} 553 554 555 556 557#if 1 558 559-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver 560{ 561 (void)archiver; 562 return (NSObject*)self; 563} 564 565-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver 566{ 567 (void)archiver; 568 return (NSObject*)self; 569} 570 571-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver 572{ 573 (void)archiver; 574 return (NSObject*)self; 575} 576 577-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver 578{ 579 (void)archiver; 580 return (NSObject*)self; 581} 582 583-(Class)classForArchiver 584{ 585 PyObjC_BEGIN_WITH_GIL 586 if (PyFloat_CheckExact(value)) { 587 /* Float is a C double and can be roundtripped using 588 * NSNumber. 589 */ 590 PyObjC_GIL_RETURN([NSNumber class]); 591 592#if PY_MAJOR_VERSION == 2 593 } else if (PyInt_CheckExact(value)) { 594 /* Int is a C double and can be roundtripped using 595 * NSNumber. 596 */ 597 PyObjC_GIL_RETURN([NSNumber class]); 598#endif 599 } else if (PyLong_CheckExact(value)) { 600 /* Long object that fits in a long long */ 601 (void)PyLong_AsLongLong(value); 602 if (PyErr_Occurred()) { 603 PyErr_Clear(); 604 PyObjC_GIL_RETURN([OC_PythonNumber class]); 605 } else { 606 PyObjC_GIL_RETURN([NSNumber class]); 607 } 608 609 } else { 610 PyObjC_GIL_RETURN([OC_PythonNumber class]); 611 } 612 PyObjC_END_WITH_GIL 613} 614 615-(Class)classForKeyedArchiver 616{ 617 return [self classForArchiver]; 618} 619 620+(Class)classForUnarchiver 621{ 622 return [OC_PythonNumber class]; 623} 624 625+(Class)classForKeyedUnarchiver 626{ 627 return [OC_PythonNumber class]; 628} 629 630-(Class)classForCoder 631{ 632 return [self classForArchiver]; 633} 634 635-(Class)classForPortCoder 636{ 637 return [self classForArchiver]; 638} 639 640-(id)copy 641{ 642 return [self copyWithZone:0]; 643} 644 645-(id)copyWithZone:(NSZone*)zone 646{ 647 (void)zone; 648 [self retain]; 649 return self; 650} 651 652 653#endif 654@end 655