ObjFW  Check-in [8573ef86c6]

Overview
Comment:Make OFListItem opaque
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8573ef86c66de270eca67694b7497096154b0ab3ea3d1b365267201e72ad725e
User & Date: js on 2021-04-25 16:48:25
Other Links: manifest | tags
Context
2021-04-25
19:41
OFStrdup -> OFStrDup and slightly change behavior check-in: fd51df7022 user: js tags: trunk
16:48
Make OFListItem opaque check-in: 8573ef86c6 user: js tags: trunk
16:20
OFSecureData: Move chunkSize into #ifdef check-in: b648c7090f user: js tags: trunk
Changes

Modified src/OFList.h from [0c075514d1] to [0e994cc065].

16
17
18
19
20
21
22
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
16
17
18
19
20
21
22

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







-

-
+



-
-
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+












-
-
+
+








-
+












-
+







#import "OFObject.h"
#import "OFCollection.h"
#import "OFEnumerator.h"
#import "OFSerialization.h"

OF_ASSUME_NONNULL_BEGIN

typedef struct OFListItem OFListItem;
/**
 * @struct OFListItem OFList.h ObjFW/OFList.h
 * @typedef OFListItem OFList.h ObjFW/OFList.h
 *
 * @brief A list item.
 *
 * A struct that contains a pointer to the next list item, the previous list
 * item and the object.
 * See @ref OFListItemNext, @ref OFListItemPrevious and @ref OFListItemObject.
 */
struct OFListItem {
	/** A pointer to the next list object in the list */
	OFListItem *_Nullable next;
	/** A pointer to the previous list object in the list */
	OFListItem *_Nullable previous;
	/** The object for the list object */
	id __unsafe_unretained object;
typedef struct OFListItem *OFListItem;

#ifdef __cplusplus
extern "C" {
#endif
/*!
 * @brief Returns the next list item of the list item.
 *
 * @param listItem The list item for which the next list item should be returned
 * @return The next list item of the list item
 */
OFListItem OFListItemNext(OFListItem _Nonnull listItem);

/*!
 * @brief Returns the previous list item of the list item.
 *
 * @param listItem The list item for which the previous list item should be
 *		   returned
 * @return The previous list item of the list item
 */
OFListItem OFListItemPrevious(OFListItem _Nonnull listItem);

/*!
 * @brief Returns the object of the list item.
 *
 * @warning The returned object is not retained and autoreleased - this is the
 *	    caller's responsibility!
 *
 * @param listItem The list item for which the object should be returned
 * @return The object of the list item
};
 */
id OFListItemObject(OFListItem _Nonnull listItem);
#ifdef __cplusplus
}
#endif

/**
 * @class OFList OFList.h ObjFW/OFList.h
 *
 * @brief A class which provides easy to use double-linked lists.
 */
@interface OFList OF_GENERIC(ObjectType): OFObject <OFCopying, OFCollection,
    OFSerialization>
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# define ObjectType id
#endif
{
	OFListItem *_Nullable _firstListItem;
	OFListItem *_Nullable _lastListItem;
	OFListItem _Nullable _firstListItem;
	OFListItem _Nullable _lastListItem;
	size_t _count;
	unsigned long _mutations;
	OF_RESERVE_IVARS(OFList, 4)
}

/**
 * @brief The first list object of the list.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem *firstListItem;
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem firstListItem;

/**
 * @brief The first object of the list or `nil`.
 *
 * @warning The returned object is *not* retained and autoreleased for
 *	    performance reasons!
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) ObjectType firstObject;

/**
 * @brief The last list object of the list.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem *lastListItem;
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem lastListItem;

/**
 * @brief The last object of the list or `nil`.
 *
 * @warning The returned object is *not* retained and autoreleased for
 *	    performance reasons!
 */
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
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







-
+









-
+











-
-
+
+











-
-
+
+






-
+







 * @brief Appends an object to the list.
 *
 * @param object The object to append
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its OFListItem.
 */
- (OFListItem *)appendObject: (ObjectType)object;
- (OFListItem)appendObject: (ObjectType)object;

/**
 * @brief Prepends an object to the list.
 *
 * @param object The object to prepend
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its OFListItem.
 */
- (OFListItem *)prependObject: (ObjectType)object;
- (OFListItem)prependObject: (ObjectType)object;

/**
 * @brief Inserts an object before another list object.
 *
 * @param object The object to insert
 * @param listItem The OFListItem of the object before which it should be
 *		   inserted
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its OFListItem.
 */
- (OFListItem *)insertObject: (ObjectType)object
	      beforeListItem: (OFListItem *)listItem;
- (OFListItem)insertObject: (ObjectType)object
	    beforeListItem: (OFListItem)listItem;

/**
 * @brief Inserts an object after another list object.
 *
 * @param object The object to insert
 * @param listItem The OFListItem of the object after which it should be
 *	  inserted
 * @return An OFListItem, needed to identify the object inside the list.
 *	   For example, if you want to remove an object from the list, you need
 *	   its OFListItem.
 */
- (OFListItem *)insertObject: (ObjectType)object
	       afterListItem: (OFListItem *)listItem;
- (OFListItem)insertObject: (ObjectType)object
	     afterListItem: (OFListItem)listItem;

/**
 * @brief Removes the object with the specified list object from the list.
 *
 * @param listItem The list object returned by append / prepend
 */
- (void)removeListItem: (OFListItem *)listItem;
- (void)removeListItem: (OFListItem)listItem;

/**
 * @brief Checks whether the list contains an object equal to the specified
 *	  object.
 *
 * @param object The object which is checked for being in the list
 * @return A boolean whether the list contains the specified object

Modified src/OFList.m from [270e405c2f] to [71b5abf54f].

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







+
+
+
+
+





-
+







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







#import "OFList.h"
#import "OFString.h"
#import "OFXMLElement.h"
#import "OFArray.h"

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

struct OFListItem {
	OFListItem previous, next;
	id object;
};

OF_DIRECT_MEMBERS
@interface OFListEnumerator: OFEnumerator
{
	OFList *_list;
	OFListItem *_Nullable _current;
	OFListItem _Nullable _current;
	unsigned long _mutations;
	unsigned long *_Nullable _mutationsPtr;
}

- (instancetype)initWithList: (OFList *)list
	    mutationsPointer: (unsigned long *)mutationsPtr;
@end

OFListItem
OFListItemNext(OFListItem listItem)
{
	return listItem->next;
}

OFListItem
OFListItemPrevious(OFListItem listItem)
{
	return listItem->previous;
}

id
OFListItemObject(OFListItem listItem)
{
	return listItem->object;
}

@implementation OFList
@synthesize firstListItem = _firstListItem, lastListItem = _lastListItem;

+ (instancetype)list
{
	return [[[self alloc] init] autorelease];
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
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







-
+

-
+








-
+

-
+

-


















-
+

-
+


















-
-
+

-
+



















-
-
+

-
+



















-
+







	}

	return self;
}

- (void)dealloc
{
	OFListItem *next;
	OFListItem next;

	for (OFListItem *iter = _firstListItem; iter != NULL; iter = next) {
	for (OFListItem iter = _firstListItem; iter != NULL; iter = next) {
		[iter->object release];
		next = iter->next;
		OFFreeMemory(iter);
	}

	[super dealloc];
}

- (OFListItem *)appendObject: (id)object
- (OFListItem)appendObject: (id)object
{
	OFListItem *listItem;
	OFListItem listItem = OFAllocMemory(1, sizeof(*listItem));

	listItem = OFAllocMemory(1, sizeof(OFListItem));
	listItem->object = [object retain];
	listItem->next = NULL;
	listItem->previous = _lastListItem;

	if (_lastListItem != NULL)
		_lastListItem->next = listItem;

	_lastListItem = listItem;

	if (_firstListItem == NULL)
		_firstListItem = listItem;

	_count++;
	_mutations++;

	return listItem;
}

- (OFListItem *)prependObject: (id)object
- (OFListItem)prependObject: (id)object
{
	OFListItem *listItem = OFAllocMemory(1, sizeof(OFListItem));
	OFListItem listItem = OFAllocMemory(1, sizeof(*listItem));

	listItem->object = [object retain];
	listItem->next = _firstListItem;
	listItem->previous = NULL;

	if (_firstListItem != NULL)
		_firstListItem->previous = listItem;

	_firstListItem = listItem;
	if (_lastListItem == NULL)
		_lastListItem = listItem;

	_count++;
	_mutations++;

	return listItem;
}

- (OFListItem *)insertObject: (id)object
	      beforeListItem: (OFListItem *)listItem
- (OFListItem)insertObject: (id)object beforeListItem: (OFListItem)listItem
{
	OFListItem *newListItem = OFAllocMemory(1, sizeof(OFListItem));
	OFListItem newListItem = OFAllocMemory(1, sizeof(*newListItem));

	newListItem->object = [object retain];
	newListItem->next = listItem;
	newListItem->previous = listItem->previous;

	if (listItem->previous != NULL)
		listItem->previous->next = newListItem;

	listItem->previous = newListItem;

	if (listItem == _firstListItem)
		_firstListItem = newListItem;

	_count++;
	_mutations++;

	return newListItem;
}

- (OFListItem *)insertObject: (id)object
	       afterListItem: (OFListItem *)listItem
- (OFListItem)insertObject: (id)object afterListItem: (OFListItem)listItem
{
	OFListItem *newListItem = OFAllocMemory(1, sizeof(OFListItem));
	OFListItem newListItem = OFAllocMemory(1, sizeof(*newListItem));

	newListItem->object = [object retain];
	newListItem->next = listItem->next;
	newListItem->previous = listItem;

	if (listItem->next != NULL)
		listItem->next->previous = newListItem;

	listItem->next = newListItem;

	if (listItem == _lastListItem)
		_lastListItem = newListItem;

	_count++;
	_mutations++;

	return newListItem;
}

- (void)removeListItem: (OFListItem *)listItem
- (void)removeListItem: (OFListItem)listItem
{
	if (listItem->previous != NULL)
		listItem->previous->next = listItem->next;
	if (listItem->next != NULL)
		listItem->next->previous = listItem->previous;

	if (_firstListItem == listItem)
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246







-
+







{
	return _count;
}

- (bool)isEqual: (id)object
{
	OFList *list;
	OFListItem *iter, *iter2;
	OFListItem iter, iter2;

	if (object == self)
		return true;

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

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
301
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
301
302
303
304
305




306
307
308

309
310

311
312
313
314
315
316
317
318







-
+











-
+








-
+



-
+











-
-
-
-
+


-
+

-
+







}

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

	for (OFListItem *iter = _firstListItem; iter != NULL; iter = iter->next)
	for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next)
		if ([iter->object isEqual: object])
			return true;

	return false;
}

- (bool)containsObjectIdenticalTo: (id)object
{
	if (_count == 0)
		return false;

	for (OFListItem *iter = _firstListItem; iter != NULL; iter = iter->next)
	for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next)
		if (iter->object == object)
			return true;

	return false;
}

- (void)removeAllObjects
{
	OFListItem *next;
	OFListItem next;

	_mutations++;

	for (OFListItem *iter = _firstListItem; iter != NULL; iter = next) {
	for (OFListItem iter = _firstListItem; iter != NULL; iter = next) {
		[iter->object release];
		next = iter->next;
		OFFreeMemory(iter);
	}

	_firstListItem = _lastListItem = NULL;
}

- (id)copy
{
	OFList *copy = [[[self class] alloc] init];
	OFListItem *listItem, *previous;

	listItem = NULL;
	previous = NULL;
	OFListItem listItem = NULL, previous = NULL;

	@try {
		for (OFListItem *iter = _firstListItem;
		for (OFListItem iter = _firstListItem;
		    iter != NULL; iter = iter->next) {
			listItem = OFAllocMemory(1, sizeof(OFListItem));
			listItem = OFAllocMemory(1, sizeof(*listItem));
			listItem->object = [iter->object retain];
			listItem->next = NULL;
			listItem->previous = previous;

			if (copy->_firstListItem == NULL)
				copy->_firstListItem = listItem;
			if (previous != NULL)
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
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







-
+
















-
+








- (unsigned long)hash
{
	unsigned long hash;

	OFHashInit(&hash);

	for (OFListItem *iter = _firstListItem; iter != NULL; iter = iter->next)
	for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next)
		OFHashAddHash(&hash, [iter->object hash]);

	OFHashFinalize(&hash);

	return hash;
}

- (OFString *)description
{
	OFMutableString *ret;

	if (_count == 0)
		return @"[]";

	ret = [OFMutableString stringWithString: @"[\n"];

	for (OFListItem *iter = _firstListItem;
	for (OFListItem iter = _firstListItem;
	    iter != NULL; iter = iter->next) {
		void *pool = objc_autoreleasePoolPush();

		[ret appendString: [iter->object description]];

		if (iter->next != NULL)
			[ret appendString: @",\n"];
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
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







-
+















-
+








- (OFXMLElement *)XMLElementBySerializing
{
	OFXMLElement *element =
	    [OFXMLElement elementWithName: self.className
				namespace: OFSerializationNS];

	for (OFListItem *iter = _firstListItem;
	for (OFListItem iter = _firstListItem;
	    iter != NULL; iter = iter->next) {
		void *pool = objc_autoreleasePoolPush();

		[element addChild: [iter->object XMLElementBySerializing]];

		objc_autoreleasePoolPop(pool);
	}

	return element;
}

- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	OFListItem *listItem;
	OFListItem listItem;

	memcpy(&listItem, state->extra, sizeof(listItem));

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

	if (state->state == 0) {

Modified src/OFRunLoop.m from [ffb2965c25] to [ab97878b5e].

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







-
+













+
-
+







	OFList OF_GENERIC(OF_KINDOF(OFRunLoopReadQueueItem *)) *queue =
	    [[_readQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![queue.firstObject handleObject: object]) {
			OFListItem *listItem = queue.firstListItem;
			OFListItem listItem = queue.firstListItem;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listItem != NULL) {
				/*
				 * Make sure we keep the target until after we
				 * are done removing the object. The reason for
				 * this is that the target might call
				 * -[cancelAsyncRequests] in its dealloc.
				 */
				[[OFListItemObject(listItem) retain]
				[[listItem->object retain] autorelease];
				    autorelease];

				[queue removeListItem: listItem];

				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForReading: object];
					[_readQueues
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
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







-
+













+
-
+







	 */
	OFList *queue = [[_writeQueues objectForKey: object] retain];

	assert(queue != nil);

	@try {
		if (![queue.firstObject handleObject: object]) {
			OFListItem *listItem = queue.firstListItem;
			OFListItem listItem = queue.firstListItem;

			/*
			 * The handler might have called -[cancelAsyncRequests]
			 * so that our queue is now empty, in which case we
			 * should do nothing.
			 */
			if (listItem != NULL) {
				/*
				 * Make sure we keep the target until after we
				 * are done removing the object. The reason for
				 * this is that the target might call
				 * -[cancelAsyncRequests] in its dealloc.
				 */
				[[OFListItemObject(listItem) retain]
				[[listItem->object retain] autorelease];
				    autorelease];

				[queue removeListItem: listItem];

				if (queue.count == 0) {
					[_kernelEventObserver
					    removeObjectForWriting: object];
					[_writeQueues
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425



1426
1427
1428
1429
1430
1431
1432
1418
1419
1420
1421
1422
1423
1424



1425
1426
1427
1428
1429
1430
1431
1432
1433
1434







-
-
-
+
+
+







	if (state == nil)
		return;

#ifdef OF_HAVE_THREADS
	[state->_timersQueueMutex lock];
	@try {
#endif
		for (OFListItem *iter = state->_timersQueue.firstListItem;
		    iter != NULL; iter = iter->next) {
			if ([iter->object isEqual: timer]) {
		for (OFListItem iter = state->_timersQueue.firstListItem;
		    iter != NULL; iter = OFListItemNext(iter)) {
			if ([OFListItemObject(iter) isEqual: timer]) {
				[state->_timersQueue removeListItem: iter];
				break;
			}
		}
#ifdef OF_HAVE_THREADS
	} @finally {
		[state->_timersQueueMutex unlock];
1573
1574
1575
1576
1577
1578
1579
1580

1581
1582
1583
1584
1585




1586
1587
1588
1589
1590
1591
1592
1575
1576
1577
1578
1579
1580
1581

1582
1583
1584



1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595







-
+


-
-
-
+
+
+
+







		for (;;) {
			OFTimer *timer;

#ifdef OF_HAVE_THREADS
			[state->_timersQueueMutex lock];
			@try {
#endif
				OFListItem *listItem =
				OFListItem listItem =
				    state->_timersQueue.firstListItem;

				if (listItem != NULL && [listItem->object
				    fireDate].timeIntervalSinceNow <= 0) {
					timer = [[listItem->object
				if (listItem != NULL &&
				    [OFListItemObject(listItem) fireDate]
				    .timeIntervalSinceNow <= 0) {
					timer = [[OFListItemObject(listItem)
					    retain] autorelease];

					[state->_timersQueue
					    removeListItem: listItem];

					[timer of_setInRunLoop: nil mode: nil];
				} else

Modified src/OFSortedList.h from [10d4fe8869] to [a53236cd47].

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







-
-
-
-
+
+
+
+
-
-
-
+
+
-







-
+






#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# define ObjectType id
#endif
{
	OF_RESERVE_IVARS(OFSortedList, 4)
}

- (OFListItem *)appendObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem *)prependObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem *)insertObject: (ObjectType)object
	      beforeListItem: (OFListItem *)listItem
- (OFListItem)appendObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem)prependObject: (ObjectType)object OF_UNAVAILABLE;
- (OFListItem)insertObject: (ObjectType)object
	    beforeListItem: (OFListItem)listItem OF_UNAVAILABLE;
    OF_UNAVAILABLE;
- (OFListItem *)insertObject: (ObjectType)object
	       afterListItem: (OFListItem *)listItem
- (OFListItem)insertObject: (ObjectType)object
	     afterListItem: (OFListItem)listItem OF_UNAVAILABLE;
    OF_UNAVAILABLE;

/**
 * @brief Inserts the object to the list while keeping the list sorted.
 *
 * @param object The object to insert
 * @return The list object for the object just added
 */
- (OFListItem *)insertObject: (ObjectType <OFComparing>)object;
- (OFListItem)insertObject: (ObjectType <OFComparing>)object;
#if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN)
# undef ObjectType
#endif
@end

OF_ASSUME_NONNULL_END

Modified src/OFSortedList.m from [228aa13ba0] to [647acba740].

14
15
16
17
18
19
20
21






22
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
14
15
16
17
18
19
20

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







-
+
+
+
+
+
+




-
+




-
+
-




-
-
-
-
-
-
-
+

-
+

-
-
+
+
+
+






 */

#include "config.h"

#import "OFSortedList.h"

@implementation OFSortedList
- (OFListItem *)appendObject: (id)object
- (OFListItem)appendObject: (id)object
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFListItem)prependObject: (id)object
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFListItem *)prependObject: (id)object
- (OFListItem)insertObject: (id)object beforeListItem: (OFListItem)listItem
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFListItem *)insertObject: (id)object
- (OFListItem)insertObject: (id)object afterListItem: (OFListItem)listItem
	      beforeListItem: (OFListItem *)listItem
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFListItem *)insertObject: (id)object
	       afterListItem: (OFListItem *)listItem
{
	OF_UNRECOGNIZED_SELECTOR
}

- (OFListItem *)insertObject: (id <OFComparing>)object
- (OFListItem)insertObject: (id <OFComparing>)object
{
	OFListItem *iter;
	OFListItem iter;

	for (iter = _lastListItem; iter != NULL; iter = iter->previous) {
		if ([object compare: iter->object] != OFOrderedAscending)
	for (iter = _lastListItem; iter != NULL;
	    iter = OFListItemPrevious(iter)) {
		if ([object compare: OFListItemObject(iter)] !=
		    OFOrderedAscending)
			return [super insertObject: object afterListItem: iter];
	}

	return [super prependObject: object];
}
@end

Modified src/OFThreadPool.m from [62afef694d] to [bf37211055].

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







-
+



















-
+







	pool = objc_autoreleasePoolPush();

	for (;;) {
		OFThreadPoolJob *job;

		[_queueCondition lock];
		@try {
			OFListItem *listItem;
			OFListItem listItem;

			if (_terminate) {
				objc_autoreleasePoolPop(pool);
				return nil;
			}

			listItem = _queue.firstListItem;

			while (listItem == NULL) {
				[_queueCondition wait];

				if (_terminate) {
					objc_autoreleasePoolPop(pool);
					return nil;
				}

				listItem = _queue.firstListItem;
			}

			job = [[listItem->object retain] autorelease];
			job = [[OFListItemObject(listItem) retain] autorelease];
			[_queue removeListItem: listItem];
		} @finally {
			[_queueCondition unlock];
		}

		if (_terminate) {
			objc_autoreleasePoolPop(pool);

Modified tests/OFListTests.m from [045f6f7c6a] to [ede47645fa].

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







-
+










-
+

+
-
-
+
+


-
+

+
-
-
+
+



-
+

-
+



+
-
+



-
-
+
+













-
-
-
+
+
+
+












-
+


-
+




















-
+


-
+








@implementation TestsAppDelegate (OFListTests)
- (void)listTests
{
	void *pool = objc_autoreleasePoolPush();
	OFList *list;
	OFEnumerator *enumerator;
	OFListItem *iter;
	OFListItem iter;
	OFString *obj;
	size_t i;
	bool ok;

	TEST(@"+[list]", (list = [OFList list]))

	TEST(@"-[appendObject:]", [list appendObject: strings[0]] &&
	    [list appendObject: strings[1]] && [list appendObject: strings[2]])

	TEST(@"-[firstListItem]",
	    [list.firstListItem->object isEqual: strings[0]])
	    [OFListItemObject(list.firstListItem) isEqual: strings[0]])

	TEST(@"OFListItemNext()",
	TEST(@"-[firstListItem]->next",
	    [list.firstListItem->next->object isEqual: strings[1]])
	    [OFListItemObject(OFListItemNext(list.firstListItem))
	    isEqual: strings[1]])

	TEST(@"-[lastListItem]",
	    [list.lastListItem->object isEqual: strings[2]])
	    [OFListItemObject(list.lastListItem) isEqual: strings[2]])

	TEST(@"OFListItemPrevious()",
	TEST(@"-[lastListItem]->previous",
	    [list.lastListItem->previous->object isEqual: strings[1]])
	    [OFListItemObject(OFListItemPrevious(list.lastListItem))
	    isEqual: strings[1]])

	TEST(@"-[removeListItem:]",
	    R([list removeListItem: list.lastListItem]) &&
	    [list.lastListItem->object isEqual: strings[1]] &&
	    [list.lastObject isEqual: strings[1]] &&
	    R([list removeListItem: list.firstListItem]) &&
	    [list.firstListItem->object isEqual: list.lastListItem->object])
	    [list.firstObject isEqual: list.lastObject])

	TEST(@"-[insertObject:beforeListItem:]",
	    [list insertObject: strings[0] beforeListItem: list.lastListItem] &&
	    [OFListItemObject(OFListItemPrevious(list.lastListItem))
	    [list.lastListItem->previous->object isEqual: strings[0]])
	    isEqual: strings[0]])

	TEST(@"-[insertObject:afterListItem:]",
	    [list insertObject: strings[2]
		 afterListItem: list.firstListItem->next] &&
	    [list.lastListItem->object isEqual: strings[2]])
		 afterListItem: OFListItemNext(list.firstListItem)] &&
	    [list.lastObject isEqual: strings[2]])

	TEST(@"-[count]", list.count == 3)

	TEST(@"-[containsObject:]",
	    [list containsObject: strings[1]] &&
	    ![list containsObject: @"nonexistent"])

	TEST(@"-[containsObjectIdenticalTo:]",
	    [list containsObjectIdenticalTo: strings[1]] &&
	    ![list containsObjectIdenticalTo:
	    [OFString stringWithString: strings[1]]])

	TEST(@"-[copy]", (list = [[list copy] autorelease]) &&
	    [list.firstListItem->object isEqual: strings[0]] &&
	    [list.firstListItem->next->object isEqual: strings[1]] &&
	    [list.lastListItem->object isEqual: strings[2]])
	    [list.firstObject isEqual: strings[0]] &&
	    [OFListItemObject(OFListItemNext(list.firstListItem))
	    isEqual: strings[1]] &&
	    [list.lastObject isEqual: strings[2]])

	TEST(@"-[isEqual:]", [list isEqual: [[list copy] autorelease]])

	TEST(@"-[description]",
	    [list.description isEqual: @"[\n\tFoo,\n\tBar,\n\tBaz\n]"])

	TEST(@"-[objectEnumerator]", (enumerator = [list objectEnumerator]))

	iter = list.firstListItem;
	i = 0;
	ok = true;
	while ((obj = [enumerator nextObject]) != nil) {
		if (![obj isEqual: iter->object])
		if (![obj isEqual: OFListItemObject(iter)])
			ok = false;

		iter = iter->next;
		iter = OFListItemNext(iter);
		i++;
	}

	if (list.count != i)
		ok = false;

	TEST(@"OFEnumerator's -[nextObject]", ok);

	[list removeListItem: list.firstListItem];

	EXPECT_EXCEPTION(@"Detection of mutation during enumeration",
	    OFEnumerationMutationException, [enumerator nextObject])

	[list prependObject: strings[0]];

	iter = list.firstListItem;
	i = 0;
	ok = true;

	for (OFString *object in list) {
		if (![object isEqual: iter->object])
		if (![object isEqual: OFListItemObject(iter)])
			ok = false;

		iter = iter->next;
		iter = OFListItemNext(iter);
		i++;
	}

	if (list.count != i)
		ok = false;

	TEST(@"Fast Enumeration", ok)