ObjFW  Check-in [de26b7668a]

Overview
Comment:Improve -[initWithKey:argList:].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: de26b7668a1abe4bf39213c2647fa25a7b755b16109dd4879f5cd3c0a6ec2811
User & Date: js on 2009-12-05 18:12:41
Other Links: manifest | tags
Context
2009-12-05
18:15
Update TODO. check-in: 741eca944e user: js tags: trunk
18:12
Improve -[initWithKey:argList:]. check-in: de26b7668a user: js tags: trunk
17:19
Fix optimization in OFDictionary / OFMutableDictionary. check-in: 011e248c30 user: js tags: trunk
Changes

Modified src/OFDictionary.m from [b08a848edb] to [09f88deaa1].

293
294
295
296
297
298
299
300
301
302
303




304

305



306


307

308



309















310





311


312




313
314








315
316





















































































317
318
319
320
321
322
323
	ret = [self initWithKey: first
			argList: args];
	va_end(args);

	return ret;
}

/* FIXME: Possible without resizing? */
- initWithKey: (OFObject <OFCopying>*)key
      argList: (va_list)args
{




	const SEL sel = @selector(setObject:forKey:);

	IMP set = [OFMutableDictionary instanceMethodForSelector: sel];






	self = [self init];





	@try {















		set(self, sel, va_arg(args, OFObject*), key);





		while ((key = va_arg(args, OFObject <OFCopying>*)) != nil)


			set(self, sel, va_arg(args, OFObject*), key);




	} @catch (OFException *e) {
		[self dealloc];








		@throw e;
	}






















































































	return self;
}

- (id)objectForKey: (OFObject <OFCopying>*)key
{
	uint32_t i, hash;







<



>
>
>
>
|
>
|
>
>
>

>
>
|
>
|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
|
>
>
>
>


>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
	ret = [self initWithKey: first
			argList: args];
	va_end(args);

	return ret;
}


- initWithKey: (OFObject <OFCopying>*)key
      argList: (va_list)args
{
	OFObject *obj;
	size_t i;
	uint32_t j, hash;
	va_list args2;

	self = [super init];

	count = 1;
	for (va_copy(args2, args); va_arg(args2, OFObject*) != nil; count++);
	count >>= 1;

	if (count > SIZE_MAX / 8) {
		Class c = isa;
		[self dealloc];
		@throw [OFOutOfRangeException newWithClass: c];
	}

	for (size = 1; size < count; size <<= 1);

	@try {
		data = [self allocMemoryForNItems: size
					 withSize: BUCKET_SIZE];
	} @catch (OFException *e) {
		/*
		 * We can't use [super dealloc] on OS X here. Compiler bug?
		 * Anyway, set size to 0 so that [self dealloc] works.
		 *                                                    */
		size = 0;
		[self dealloc];
		@throw e;
	}
	memset(data, 0, size * BUCKET_SIZE);

	if (key == nil)
		return self;
	else if ((obj = va_arg(args, OFObject*)) == nil) {
		Class c = isa;
		[self dealloc];
		@throw [OFInvalidArgumentException newWithClass: c
						       selector: _cmd];
	}

	/* Add first key / object pair */
	hash = [key hash];

	for (j = hash & (size - 1); j < size && data[j].key != nil; j++);

	@try {
		key = [key copy];
	} @catch (OFException *e) {
		[self dealloc];
		@throw e;
	}

	@try {
		[obj retain];
	} @catch (OFException *e) {
		[self dealloc];
		[key release];
		@throw e;
	}

	data[j].key = key;
	data[j].object = obj;
	data[j].hash = hash;

	for (i = 1; i < count; i++) {
		key = va_arg(args, OFObject <OFCopying>*);
		obj = va_arg(args, OFObject*);

		if (key == nil || obj == nil) {
			Class c = isa;
			[self dealloc];
			@throw [OFInvalidArgumentException newWithClass: c
							       selector: _cmd];
		}

		hash = [key hash];

		for (j = hash & (size - 1); j < size && data[j].key != nil &&
		    ![data[j].key isEqual: key]; j++);

		/* In case the last bucket is already used */
		if (j >= size)
			for (j = 0; j < size && data[j].key != nil &&
			    ![data[j].key isEqual: key]; j++);

		/* Key not in dictionary */
		if (j >= size || ![data[j].key isEqual: key]) {
			j = hash & (size - 1);
			for (; j < size && data[j].key != nil; j++);

			/* In case the last bucket is already used */
			if (j >= size)
				for (j = 0; j < size && data[j].key != nil;
				    j++);
			if (j >= size) {
				Class c = isa;
				[self dealloc];
				@throw [OFOutOfRangeException newWithClass: c];
			}

			@try {
				key = [key copy];
			} @catch (OFException *e) {
				[self dealloc];
				@throw e;
			}

			@try {
				[obj retain];
			} @catch (OFException *e) {
				[self dealloc];
				[key release];
				@throw e;
			}

			data[j].key = key;
			data[j].object = obj;
			data[j].hash = hash;

			continue;
		}

		/*
		 * They key is already in the dictionary. However, we just
		 * replace it so that the programmer gets the same behavior
		 * as if he'd call setObject:forKey: for each key/object pair.
		 */
		@try {
			[obj retain];
		} @catch (OFException *e) {
			[self dealloc];
			@throw e;
		}

		@try {
			[data[j].object release];
		} @catch (OFException *e) {
			[self dealloc];
			[obj release];
			@throw e;
		}

		data[j].object = obj;
	}

	return self;
}

- (id)objectForKey: (OFObject <OFCopying>*)key
{
	uint32_t i, hash;