1#include "pyobjc.h" 2 3 4static PyObject* mapTypes = NULL; 5 6 7@implementation OC_PythonSet 8 9+ (instancetype)depythonifyObject:(PyObject*)object 10{ 11 Py_ssize_t i, len; 12 13 if (mapTypes == NULL) return NULL; 14 15 len = PyList_GET_SIZE(mapTypes); 16 17 for (i = 0; i < len; i++) { 18 PyObject* tp = PyList_GET_ITEM(mapTypes, i); 19 int r = PyObject_IsInstance(object, tp); 20 if (r == -1) { 21 return NULL; 22 } 23 24 if (!r) continue; 25 26 /* Instance of this type should be pythonifyed as a sequence */ 27 return [OC_PythonSet setWithPythonObject:object]; 28 } 29 30 return NULL; 31} 32 33+ (id)depythonifyTable 34{ 35 NSObject* result; 36 37 PyObjC_BEGIN_WITH_GIL 38 39 if (mapTypes == NULL) { 40 mapTypes = PyList_New(0); 41 if (mapTypes == NULL) { 42 PyObjC_GIL_FORWARD_EXC(); 43 } 44 } 45 result = PyObjC_PythonToId(mapTypes); 46 if (result == NULL) { 47 PyObjC_GIL_FORWARD_EXC(); 48 } 49 50 PyObjC_END_WITH_GIL 51 52 return result; 53} 54 55+ (instancetype)setWithPythonObject:(PyObject*)v 56{ 57 OC_PythonSet* res; 58 59 res = [[OC_PythonSet alloc] initWithPythonObject:v]; 60 [res autorelease]; 61 return res; 62} 63 64- (id)initWithPythonObject:(PyObject*)v 65{ 66 self = [super init]; 67 if (unlikely(self == nil)) return nil; 68 69 Py_INCREF(v); 70 Py_XDECREF(value); 71 value = v; 72 return self; 73} 74 75-(PyObject*)__pyobjc_PythonObject__ 76{ 77 Py_INCREF(value); 78 return value; 79} 80 81-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 82{ 83 *cookie = 0; 84 Py_INCREF(value); 85 return value; 86} 87 88-(BOOL)supportsWeakPointers { return YES; } 89 90-(oneway void)release 91{ 92 /* See comment in OC_PythonUnicode */ 93 PyObjC_BEGIN_WITH_GIL 94 [super release]; 95 PyObjC_END_WITH_GIL 96} 97 98-(void)dealloc 99{ 100 PyObjC_BEGIN_WITH_GIL 101 PyObjC_UnregisterObjCProxy(value, self); 102 Py_XDECREF(value); 103 104 PyObjC_END_WITH_GIL 105 106 [super dealloc]; 107} 108 109 110/* NSCoding support */ 111 112-(Class)classForCoder 113{ 114 return [OC_PythonSet class]; 115} 116 117 118- (void)encodeWithCoder:(NSCoder*)coder 119{ 120 PyObjC_encodeWithCoder(value, coder); 121} 122 123 124/* 125 * Helper method for initWithCoder, needed to deal with 126 * recursive objects (e.g. o.value = o) 127 */ 128-(void)pyobjcSetValue:(NSObject*)other 129{ 130 PyObjC_BEGIN_WITH_GIL 131 PyObject* v = PyObjC_IdToPython(other); 132 Py_XDECREF(value); 133 value = v; 134 PyObjC_END_WITH_GIL 135} 136 137- (id)initWithCoder:(NSCoder*)coder 138{ 139 if (PyObjC_Decoder != NULL) { 140 PyObjC_BEGIN_WITH_GIL 141 PyObject* cdr = PyObjC_IdToPython(coder); 142 if (cdr == NULL) { 143 PyObjC_GIL_FORWARD_EXC(); 144 } 145 146 PyObject* setValue; 147 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 148 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 149 150 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 151 Py_DECREF(cdr); 152 Py_DECREF(setValue); 153 Py_DECREF(selfAsPython); 154 155 if (v == NULL) { 156 PyObjC_GIL_FORWARD_EXC(); 157 } 158 159 Py_XDECREF(value); 160 value = v; 161 162 NSObject* proxy = PyObjC_FindObjCProxy(value); 163 if (proxy == NULL) { 164 PyObjC_RegisterObjCProxy(value, self); 165 } else { 166 [self release]; 167 [proxy retain]; 168 self = (OC_PythonSet*)proxy; 169 } 170 171 172 PyObjC_END_WITH_GIL 173 174 return self; 175 176 } else { 177 [NSException raise:NSInvalidArgumentException 178 format:@"decoding Python objects is not supported"]; 179 return nil; 180 181 } 182} 183 184 185/* 186 * Implementation of the NSMutableSet interface 187 */ 188-(id)copyWithZone:(NSZone*)zone 189{ 190 (void)zone; 191 if (PyObjC_CopyFunc != NULL) { 192 PyObjC_BEGIN_WITH_GIL 193 PyObject* tmp = PyObject_CallFunction(PyObjC_CopyFunc, "O", value); 194 if (tmp == NULL) { 195 PyObjC_GIL_FORWARD_EXC(); 196 } 197 198 NSObject* result = PyObjC_PythonToId(tmp); 199 Py_DECREF(tmp); 200 if (PyErr_Occurred()) { 201 PyObjC_GIL_FORWARD_EXC(); 202 } 203 204 [result retain]; 205 PyObjC_GIL_RETURN(result); 206 207 PyObjC_END_WITH_GIL 208 209 } else { 210 [NSException raise:NSInvalidArgumentException 211 format:@"cannot copy python set"]; 212 return nil; 213 } 214} 215 216-(id)mutableCopyWithZone:(NSZone*)zone 217{ 218 (void)zone; 219 PyObjC_BEGIN_WITH_GIL 220 221 PyObject* tmp = PySet_New(value); 222 if (tmp == NULL) { 223 PyObjC_GIL_FORWARD_EXC(); 224 } 225 226 NSObject* result = PyObjC_PythonToId(tmp); 227 Py_DECREF(tmp); 228 if (PyErr_Occurred()) { 229 PyObjC_GIL_FORWARD_EXC(); 230 } 231 232 [result retain]; 233 PyObjC_GIL_RETURN(result); 234 235 PyObjC_END_WITH_GIL 236} 237 238-(NSArray*)allObjects 239{ 240 PyObjC_BEGIN_WITH_GIL 241 PyObject* tmp = PySequence_List(value); 242 if (tmp == NULL) { 243 PyObjC_GIL_FORWARD_EXC(); 244 } 245 246 NSArray* result = (NSArray*)PyObjC_PythonToId(tmp); 247 Py_DECREF(tmp); 248 if (PyErr_Occurred()) { 249 PyObjC_GIL_FORWARD_EXC(); 250 } 251 252 PyObjC_GIL_RETURN(result); 253 254 PyObjC_END_WITH_GIL 255} 256 257-(NSObject*)anyObject 258{ 259 PyObjC_BEGIN_WITH_GIL 260 if (PySet_Size(value) == 0) { 261 PyObjC_GIL_RETURN(nil); 262 } 263 264 PyObject* tmp = PyObject_GetIter(value); 265 if (tmp == NULL) { 266 PyObjC_GIL_FORWARD_EXC(); 267 } 268 269 PyObject* v = PyIter_Next(tmp); 270 Py_DECREF(tmp); 271 if (v == NULL) { 272 PyObjC_GIL_FORWARD_EXC(); 273 } 274 275 NSObject* result = PyObjC_PythonToId(v); 276 Py_DECREF(v); 277 if (PyErr_Occurred()) { 278 PyObjC_GIL_FORWARD_EXC(); 279 } 280 281 PyObjC_GIL_RETURN(result); 282 283 PyObjC_END_WITH_GIL 284} 285 286-(BOOL)containsObject:(id)anObject 287{ 288 PyObjC_BEGIN_WITH_GIL 289 PyObject* tmp = PyObjC_IdToPython(anObject); 290 if (tmp == NULL) { 291 PyObjC_GIL_FORWARD_EXC(); 292 } 293 294 int r = PySequence_Contains(value, tmp); 295 Py_DECREF(tmp); 296 if (r == -1) { 297 PyObjC_GIL_FORWARD_EXC(); 298 } 299 300 301 if (r) { 302 PyObjC_GIL_RETURN(YES); 303 } else { 304 PyObjC_GIL_RETURN(NO); 305 } 306 PyObjC_END_WITH_GIL 307} 308 309-(NSUInteger)count 310{ 311 PyObjC_BEGIN_WITH_GIL 312 Py_ssize_t result = PySequence_Size(value); 313 if (result == -1) { 314 PyObjC_GIL_FORWARD_EXC(); 315 } 316 317 PyObjC_GIL_RETURN((NSUInteger)result); 318 PyObjC_END_WITH_GIL 319} 320 321-(NSEnumerator*)objectEnumerator 322{ 323 PyObjC_BEGIN_WITH_GIL 324 PyObject* tmp = PyObject_GetIter(value); 325 if (tmp == NULL) { 326 PyObjC_GIL_FORWARD_EXC(); 327 } 328 329 NSEnumerator* result = [OC_PythonEnumerator enumeratorWithPythonObject:tmp]; 330 Py_DECREF(tmp); 331 332 PyObjC_GIL_RETURN(result); 333 334 PyObjC_END_WITH_GIL 335} 336 337/* It seems impossible to create an efficient implementation of this method, 338 * iteration is basicly the only way to fetch the requested object 339 * 340 * XXX: this means we should implement more of NS(Mutable)Set interface, 341 * that's a lot more efficient than iterating over and over again. 342 * 343 */ 344-(id)member:(id)anObject 345{ 346 PyObjC_BEGIN_WITH_GIL 347 PyObject* tmpMember = PyObjC_IdToPython(anObject); 348 if (tmpMember == NULL) { 349 PyObjC_GIL_FORWARD_EXC(); 350 } 351 352 int r = PySequence_Contains(value, tmpMember); 353 if (r == -1) { 354 Py_DECREF(tmpMember); 355 PyObjC_GIL_FORWARD_EXC(); 356 } 357 358 if (!r) { 359 Py_DECREF(tmpMember); 360 PyObjC_GIL_RETURN(nil); 361 } 362 363 364 /* This sucks, we have to iterate over the contents of the 365 * set to find the object we need... 366 */ 367 PyObject* tmp = PyObject_GetIter(value); 368 if (tmp == NULL) { 369 PyObjC_GIL_FORWARD_EXC(); 370 } 371 372 PyObject* v; 373 374 while ((v = PyIter_Next(tmp)) != NULL) { 375 r = PyObject_RichCompareBool(v, tmpMember, Py_EQ); 376 if (r == -1) { 377 Py_DECREF(tmp); 378 Py_DECREF(tmpMember); 379 PyObjC_GIL_FORWARD_EXC(); 380 } 381 382 if (r) { 383 /* Found the object */ 384 Py_DECREF(tmp); 385 Py_DECREF(tmpMember); 386 387 NSObject* result = PyObjC_PythonToId(v); 388 if (PyErr_Occurred()) { 389 PyObjC_GIL_FORWARD_EXC(); 390 } 391 PyObjC_GIL_RETURN(result); 392 } 393 } 394 395 Py_DECREF(tmp); 396 Py_DECREF(tmpMember); 397 PyObjC_GIL_RETURN(nil); 398 399 400 PyObjC_END_WITH_GIL 401} 402 403-(void)removeAllObjects 404{ 405 PyObjC_BEGIN_WITH_GIL 406 if (PyFrozenSet_CheckExact(value)) { 407 PyErr_SetString(PyExc_TypeError, 408 "Cannot mutate a frozenstring"); 409 PyObjC_GIL_FORWARD_EXC(); 410 } 411 412 if (PyAnySet_Check(value)) { 413 int r = PySet_Clear(value);\ 414 if (r == -1) { 415 PyObjC_GIL_FORWARD_EXC(); 416 } 417 } else { 418 /* Assume an object that conforms to 419 * the set interface 420 */ 421 PyObject* r; 422 423 r = PyObject_CallMethod(value, "clear", NULL); 424 if (r == NULL) { 425 PyObjC_GIL_FORWARD_EXC(); 426 } 427 Py_DECREF(r); 428 } 429 PyObjC_END_WITH_GIL 430} 431 432-(void)removeObject:(id)anObject 433{ 434 PyObjC_BEGIN_WITH_GIL 435 PyObject* tmp = PyObjC_IdToPython(anObject); 436 if (tmp == NULL) { 437 PyObjC_GIL_FORWARD_EXC(); 438 } 439 440 if (PyFrozenSet_CheckExact(value)) { 441 PyErr_SetString(PyExc_TypeError, 442 "Cannot mutate a frozenstring"); 443 PyObjC_GIL_FORWARD_EXC(); 444 } 445 446 if (PyAnySet_Check(value)) { 447 int r = PySet_Discard(value, tmp); 448 Py_DECREF(tmp); 449 if (r == -1) { 450 PyObjC_GIL_FORWARD_EXC(); 451 } 452 453 } else { 454 PyObject* r; 455 456 r = PyObject_CallMethod(value, "discard", "O", tmp); 457 Py_DECREF(tmp); 458 if (r == NULL) { 459 PyObjC_GIL_FORWARD_EXC(); 460 } 461 Py_DECREF(r); 462 } 463 464 PyObjC_END_WITH_GIL 465} 466 467-(void)addObject:(id)anObject 468{ 469 PyObjC_BEGIN_WITH_GIL 470 PyObject* tmp = PyObjC_IdToPython(anObject); 471 if (tmp == NULL) { 472 PyObjC_GIL_FORWARD_EXC(); 473 } 474 475 if (PyFrozenSet_CheckExact(value)) { 476 PyErr_SetString(PyExc_TypeError, 477 "Cannot mutate a frozenstring"); 478 PyObjC_GIL_FORWARD_EXC(); 479 } 480 481 if (PyAnySet_Check(value)) { 482 int r = PySet_Add(value, tmp); 483 Py_DECREF(tmp); 484 if (r == -1) { 485 PyObjC_GIL_FORWARD_EXC(); 486 } 487 488 } else { 489 PyObject* r; 490 491 r = PyObject_CallMethod(value, "add", "O", tmp); 492 Py_DECREF(tmp); 493 if (r == NULL) { 494 PyObjC_GIL_FORWARD_EXC(); 495 } 496 Py_DECREF(r); 497 } 498 499 PyObjC_END_WITH_GIL 500} 501 502@end 503