ObjFW  Check-in [1ba9c051a6]

Overview
Comment:OFMapTable: Rename valueForKey to objectForKey

The reason for this is that -[valueForKey:] could be confused with
Key Value Coding.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1ba9c051a64d8f43527205775c0af58ef649638091bb6dfd1afa6c8981ca7246
User & Date: js on 2016-06-04 18:49:46
Other Links: manifest | tags
Context
2016-06-04
22:31
OFZIP: Cast app delegate to OFZIP* check-in: c5901029a0 user: js tags: trunk
18:49
OFMapTable: Rename valueForKey to objectForKey check-in: 1ba9c051a6 user: js tags: trunk
18:07
PLATFORMS.md: Increase minimum GCC version to 4.6 check-in: 03867d6f12 user: js tags: trunk
Changes

Modified src/OFCountedSet_hashtable.m from [14556b7ee8] to [a4ddef010c].

144
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178



179
180
181
182
183
184
185
186
187
188
189

190
191
192
193
194
195


196
197
198
199
200

201
202
203
204
205
206
207
208
209


210
211

212
213
214
215
216
217
144
145
146
147
148
149
150


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175



176
177
178
179
180
181
182
183
184
185
186
187
188

189
190
191
192
193


194
195
196
197
198
199

200
201
202
203
204
205
206
207


208
209
210

211
212
213
214
215
216
217







-
-
+
+















-
+







-
-
-
+
+
+










-
+




-
-
+
+




-
+







-
-
+
+

-
+






			count_ = [objectElement attributeForName: @"count"];

			if (object == nil || count_ == nil)
				@throw [OFInvalidFormatException exception];

			count = (size_t)[[count_ stringValue] decimalValue];

			[_mapTable setValue: (void*)(uintptr_t)count
				     forKey: [object objectByDeserializing]];
			[_mapTable setObject: (void*)(uintptr_t)count
				      forKey: [object objectByDeserializing]];

			objc_autoreleasePoolPop(pool2);
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (size_t)countForObject: (id)object
{
	return (size_t)(uintptr_t)[_mapTable valueForKey: object];
	return (size_t)(uintptr_t)[_mapTable objectForKey: object];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsAndCountUsingBlock:
    (of_counted_set_enumeration_block_t)block
{
	@try {
		[_mapTable enumerateKeysAndValuesUsingBlock:
		    ^ (void *key, void *value, bool *stop) {
			block(key, (size_t)(uintptr_t)value, stop);
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, (size_t)(uintptr_t)object, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: self];
	}
}
#endif

- (void)addObject: (id)object
{
	size_t count = (size_t)(uintptr_t)[_mapTable valueForKey: object];
	size_t count = (size_t)(uintptr_t)[_mapTable objectForKey: object];

	if (SIZE_MAX - count < 1 || UINTPTR_MAX - count < 1)
		@throw [OFOutOfRangeException exception];

	[_mapTable setValue: (void*)(uintptr_t)(count + 1)
		     forKey: object];
	[_mapTable setObject: (void*)(uintptr_t)(count + 1)
		      forKey: object];
}

- (void)removeObject: (id)object
{
	size_t count = (size_t)(uintptr_t)[_mapTable valueForKey: object];
	size_t count = (size_t)(uintptr_t)[_mapTable objectForKey: object];

	if (count == 0)
		return;

	count--;

	if (count > 0)
		[_mapTable setValue: (void*)(uintptr_t)count
			     forKey: object];
		[_mapTable setObject: (void*)(uintptr_t)count
			      forKey: object];
	else
		[_mapTable removeValueForKey: object];
		[_mapTable removeObjectForKey: object];
}

- (void)makeImmutable
{
}
@end

Modified src/OFDictionary_hashtable.m from [07ad349225] to [5ceb760b7b].

27
28
29
30
31
32
33
34

35
36

37
38
39
40

41
42

43
44
45
46

47
48

49
50
51
52

53
54

55
56
57
58

59
60

61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
27
28
29
30
31
32
33

34
35

36
37
38
39

40
41

42
43
44
45

46
47

48
49
50
51

52
53

54
55
56
57

58
59

60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96







-
+

-
+



-
+

-
+



-
+

-
+



-
+

-
+



-
+

-
+








-
+



















-
+







#import "OFXMLElement.h"

#import "OFEnumerationMutationException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"

static void*
copy(void *value)
copy(void *object)
{
	return [(id)value copy];
	return [(id)object copy];
}

static void*
retain(void *value)
retain(void *object)
{
	return [(id)value retain];
	return [(id)object retain];
}

static void
release(void *value)
release(void *object)
{
	[(id)value release];
	[(id)object release];
}

static uint32_t
hash(void *value)
hash(void *object)
{
	return [(id)value hash];
	return [(id)object hash];
}

static bool
equal(void *value1, void *value2)
equal(void *object1, void *object2)
{
	return [(id)value1 isEqual: (id)value2];
	return [(id)object1 isEqual: (id)object2];
}

static const of_map_table_functions_t keyFunctions = {
	.retain = copy,
	.release = release,
	.hash = hash,
	.equal = equal
};
static const of_map_table_functions_t valueFunctions = {
static const of_map_table_functions_t objectFunctions = {
	.retain = retain,
	.release = release,
	.hash = hash,
	.equal = equal
};

@implementation OFDictionary_hashtable
- init
{
	return [self initWithCapacity: 0];
}

- initWithCapacity: (size_t)capacity
{
	self = [super init];

	@try {
		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions
			 objectFunctions: objectFunctions
				capacity: capacity];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
134
135
136
137
138
139
140
141
142


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180


181
182
183
184
185
186
187
134
135
136
137
138
139
140


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158


159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178


179
180
181
182
183
184
185
186
187







-
-
+
+
















-
-
+
+


















-
-
+
+







		OFEnumerator *keyEnumerator, *objectEnumerator;
		id key, object;

		keyEnumerator = [dictionary keyEnumerator];
		objectEnumerator = [dictionary objectEnumerator];
		while ((key = [keyEnumerator nextObject]) != nil &&
		    (object = [objectEnumerator nextObject]) != nil)
			[_mapTable setValue: object
				     forKey: key];
			[_mapTable setObject: object
				      forKey: key];

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithObject: (id)object
	  forKey: (id)key
{
	self = [self initWithCapacity: 1];

	@try {
		[_mapTable setValue: object
			     forKey: key];
		[_mapTable setObject: object
			      forKey: key];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithObjects: (id const*)objects
	  forKeys: (id const*)keys
	    count: (size_t)count
{
	self = [self initWithCapacity: count];

	@try {
		size_t i;

		for (i = 0; i < count; i++)
			[_mapTable setValue: objects[i]
				     forKey: keys[i]];
			[_mapTable setObject: objects[i]
				      forKey: keys[i]];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
212
213
214
215
216
217
218
219

220
221
222
223


224
225
226
227
228
229
230
231
232
233


234
235
236
237
238
239
240
212
213
214
215
216
217
218

219
220
221


222
223
224
225
226
227
228
229
230
231


232
233
234
235
236
237
238
239
240







-
+


-
-
+
+








-
-
+
+







		if (count % 2 != 0)
			@throw [OFInvalidArgumentException exception];

		count /= 2;

		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions
			 objectFunctions: objectFunctions
				capacity: count];

		[_mapTable setValue: object
			     forKey: key];
		[_mapTable setObject: object
			      forKey: key];

		for (i = 1; i < count; i++) {
			key = va_arg(arguments, id);
			object = va_arg(arguments, id);

			if (key == nil || object == nil)
				@throw [OFInvalidArgumentException exception];

			[_mapTable setValue: object
				     forKey: key];
			[_mapTable setObject: object
				      forKey: key];
		}
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282


283
284
285
286
287
288
289
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280


281
282
283
284
285
286
287
288
289







-
+

















-
-
+
+







					 namespace: OF_SERIALIZATION_NS];

		if ([keys count] != [objects count])
			@throw [OFInvalidFormatException exception];

		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions
			 objectFunctions: objectFunctions
				capacity: [keys count]];

		keyEnumerator = [keys objectEnumerator];
		objectEnumerator = [objects objectEnumerator];
		while ((keyElement = [keyEnumerator nextObject]) != nil &&
		    (objectElement = [objectEnumerator nextObject]) != nil) {
			void *pool2 = objc_autoreleasePoolPush();
			OFXMLElement *key, *object;

			key = [[keyElement elementsForNamespace:
			    OF_SERIALIZATION_NS] firstObject];
			object = [[objectElement elementsForNamespace:
			    OF_SERIALIZATION_NS] firstObject];

			if (key == nil || object == nil)
				@throw [OFInvalidFormatException exception];

			[_mapTable setValue: [object objectByDeserializing]
				     forKey: [key objectByDeserializing]];
			[_mapTable setObject: [object objectByDeserializing]
				      forKey: [key objectByDeserializing]];

			objc_autoreleasePoolPop(pool2);
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
298
299
300
301
302
303
304
305

306
307
308
309
310
311
312
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312







-
+







	[_mapTable release];

	[super dealloc];
}

- (id)objectForKey: (id)key
{
	return [_mapTable valueForKey: key];
	return [_mapTable objectForKey: key];
}

- (size_t)count
{
	return [_mapTable count];
}

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
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







-
+




-
+




















-
+







	dictionary_ = (OFDictionary_hashtable*)dictionary;

	return [dictionary_->_mapTable isEqual: _mapTable];
}

- (bool)containsObject: (id)object
{
	return [_mapTable containsValue: object];
	return [_mapTable containsObject: object];
}

- (bool)containsObjectIdenticalTo: (id)object
{
	return [_mapTable containsValueIdenticalTo: object];
	return [_mapTable containsObjectIdenticalTo: object];
}

- (OFArray*)allKeys
{
	OFArray *ret;
	id *keys;
	size_t count;

	count = [_mapTable count];
	keys = [self allocMemoryWithSize: sizeof(*keys)
				   count: count];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMapTableEnumerator *enumerator;
		id key;
		size_t i;

		i = 0;
		enumerator = [_mapTable keyEnumerator];
		while ((key = [enumerator nextValue]) != nil) {
		while ((key = [enumerator nextObject]) != nil) {
			assert(i < count);

			keys[i++] = key;
		}

		objc_autoreleasePoolPop(pool);

381
382
383
384
385
386
387
388
389


390
391
392
393
394
395
396
381
382
383
384
385
386
387


388
389
390
391
392
393
394
395
396







-
-
+
+







	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMapTableEnumerator *enumerator;
		id object;
		size_t i;

		i = 0;
		enumerator = [_mapTable valueEnumerator];
		while ((object = [enumerator nextValue]) != nil) {
		enumerator = [_mapTable objectEnumerator];
		while ((object = [enumerator nextObject]) != nil) {
			assert(i < count);

			objects[i++] = object;
		}

		objc_autoreleasePoolPop(pool);

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
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







-
+

















-
-
-
+
+
+













	    initWithEnumerator: [_mapTable keyEnumerator]
			object: self] autorelease];
}

- (OFEnumerator*)objectEnumerator
{
	return [[[OFMapTable_EnumeratorWrapper alloc]
	    initWithEnumerator: [_mapTable valueEnumerator]
	    initWithEnumerator: [_mapTable objectEnumerator]
			object: self] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
			   objects: (id*)objects
			     count: (int)count
{
	return [_mapTable countByEnumeratingWithState: state
					      objects: objects
						count: count];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock:
    (of_dictionary_enumeration_block_t)block
{
	@try {
		[_mapTable enumerateKeysAndValuesUsingBlock:
		    ^ (void *key, void *value, bool *stop) {
			block(key, value, stop);
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, object, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: self];
	}
}
#endif

- (uint32_t)hash
{
	return [_mapTable hash];
}
@end

Modified src/OFKernelEventObserver_epoll.m from [f5a39990c0] to [345a2363cb].

60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74







-
+








		if ((flags = fcntl(_epfd, F_GETFD, 0)) != -1)
			fcntl(_epfd, F_SETFD, flags | FD_CLOEXEC);
#endif

		_FDToEvents = [[OFMapTable alloc]
		    initWithKeyFunctions: mapFunctions
			  valueFunctions: mapFunctions];
			 objectFunctions: mapFunctions];

		memset(&event, 0, sizeof(event));
		event.events = EPOLLIN;
		event.data.ptr = [OFNull null];

		if (epoll_ctl(_epfd, EPOLL_CTL_ADD, _cancelFD[0], &event) == -1)
			@throw [OFInitializationFailedException exception];
92
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108
109
110
111


112
113
114
115
116
117
118
119
120


121
122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
137
138
139
140
141
142
143


144
145
146
147
148
149
150
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110


111
112
113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138
139
140
141
142
143


144
145
146
147
148
149
150
151
152







-
+
+










-
-
+
+








-
+
+








-
+












-
-
+
+







- (void)OF_addObject: (id)object
      fileDescriptor: (int)fd
	      events: (int)addEvents
{
	struct epoll_event event;
	intptr_t events;

	events = (intptr_t)[_FDToEvents valueForKey: (void*)((intptr_t)fd + 1)];
	events = (intptr_t)[_FDToEvents
	    objectForKey: (void*)((intptr_t)fd + 1)];

	memset(&event, 0, sizeof(event));
	event.events = (int)events | addEvents;
	event.data.ptr = object;

	if (epoll_ctl(_epfd, (events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD),
	    fd, &event) == -1)
		@throw [OFObserveFailedException exceptionWithObserver: self
								 errNo: errno];

	[_FDToEvents setValue: (void*)(events | addEvents)
		       forKey: (void*)((intptr_t)fd + 1)];
	[_FDToEvents setObject: (void*)(events | addEvents)
			forKey: (void*)((intptr_t)fd + 1)];
}

- (void)OF_removeObject: (id)object
	 fileDescriptor: (int)fd
		 events: (int)removeEvents
{
	intptr_t events;

	events = (intptr_t)[_FDToEvents valueForKey: (void*)((intptr_t)fd + 1)];
	events = (intptr_t)[_FDToEvents
	    objectForKey: (void*)((intptr_t)fd + 1)];
	events &= ~removeEvents;

	if (events == 0) {
		if (epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_FDToEvents removeValueForKey: (void*)((intptr_t)fd + 1)];
		[_FDToEvents removeObjectForKey: (void*)((intptr_t)fd + 1)];
	} else {
		struct epoll_event event;

		memset(&event, 0, sizeof(event));
		event.events = (int)events;
		event.data.ptr = object;

		if (epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &event) == -1)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_FDToEvents setValue: (void*)events
			       forKey: (void*)((intptr_t)fd + 1)];
		[_FDToEvents setObject: (void*)events
				forKey: (void*)((intptr_t)fd + 1)];
	}
}

- (void)OF_addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self OF_addObject: object
	    fileDescriptor: [object fileDescriptorForReading]

Modified src/OFMapTable.h from [65a71eea19] to [2c4d7aef99].

23
24
25
26
27
28
29
30
31
32
33




34
35
36
37



38
39
40
41
42
43
44
45

46
47
48
49

50
51
52
53

54
55
56
57



58
59

60
61
62
63
64
65
66
67
68

69
70
71
72

73
74
75
76
77
78
79
80
81
82
83
84
85

86
87

88
89
90

91
92
93

94
95
96
97
98


99
100
101

102
103
104
105

106
107
108
109
110
111
112


113
114
115
116
117

118
119
120

121
122
123
124

125
126
127
128

129
130
131

132
133
134
135
136
137

138
139
140
141
142
143
144
145
146
147
148

149
150
151

152
153

154
155
156

157
158
159

160
161
162


163
164
165

166
167
168
169

170
171
172

173
174

175
176
177
178


179
180
181


182
183

184
185
186

187
188
189
190
191



192
193

194
195
196
197
198
199
200
201
202
203
204
205

206
207

208
209

210
211
212
213
214
215
216
217

218
219
220
221

222
223

224
225

226
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241
242
243
244
245
246

247
248

249
250

251
252
253
254
255
256
257
258
259
23
24
25
26
27
28
29




30
31
32
33
34



35
36
37
38
39
40
41
42
43
44

45
46
47
48

49
50
51
52

53
54



55
56
57
58

59
60
61
62
63
64
65
66
67

68
69
70
71

72
73
74
75
76
77
78
79
80
81
82
83
84

85
86

87
88
89

90
91
92

93
94
95
96


97
98
99
100

101
102
103
104

105
106
107
108
109
110


111
112
113
114
115
116

117
118
119

120
121
122
123

124
125
126
127

128
129
130

131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147

148
149
150

151
152

153
154
155

156
157
158

159
160


161
162
163
164

165
166
167
168

169
170
171

172
173

174
175
176


177
178
179


180
181
182

183
184
185

186
187
188



189
190
191
192

193
194
195
196
197
198
199
200
201
202
203
204

205
206

207
208

209
210
211
212
213
214
215
216

217
218
219
220

221
222

223
224

225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
240
241
242
243
244
245

246
247

248
249

250
251
252
253
254
255
256
257
258
259







-
-
-
-
+
+
+
+

-
-
-
+
+
+







-
+



-
+



-
+

-
-
-
+
+
+

-
+








-
+



-
+












-
+

-
+


-
+


-
+



-
-
+
+


-
+



-
+





-
-
+
+




-
+


-
+



-
+



-
+


-
+





-
+










-
+


-
+

-
+


-
+


-
+

-
-
+
+


-
+



-
+


-
+

-
+


-
-
+
+

-
-
+
+

-
+


-
+


-
-
-
+
+
+

-
+











-
+

-
+

-
+







-
+



-
+

-
+

-
+







-
+












-
+

-
+

-
+










/*!
 * @struct of_map_table_functions_t OFMapTable.h ObjFW/OFMapTable.h
 *
 * @brief A struct describing the functions to be used by the map table.
 */
typedef struct {
	/// The function to retain keys / values
	void *_Nonnull (*_Nullable retain)(void *value);
	/// The function to release keys / values
	void (*_Nullable release)(void *value);
	/// The function to retain keys / objects
	void *_Nonnull (*_Nullable retain)(void *object);
	/// The function to release keys / objects
	void (*_Nullable release)(void *object);
	/// The function to hash keys
	uint32_t (*_Nullable hash)(void *value);
	/// The function to compare keys / values
	bool (*_Nullable equal)(void *value1, void *value2);
	uint32_t (*_Nullable hash)(void *object);
	/// The function to compare keys / objects
	bool (*_Nullable equal)(void *object1, void *object2);
} of_map_table_functions_t;

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief A block for enumerating an OFMapTable.
 *
 * @param key The current key
 * @param value The current value
 * @param object The current object
 * @param stop A pointer to a variable that can be set to true to stop the
 *	       enumeration
 */
typedef void (^of_map_table_enumeration_block_t)(void *key, void *value,
typedef void (^of_map_table_enumeration_block_t)(void *key, void *object,
    bool *stop);

/*!
 * @brief A block for replacing values in an OFMapTable.
 * @brief A block for replacing objects in an OFMapTable.
 *
 * @param key The key of the value to replace
 * @param value The value to replace
 * @return The value to replace the value with
 * @param key The key of the object to replace
 * @param object The object to replace
 * @return The object to replace the object with
 */
typedef void *_Nonnull (^of_map_table_replace_block_t)(void *key, void *value);
typedef void *_Nonnull (^of_map_table_replace_block_t)(void *key, void *object);
#endif

@class OFMapTableEnumerator;

/*!
 * @class OFMapTable OFMapTable.h ObjFW/OFMapTable.h
 *
 * @brief A class similar to OFDictionary, but providing more options how keys
 *	  and values should be retained, released, compared and hashed.
 *	  and objects should be retained, released, compared and hashed.
 */
@interface OFMapTable: OFObject <OFCopying, OFFastEnumeration>
{
	of_map_table_functions_t _keyFunctions, _valueFunctions;
	of_map_table_functions_t _keyFunctions, _objectFunctions;
	struct of_map_table_bucket **_buckets;
	uint32_t _count, _capacity;
	uint8_t _rotate;
	unsigned long _mutations;
}

/*!
 * The key functions used by the map table.
 */
@property (readonly) of_map_table_functions_t keyFunctions;

/*!
 * The value functions used by the map table.
 * The object functions used by the map table.
 */
@property (readonly) of_map_table_functions_t valueFunctions;
@property (readonly) of_map_table_functions_t objectFunctions;

/*!
 * @brief Creates a new OFMapTable with the specified key and value functions.
 * @brief Creates a new OFMapTable with the specified key and object functions.
 *
 * @param keyFunctions A structure of functions for handling keys
 * @param valueFunctions A structure of functions for handling values
 * @param objectFunctions A structure of functions for handling objects
 * @return A new autoreleased OFMapTable
 */
+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions
			  valueFunctions: (of_map_table_functions_t)
					      valueFunctions;
			 objectFunctions: (of_map_table_functions_t)
					      objectFunctions;

/*!
 * @brief Creates a new OFMapTable with the specified key functions, value
 * @brief Creates a new OFMapTable with the specified key functions, object
 *	  functions and capacity.
 *
 * @param keyFunctions A structure of functions for handling keys
 * @param valueFunctions A structure of functions for handling values
 * @param objectFunctions A structure of functions for handling objects
 * @param capacity A hint about the count of elements expected to be in the map
 *	  table
 * @return A new autoreleased OFMapTable
 */
+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions
			  valueFunctions: (of_map_table_functions_t)
					      valueFunctions
			 objectFunctions: (of_map_table_functions_t)
					      objectFunctions
				capacity: (size_t)capacity;

/*!
 * @brief Initializes an already allocated OFMapTable with the specified key
 *	  and value functions.
 *	  and object functions.
 *
 * @param keyFunctions A structure of functions for handling keys
 * @param valueFunctions A structure of functions for handling values
 * @param objectFunctions A structure of functions for handling objects
 * @return An initialized OFMapTable
 */
- initWithKeyFunctions: (of_map_table_functions_t)keyFunctions
	valueFunctions: (of_map_table_functions_t)valueFunctions;
       objectFunctions: (of_map_table_functions_t)objectFunctions;

/*!
 * @brief Initializes an already allocated OFMapTable with the specified key
 *	  functions, value functions and capacity.
 *	  functions, object functions and capacity.
 *
 * @param keyFunctions A structure of functions for handling keys
 * @param valueFunctions A structure of functions for handling values
 * @param objectFunctions A structure of functions for handling objects
 * @param capacity A hint about the count of elements expected to be in the map
 *	  table
 * @return An initialized OFMapTable
 */
- initWithKeyFunctions: (of_map_table_functions_t)keyFunctions
	valueFunctions: (of_map_table_functions_t)valueFunctions
       objectFunctions: (of_map_table_functions_t)objectFunctions
	      capacity: (size_t)capacity;

/*!
 * @brief Returns the number of objects in the map table.
 *
 * @return The number of objects in the map table
 */
- (size_t)count;

/*!
 * @brief Returns the value for the given key or NULL if the key was not found.
 * @brief Returns the object for the given key or NULL if the key was not found.
 *
 * @param key The key whose object should be returned
 * @return The value for the given key or NULL if the key was not found
 * @return The object for the given key or NULL if the key was not found
 */
- (nullable void*)valueForKey: (void*)key;
- (nullable void*)objectForKey: (void*)key;

/*!
 * @brief Sets a value for a key.
 * @brief Sets an object for a key.
 *
 * @param key The key to set
 * @param value The value to set the key to
 * @param object The object to set the key to
 */
- (void)setValue: (void*)value
	  forKey: (void*)key;
- (void)setObject: (void*)object
	   forKey: (void*)key;

/*!
 * @brief Removes the value for the specified key from the map table.
 * @brief Removes the object for the specified key from the map table.
 *
 * @param key The key whose object should be removed
 */
- (void)removeValueForKey: (void*)key;
- (void)removeObjectForKey: (void*)key;

/*!
 * @brief Removes all values.
 * @brief Removes all objects.
 */
- (void)removeAllValues;
- (void)removeAllObjects;

/*!
 * @brief Checks whether the map table contains a value equal to the specified
 *	  value.
 * @brief Checks whether the map table contains an object equal to the
 *	  specified object.
 *
 * @param value The value which is checked for being in the map table
 * @return A boolean whether the map table contains the specified value
 * @param object The object which is checked for being in the map table
 * @return A boolean whether the map table contains the specified object
*/
- (bool)containsValue: (nullable void*)value;
- (bool)containsObject: (nullable void*)object;

/*!
 * @brief Checks whether the map table contains a value with the specified
 * @brief Checks whether the map table contains an object with the specified
 *        address.
 *
 * @param value The value which is checked for being in the map table
 * @return A boolean whether the map table contains a value with the specified
 *	   address.
 * @param object The object which is checked for being in the map table
 * @return A boolean whether the map table contains an object with the
 *	   specified address.
 */
- (bool)containsValueIdenticalTo: (nullable void*)value;
- (bool)containsObjectIdenticalTo: (nullable void*)object;

/*!
 * @brief Returns an OFMapTableEnumerator to enumerate through the map table's
 *	  keys.
 *
 * @return An OFMapTableEnumerator to enumerate through the map table's keys
 */
- (OFMapTableEnumerator*)keyEnumerator;

/*!
 * @brief Returns an OFMapTableEnumerator to enumerate through the map table's
 *	  values.
 *	  objects.
 *
 * @return An OFMapTableEnumerator to enumerate through the map table's values
 * @return An OFMapTableEnumerator to enumerate through the map table's objects
 */
- (OFMapTableEnumerator*)valueEnumerator;
- (OFMapTableEnumerator*)objectEnumerator;

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief Executes a block for each key / object pair.
 *
 * @param block The block to execute for each key / object pair.
 */
- (void)enumerateKeysAndValuesUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock:
    (of_map_table_enumeration_block_t)block;

/*!
 * @brief Replaces each value with the value returned by the block.
 * @brief Replaces each object with the object returned by the block.
 *
 * @param block The block which returns a new value for each value
 * @param block The block which returns a new object for each object
 */
- (void)replaceValuesUsingBlock: (of_map_table_replace_block_t)block;
- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block;
#endif
@end

/*!
 * @class OFMapTableEnumerator OFMapTable.h ObjFW/OFMapTable.h
 *
 * @brief A class which provides methods to enumerate through an OFMapTable's
 *	  keys or values.
 *	  keys or objects.
 */
@interface OFMapTableEnumerator: OFObject
{
	OFMapTable *_mapTable;
	struct of_map_table_bucket **_buckets;
	uint32_t _capacity;
	unsigned long _mutations;
	unsigned long *_mutationsPtr;
	uint32_t _position;
}

/*!
 * @brief Returns the next value.
 * @brief Returns the next object.
 *
 * @return The next value
 * @return The next object
 */
- (void*)nextValue;
- (void*)nextObject;

/*!
 * @brief Resets the enumerator, so the next call to nextKey returns the first
 *	  key again.
 */
- (void)reset;
@end

OF_ASSUME_NONNULL_END

Modified src/OFMapTable.m from [d08b0754f8] to [f6af531a58].

28
29
30
31
32
33
34
35

36
37
38
39
40
41

42
43

44
45
46
47

48
49
50
51
52

53
54

55
56
57
58

59
60

61
62
63
64
65
66



67
68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83

84
85
86
87


88
89
90
91

92
93
94
95
96


97
98
99
100
101

102
103
104
105
106
107
108
109
110
111

112
113
114

115
116
117
118
119

120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140




141
142
143
144
145
146
147
28
29
30
31
32
33
34

35
36
37
38
39
40

41
42

43
44
45
46

47
48
49
50
51

52
53

54
55
56
57

58
59

60
61
62
63



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82

83
84
85


86
87
88
89
90

91
92
93
94


95
96
97
98
99
100

101
102
103
104
105
106
107
108
109
110

111
112
113

114
115
116
117
118

119
120
121
122
123
124
125

126
127
128
129
130
131
132
133
134
135
136




137
138
139
140
141
142
143
144
145
146
147







-
+





-
+

-
+



-
+




-
+

-
+



-
+

-
+



-
-
-
+
+
+












-
+



-
+


-
-
+
+



-
+



-
-
+
+




-
+









-
+


-
+




-
+






-
+










-
-
-
-
+
+
+
+







#import "OFEnumerationMutationException.h"
#import "OFInvalidArgumentException.h"
#import "OFOutOfRangeException.h"

#define MIN_CAPACITY 16

struct of_map_table_bucket {
	void *key, *value;
	void *key, *object;
	uint32_t hash;
};
static struct of_map_table_bucket deleted = { 0 };

static void*
defaultRetain(void *value)
defaultRetain(void *object)
{
	return value;
	return object;
}

static void
defaultRelease(void *value)
defaultRelease(void *object)
{
}

static uint32_t
defaultHash(void *value)
defaultHash(void *object)
{
	return (uint32_t)(uintptr_t)value;
	return (uint32_t)(uintptr_t)object;
}

static bool
defaultEqual(void *value1, void *value2)
defaultEqual(void *object1, void *object2)
{
	return (value1 == value2);
	return (object1 == object2);
}

@interface OFMapTable ()
- (void)OF_setValue: (void*)value
	     forKey: (void*)key
	       hash: (uint32_t)hash;
- (void)OF_setObject: (void*)object
	      forKey: (void*)key
		hash: (uint32_t)hash;
@end

@interface OFMapTableEnumerator ()
- (instancetype)OF_initWithMapTable: (OFMapTable*)mapTable
			    buckets: (struct of_map_table_bucket**)buckets
			   capacity: (uint32_t)capacity
		   mutationsPointer: (unsigned long*)mutationsPtr;
@end

@interface OFMapTableKeyEnumerator: OFMapTableEnumerator
@end

@interface OFMapTableValueEnumerator: OFMapTableEnumerator
@interface OFMapTableObjectEnumerator: OFMapTableEnumerator
@end

@implementation OFMapTable
@synthesize keyFunctions = _keyFunctions, valueFunctions = _valueFunctions;
@synthesize keyFunctions = _keyFunctions, objectFunctions = _objectFunctions;

+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions
			  valueFunctions: (of_map_table_functions_t)
					      valueFunctions
			 objectFunctions: (of_map_table_functions_t)
					      objectFunctions
{
	return [[[self alloc]
	    initWithKeyFunctions: keyFunctions
		  valueFunctions: valueFunctions] autorelease];
		  objectFunctions: objectFunctions] autorelease];
}

+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions
			  valueFunctions: (of_map_table_functions_t)
					      valueFunctions
			 objectFunctions: (of_map_table_functions_t)
					      objectFunctions
				capacity: (size_t)capacity
{
	return [[[self alloc]
	    initWithKeyFunctions: keyFunctions
		  valueFunctions: valueFunctions
		 objectFunctions: objectFunctions
			capacity: capacity] autorelease];
}

- init
{
	OF_INVALID_INIT_METHOD
}

- initWithKeyFunctions: (of_map_table_functions_t)keyFunctions
	valueFunctions: (of_map_table_functions_t)valueFunctions
       objectFunctions: (of_map_table_functions_t)objectFunctions
{
	return [self initWithKeyFunctions: keyFunctions
			   valueFunctions: valueFunctions
			  objectFunctions: objectFunctions
				 capacity: 0];
}

- initWithKeyFunctions: (of_map_table_functions_t)keyFunctions
	valueFunctions: (of_map_table_functions_t)valueFunctions
       objectFunctions: (of_map_table_functions_t)objectFunctions
	      capacity: (size_t)capacity
{
	self = [super init];

	@try {
		_keyFunctions = keyFunctions;
		_valueFunctions = valueFunctions;
		_objectFunctions = objectFunctions;

#define SET_DEFAULT(var, value) \
	if (var == NULL)	\
		var = value;

		SET_DEFAULT(_keyFunctions.retain, defaultRetain);
		SET_DEFAULT(_keyFunctions.release, defaultRelease);
		SET_DEFAULT(_keyFunctions.hash, defaultHash);
		SET_DEFAULT(_keyFunctions.equal, defaultEqual);

		SET_DEFAULT(_valueFunctions.retain, defaultRetain);
		SET_DEFAULT(_valueFunctions.release, defaultRelease);
		SET_DEFAULT(_valueFunctions.hash, defaultHash);
		SET_DEFAULT(_valueFunctions.equal, defaultEqual);
		SET_DEFAULT(_objectFunctions.retain, defaultRetain);
		SET_DEFAULT(_objectFunctions.release, defaultRelease);
		SET_DEFAULT(_objectFunctions.hash, defaultHash);
		SET_DEFAULT(_objectFunctions.equal, defaultEqual);

#undef SET_DEFAULT

		if (capacity > UINT32_MAX / sizeof(*_buckets) ||
		    capacity > UINT32_MAX / 8)
			@throw [OFOutOfRangeException exception];

181
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206

207
208
209
210

211

212
213


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248




249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206
207
208
209
210
211

212
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239
240

241
242
243
244
245
246




247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278

279
280
281
282
283
284
285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
300







-
+

















-
+




+
-
+

-
+
+














-
+










-
+





-
-
-
-
+
+
+
+













-
+














-
+













-
+







}

- (void)dealloc
{
	for (uint32_t i = 0; i < _capacity; i++) {
		if (_buckets[i] != NULL && _buckets[i] != &deleted) {
			_keyFunctions.release(_buckets[i]->key);
			_valueFunctions.release(_buckets[i]->value);
			_objectFunctions.release(_buckets[i]->object);
		}
	}

	[super dealloc];
}

- (bool)isEqual: (id)object
{
	OFMapTable *mapTable;

	if (![object isKindOfClass: [OFMapTable class]])
		return false;

	mapTable = object;

	if (mapTable->_count != _count ||
	    mapTable->_keyFunctions.equal != _keyFunctions.equal ||
	    mapTable->_valueFunctions.equal != _valueFunctions.equal)
	    mapTable->_objectFunctions.equal != _objectFunctions.equal)
		return false;

	for (uint32_t i = 0; i < _capacity; i++) {
		if (_buckets[i] != NULL && _buckets[i] != &deleted) {
			void *object =
			void *value = [mapTable valueForKey: _buckets[i]->key];
			    [mapTable objectForKey: _buckets[i]->key];

			if (!_valueFunctions.equal(value, _buckets[i]->value))
			if (!_objectFunctions.equal(object,
			    _buckets[i]->object))
				return false;
		}
	}

	return true;
}

- (uint32_t)hash
{
	uint32_t hash = 0;

	for (uint32_t i = 0; i < _capacity; i++) {
		if (_buckets[i] != NULL && _buckets[i] != &deleted) {
			hash += OF_ROR(_buckets[i]->hash, _rotate);
			hash += _valueFunctions.hash(_buckets[i]->value);
			hash += _objectFunctions.hash(_buckets[i]->object);
		}
	}

	return hash;
}

- copy
{
	OFMapTable *copy = [[OFMapTable alloc]
	    initWithKeyFunctions: _keyFunctions
		  valueFunctions: _valueFunctions
		 objectFunctions: _objectFunctions
			capacity: _capacity];

	@try {
		for (uint32_t i = 0; i < _capacity; i++)
			if (_buckets[i] != NULL && _buckets[i] != &deleted)
				[copy OF_setValue: _buckets[i]->value
					   forKey: _buckets[i]->key
					     hash: OF_ROR(_buckets[i]->hash,
						       _rotate)];
				[copy OF_setObject: _buckets[i]->object
					    forKey: _buckets[i]->key
					      hash: OF_ROR(_buckets[i]->hash,
							_rotate)];
	} @catch (id e) {
		[copy release];
		@throw e;
	}

	return copy;
}

- (size_t)count
{
	return _count;
}

- (void*)valueForKey: (void*)key
- (void*)objectForKey: (void*)key
{
	uint32_t i, hash, last;

	if (key == NULL)
		@throw [OFInvalidArgumentException exception];

	hash = OF_ROL(_keyFunctions.hash(key), _rotate);
	last = _capacity;

	for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deleted)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key))
			return _buckets[i]->value;
			return _buckets[i]->object;
	}

	if (i < last)
		return nil;

	/* In case the last bucket is already used */
	last = hash & (_capacity - 1);

	for (i = 0; i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deleted)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key))
			return _buckets[i]->value;
			return _buckets[i]->object;
	}

	return NULL;
}

- (void)OF_resizeForCount: (uint32_t)count
{
351
352
353
354
355
356
357
358
359
360



361
362
363
364
365

366
367
368
369
370
371
372
353
354
355
356
357
358
359



360
361
362
363
364
365
366

367
368
369
370
371
372
373
374







-
-
-
+
+
+




-
+







	}

	[self freeMemory: _buckets];
	_buckets = buckets;
	_capacity = capacity;
}

- (void)OF_setValue: (void*)value
	     forKey: (void*)key
	       hash: (uint32_t)hash
- (void)OF_setObject: (void*)object
	      forKey: (void*)key
		hash: (uint32_t)hash
{
	uint32_t i, last;
	void *old;

	if (key == NULL || value == NULL)
	if (key == NULL || object == NULL)
		@throw [OFInvalidArgumentException exception];

	hash = OF_ROL(hash, _rotate);
	last = _capacity;

	for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deleted)
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
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

473
474
475
476
477
478
479
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

456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473

474
475
476
477
478
479
480
481







-
+














-
-
-
+
+
+


-
-
+
+

-
-
-
+
+
+


-
+

















-
+







			bucket->key = _keyFunctions.retain(key);
		} @catch (id e) {
			[self freeMemory: bucket];
			@throw e;
		}

		@try {
			bucket->value = _valueFunctions.retain(value);
			bucket->object = _objectFunctions.retain(object);
		} @catch (id e) {
			_keyFunctions.release(bucket->key);
			[self freeMemory: bucket];
			@throw e;
		}

		bucket->hash = hash;

		_buckets[i] = bucket;
		_count++;

		return;
	}

	old = _buckets[i]->value;
	_buckets[i]->value = _valueFunctions.retain(value);
	_valueFunctions.release(old);
	old = _buckets[i]->object;
	_buckets[i]->object = _objectFunctions.retain(object);
	_objectFunctions.release(old);
}

- (void)setValue: (void*)value
	  forKey: (void*)key
- (void)setObject: (void*)object
	   forKey: (void*)key
{
	[self OF_setValue: value
		   forKey: key
		     hash: _keyFunctions.hash(key)];
	[self OF_setObject: object
		    forKey: key
		      hash: _keyFunctions.hash(key)];
}

- (void)removeValueForKey: (void*)key
- (void)removeObjectForKey: (void*)key
{
	uint32_t i, hash, last;

	if (key == NULL)
		@throw [OFInvalidArgumentException exception];

	hash = OF_ROL(_keyFunctions.hash(key), _rotate);
	last = _capacity;

	for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deleted)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key)) {
			_mutations++;

			_keyFunctions.release(_buckets[i]->key);
			_valueFunctions.release(_buckets[i]->value);
			_objectFunctions.release(_buckets[i]->object);

			[self freeMemory: _buckets[i]];
			_buckets[i] = &deleted;

			_count--;
			[self OF_resizeForCount: _count];

489
490
491
492
493
494
495
496

497
498
499
500
501
502
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
518
519
520

521
522
523
524
525
526
527
491
492
493
494
495
496
497

498
499
500
501
502
503
504
505
506
507
508
509
510
511

512
513
514
515
516
517
518
519
520
521

522
523
524
525
526
527
528
529







-
+













-
+









-
+








	for (i = 0; i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deleted)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key)) {
			_keyFunctions.release(_buckets[i]->key);
			_valueFunctions.release(_buckets[i]->value);
			_objectFunctions.release(_buckets[i]->object);

			[self freeMemory: _buckets[i]];
			_buckets[i] = &deleted;

			_count--;
			_mutations++;
			[self OF_resizeForCount: _count];

			return;
		}
	}
}

- (void)removeAllValues
- (void)removeAllObjects
{
	for (uint32_t i = 0; i < _capacity; i++) {
		if (_buckets[i] != NULL) {
			if (_buckets[i] == &deleted) {
				_buckets[i] = NULL;
				continue;
			}

			_keyFunctions.release(_buckets[i]->key);
			_valueFunctions.release(_buckets[i]->value);
			_objectFunctions.release(_buckets[i]->object);

			[self freeMemory: _buckets[i]];
			_buckets[i] = NULL;
		}
	}

	_count = 0;
540
541
542
543
544
545
546
547

548
549

550
551
552
553
554

555
556
557
558
559
560

561
562

563
564
565
566
567

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

583
584

585
586
587
588
589
590
591
542
543
544
545
546
547
548

549
550

551
552
553
554
555

556
557
558
559
560
561

562
563

564
565
566
567
568

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583

584
585

586
587
588
589
590
591
592
593







-
+

-
+




-
+





-
+

-
+




-
+














-
+

-
+







#elif defined(HAVE_RANDOM)
		_rotate = random() & 31;
#else
		_rotate = rand() & 31;
#endif
}

- (bool)containsValue: (void*)value
- (bool)containsObject: (void*)object
{
	if (value == NULL || _count == 0)
	if (object == NULL || _count == 0)
		return false;

	for (uint32_t i = 0; i < _capacity; i++)
		if (_buckets[i] != NULL && _buckets[i] != &deleted)
			if (_valueFunctions.equal(_buckets[i]->value, value))
			if (_objectFunctions.equal(_buckets[i]->object, object))
				return true;

	return false;
}

- (bool)containsValueIdenticalTo: (void*)value
- (bool)containsObjectIdenticalTo: (void*)object
{
	if (value == NULL || _count == 0)
	if (object == NULL || _count == 0)
		return false;

	for (uint32_t i = 0; i < _capacity; i++)
		if (_buckets[i] != NULL && _buckets[i] != &deleted)
			if (_buckets[i]->value == value)
			if (_buckets[i]->object == object)
				return true;

	return false;
}

- (OFMapTableEnumerator*)keyEnumerator
{
	return [[[OFMapTableKeyEnumerator alloc]
	    OF_initWithMapTable: self
			buckets: _buckets
		       capacity: _capacity
	       mutationsPointer: &_mutations] autorelease];
}

- (OFMapTableEnumerator*)valueEnumerator
- (OFMapTableEnumerator*)objectEnumerator
{
	return [[[OFMapTableValueEnumerator alloc]
	return [[[OFMapTableObjectEnumerator alloc]
	    OF_initWithMapTable: self
			buckets: _buckets
		       capacity: _capacity
	       mutationsPointer: &_mutations] autorelease];
}

- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t*)state
610
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625
626
627
628
629

630
631
632
633

634
635
636
637
638
639
640
641
642
643
644
645

646
647
648
649
650
651
652




653
654
655
656
657
658
659
612
613
614
615
616
617
618

619
620
621
622
623
624
625
626
627
628
629
630

631
632
633
634

635
636
637
638
639
640
641
642
643
644
645
646

647
648
649
650




651
652
653
654
655
656
657
658
659
660
661







-
+











-
+



-
+











-
+



-
-
-
-
+
+
+
+







	state->itemsPtr = objects;
	state->mutationsPtr = &_mutations;

	return i;
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndValuesUsingBlock:
- (void)enumerateKeysAndObjectsUsingBlock:
    (of_map_table_enumeration_block_t)block
{
	bool stop = false;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity && !stop; i++) {
		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

		if (_buckets[i] != NULL && _buckets[i] != &deleted)
			block(_buckets[i]->key, _buckets[i]->value, &stop);
			block(_buckets[i]->key, _buckets[i]->object, &stop);
	}
}

- (void)replaceValuesUsingBlock: (of_map_table_replace_block_t)block
- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block
{
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity; i++) {
		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

		if (_buckets[i] != NULL && _buckets[i] != &deleted) {
			void *new;

			new = block(_buckets[i]->key, _buckets[i]->value);
			new = block(_buckets[i]->key, _buckets[i]->object);
			if (new == NULL)
				@throw [OFInvalidArgumentException exception];

			if (new != _buckets[i]->value) {
				_valueFunctions.release(_buckets[i]->value);
				_buckets[i]->value =
				    _valueFunctions.retain(new);
			if (new != _buckets[i]->object) {
				_objectFunctions.release(_buckets[i]->object);
				_buckets[i]->object =
				    _objectFunctions.retain(new);
			}
		}
	}
}
#endif
@end

682
683
684
685
686
687
688
689

690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722


723
724
725
726
727
728
729
730
731
732

733
734
735
736
737
738
739
684
685
686
687
688
689
690

691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706

707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722


723
724
725
726
727
728
729
730
731
732
733

734
735
736
737
738
739
740
741







-
+















-
+















-
-
+
+









-
+







- (void)dealloc
{
	[_mapTable release];

	[super dealloc];
}

- (void*)nextValue
- (void*)nextObject
{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)reset
{
	if (*_mutationsPtr != _mutations)
		@throw [OFEnumerationMutationException
		    exceptionWithObject: _mapTable];

	_position = 0;
}
@end

@implementation OFMapTableKeyEnumerator
- (void*)nextValue
- (void*)nextObject
{
	if (*_mutationsPtr != _mutations)
		@throw [OFEnumerationMutationException
		    exceptionWithObject: _mapTable];

	for (; _position < _capacity && (_buckets[_position] == NULL ||
	    _buckets[_position] == &deleted); _position++);

	if (_position < _capacity)
		return _buckets[_position++]->key;
	else
		return NULL;
}
@end

@implementation OFMapTableValueEnumerator
- (void*)nextValue
@implementation OFMapTableObjectEnumerator
- (void*)nextObject
{
	if (*_mutationsPtr != _mutations)
		@throw [OFEnumerationMutationException
		    exceptionWithObject: _mapTable];

	for (; _position < _capacity && (_buckets[_position] == NULL ||
	    _buckets[_position] == &deleted); _position++);

	if (_position < _capacity)
		return _buckets[_position++]->value;
		return _buckets[_position++]->object;
	else
		return NULL;
}
@end

@implementation OFMapTable_EnumeratorWrapper
- initWithEnumerator: (OFMapTableEnumerator*)enumerator
756
757
758
759
760
761
762
763

764
765
766
767
768
769
770
758
759
760
761
762
763
764

765
766
767
768
769
770
771
772







-
+







}

- (id)nextObject
{
	id ret;

	@try {
		ret = [_enumerator nextValue];
		ret = [_enumerator nextObject];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: _object];
	}

	return ret;
}

Modified src/OFMutableDictionary_hashtable.m from [1dfc2b158b] to [8c881f7ce1].

31
32
33
34
35
36
37
38
39


40
41
42
43
44

45
46
47
48
49

50
51
52
53
54
55
56
57
58



59
60
61
62
63
64
65
66
67
68
69
70
71
31
32
33
34
35
36
37


38
39
40
41
42
43

44
45
46
47
48

49
50
51
52
53
54
55



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71







-
-
+
+




-
+




-
+






-
-
-
+
+
+













	if (self == [OFMutableDictionary_hashtable class])
		[self inheritMethodsFromClass: [OFDictionary_hashtable class]];
}

- (void)setObject: (id)object
	   forKey: (id)key
{
	[_mapTable setValue: object
		     forKey: key];
	[_mapTable setObject: object
		      forKey: key];
}

- (void)removeObjectForKey: (id)key
{
	[_mapTable removeValueForKey: key];
	[_mapTable removeObjectForKey: key];
}

- (void)removeAllObjects
{
	[_mapTable removeAllValues];
	[_mapTable removeAllObjects];
}

#ifdef OF_HAVE_BLOCKS
- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block
{
	@try {
		[_mapTable replaceValuesUsingBlock:
		    ^ void* (void *key, void *value) {
			return block(key, value);
		[_mapTable replaceObjectsUsingBlock:
		    ^ void* (void *key, void *object) {
			return block(key, object);
		}];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: self];
	}
}
#endif

- (void)makeImmutable
{
	object_setClass(self, [OFDictionary_hashtable class]);
}
@end

Modified src/OFMutableSet_hashtable.m from [d6d4078141] to [dbc58689d1].

25
26
27
28
29
30
31
32
33


34
35
36
37
38

39
40
41
42
43
44
45
25
26
27
28
29
30
31


32
33
34
35
36
37

38
39
40
41
42
43
44
45







-
-
+
+




-
+







{
	if (self == [OFMutableSet_hashtable class])
		[self inheritMethodsFromClass: [OFSet_hashtable class]];
}

- (void)addObject: (id)object
{
	[_mapTable setValue: (void*)1
		     forKey: object];
	[_mapTable setObject: (void*)1
		      forKey: object];
}

- (void)removeObject: (id)object
{
	[_mapTable removeValueForKey: object];
	[_mapTable removeObjectForKey: object];
}

- (void)makeImmutable
{
	object_setClass(self, [OFSet_hashtable class]);
}
@end

Modified src/OFOptionsParser.m from [917ac12657] to [69cbd54c95].

20
21
22
23
24
25
26
27

28
29

30
31
32
33

34
35

36
37
38
39
40
41
42
20
21
22
23
24
25
26

27
28

29
30
31
32

33
34

35
36
37
38
39
40
41
42







-
+

-
+



-
+

-
+







#import "OFApplication.h"
#import "OFArray.h"
#import "OFMapTable.h"

#import "OFInvalidArgumentException.h"

static uint32_t
stringHash(void *value)
stringHash(void *object)
{
	return [(OFString*)value hash];
	return [(OFString*)object hash];
}

static bool
stringEqual(void *value1, void *value2)
stringEqual(void *object1, void *object2)
{
	return [(OFString*)value1 isEqual: (OFString*)value2];
	return [(OFString*)object1 isEqual: (OFString*)object2];
}

@implementation OFOptionsParser
@synthesize lastOption = _lastOption, lastLongOption = _lastLongOption;
@synthesize argument = _argument;

+ (instancetype)parserWithOptions: (const of_options_parser_option_t*)options
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71







-
+







		size_t count = 0;
		const of_options_parser_option_t *iter;
		of_options_parser_option_t *iter2;
		const of_map_table_functions_t keyFunctions = {
			.hash = stringHash,
			.equal = stringEqual
		};
		const of_map_table_functions_t valueFunctions = { NULL };
		const of_map_table_functions_t objectFunctions = { NULL };

		/* Count, sanity check, initialize pointers */
		for (iter = options;
		    iter->shortOption != '\0' || iter->longOption != nil;
		    iter++) {
			if (iter->hasArgument < -1 || iter->hasArgument > 1)
				@throw [OFInvalidArgumentException exception];
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117


118
119
120
121
122
123
124
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115


116
117
118
119
120
121
122
123
124







-
+


















-
+






-
-
+
+







				*iter->argumentPtr = nil;

			count++;
		}

		_longOptions = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions];
			 objectFunctions: objectFunctions];
		_options = [self
		    allocMemoryWithSize: sizeof(*_options)
				  count: count + 1];

		for (iter = options, iter2 = _options;
		    iter->shortOption != '\0' || iter->longOption != nil;
		    iter++, iter2++) {
			iter2->shortOption = iter->shortOption;
			iter2->longOption = nil;
			iter2->hasArgument = iter->hasArgument;
			iter2->isSpecifiedPtr = iter->isSpecifiedPtr;
			iter2->argumentPtr = iter->argumentPtr;

			if (iter->longOption != nil) {
				@try {
					iter2->longOption =
					    [iter->longOption copy];

					if ([_longOptions valueForKey:
					if ([_longOptions objectForKey:
					    iter2->longOption] != NULL)
						@throw
						    [OFInvalidArgumentException
						    exception];

					[_longOptions
					    setValue: iter2
					      forKey: iter2->longOption];
					    setObject: iter2
					       forKey: iter2->longOption];
				} @catch (id e) {
					/*
					 * Make sure we are in a consistent
					 * state where dealloc works.
					 */
					[iter2->longOption release];

205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219







-
+







				pos = [argument length];

			_lastLongOption = [[argument substringWithRange:
			    of_range(2, pos - 2)] copy];

			objc_autoreleasePoolPop(pool);

			option = [_longOptions valueForKey: _lastLongOption];
			option = [_longOptions objectForKey: _lastLongOption];
			if (option == NULL)
				return '?';

			if (option->hasArgument == 1 && _argument == nil)
				return ':';
			if (option->hasArgument == 0 && _argument != nil)
				return '=';

Modified src/OFSet_hashtable.m from [97b4c86e48] to [c4c7c8ad52].

25
26
27
28
29
30
31
32

33
34

35
36
37
38

39
40

41
42
43
44

45
46

47
48
49
50

51
52

53
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
25
26
27
28
29
30
31

32
33

34
35
36
37

38
39

40
41
42
43

44
45

46
47
48
49

50
51

52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
83







-
+

-
+



-
+

-
+



-
+

-
+



-
+

-
+








-
+














-
+







#import "OFString.h"
#import "OFXMLElement.h"

#import "OFInvalidArgumentException.h"
#import "OFEnumerationMutationException.h"

static void*
retain(void *value)
retain(void *object)
{
	return [(id)value retain];
	return [(id)object retain];
}

static void
release(void *value)
release(void *object)
{
	[(id)value release];
	[(id)object release];
}

static uint32_t
hash(void *value)
hash(void *object)
{
	return [(id)value hash];
	return [(id)object hash];
}

static bool
equal(void *value1, void *value2)
equal(void *object1, void *object2)
{
	return [(id)value1 isEqual: (id)value2];
	return [(id)object1 isEqual: (id)object2];
}

static const of_map_table_functions_t keyFunctions = {
	.retain = retain,
	.release = release,
	.hash = hash,
	.equal = equal
};
static const of_map_table_functions_t valueFunctions = { NULL };
static const of_map_table_functions_t objectFunctions = { NULL };

@implementation OFSet_hashtable
- init
{
	return [self initWithCapacity: 0];
}

- initWithCapacity: (size_t)capacity
{
	self = [super init];

	@try {
		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions
			 objectFunctions: objectFunctions
				capacity: capacity];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
97
98
99
100
101
102
103
104
105


106
107
108
109
110
111
112
97
98
99
100
101
102
103


104
105
106
107
108
109
110
111
112







-
-
+
+







		@throw e;
	}

	self = [self initWithCapacity: count];

	@try {
		for (id object in set)
			[_mapTable setValue: (void*)1
				     forKey: object];
			[_mapTable setObject: (void*)1
				      forKey: object];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
125
126
127
128
129
130
131
132
133


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150


151
152
153
154
155
156
157
125
126
127
128
129
130
131


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148


149
150
151
152
153
154
155
156
157







-
-
+
+















-
-
+
+







		@throw e;
	}

	self = [self initWithCapacity: count];

	@try {
		for (id object in array)
			[_mapTable setValue: (void*)1
				     forKey: object];
			[_mapTable setObject: (void*)1
				      forKey: object];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithObjects: (id const*)objects
	    count: (size_t)count
{
	self = [self initWithCapacity: count];

	@try {
		for (size_t i = 0; i < count; i++)
			[_mapTable setValue: (void*)1
				     forKey: objects[i]];
			[_mapTable setObject: (void*)1
				      forKey: objects[i]];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
168
169
170
171
172
173
174
175

176
177
178
179


180
181
182
183


184
185
186
187
188
189
190
168
169
170
171
172
173
174

175
176
177


178
179
180
181


182
183
184
185
186
187
188
189
190







-
+


-
-
+
+


-
-
+
+








		va_copy(argumentsCopy, arguments);

		for (count = 1; va_arg(argumentsCopy, id) != nil; count++);

		_mapTable = [[OFMapTable alloc]
		    initWithKeyFunctions: keyFunctions
			  valueFunctions: valueFunctions
			 objectFunctions: objectFunctions
				capacity: count];

		[_mapTable setValue: (void*)1
			     forKey: firstObject];
		[_mapTable setObject: (void*)1
			      forKey: firstObject];

		while ((object = va_arg(arguments, id)) != nil)
			[_mapTable setValue: (void*)1
				     forKey: object];
			[_mapTable setObject: (void*)1
				      forKey: object];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
201
202
203
204
205
206
207
208
209


210
211
212
213
214
215
216
201
202
203
204
205
206
207


208
209
210
211
212
213
214
215
216







-
-
+
+







		    ![[element namespace] isEqual: OF_SERIALIZATION_NS])
			@throw [OFInvalidArgumentException exception];

		for (OFXMLElement *child in
		    [element elementsForNamespace: OF_SERIALIZATION_NS]) {
			void *pool2  = objc_autoreleasePoolPush();

			[_mapTable setValue: (void*)1
				     forKey: [child objectByDeserializing]];
			[_mapTable setObject: (void*)1
				      forKey: [child objectByDeserializing]];

			objc_autoreleasePoolPop(pool2);
		}

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
233
234
235
236
237
238
239
240

241
242
243
244
245
246
247
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247







-
+







}

- (bool)containsObject: (id)object
{
	if (object == nil)
		return false;

	return ([_mapTable valueForKey: object] != nil);
	return ([_mapTable objectForKey: object] != nil);
}

- (bool)isEqual: (id)object
{
	OFSet_hashtable *set;

	if (![object isKindOfClass: [OFSet_hashtable class]] &&
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269







-
+







}

- (id)anyObject
{
	void *pool = objc_autoreleasePoolPush();
	id object;

	object = [[_mapTable keyEnumerator] nextValue];
	object = [[_mapTable keyEnumerator] nextObject];
	object = [object retain];

	objc_autoreleasePoolPop(pool);

	return [object autorelease];
}

283
284
285
286
287
288
289
290
291


292
293
294
295
296
297
298
299
300
283
284
285
286
287
288
289


290
291
292
293
294
295
296
297
298
299
300







-
-
+
+









						count: count];
}

#ifdef OF_HAVE_BLOCKS
- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block
{
	@try {
		[_mapTable enumerateKeysAndValuesUsingBlock:
		    ^ (void *key, void *value, bool *stop) {
		[_mapTable enumerateKeysAndObjectsUsingBlock:
		    ^ (void *key, void *object, bool *stop) {
			block(key, stop);
		}];
	} @catch (OFEnumerationMutationException *e) {
		@throw [OFEnumerationMutationException
		    exceptionWithObject: self];
	}
}
#endif
@end