ObjFW  Check-in [96f946d7ad]

Overview
Comment:Use unsigned long for bit sets

This should be more efficient on some architectures.

As a nice side effect, this is also what Linux does in some userspace
APIs, so after this change, these macros can be used for this as well
(and Linux interestingly does not provide similar macros in the
userspace headers).

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 96f946d7ad5a1f5a96b35578004bc1e50fa459afbf3169f4140dde2e6f4618f5
User & Date: js on 2024-05-09 10:21:24
Other Links: manifest | tags
Context
2024-05-11
18:02
configure: Check whether blx is available on ARM check-in: 4f3f90e5e7 user: js tags: trunk
2024-05-09
10:22
Merge trunk into branch "gamecontroller" check-in: c0a80a897d user: js tags: gamecontroller
10:21
Use unsigned long for bit sets check-in: 96f946d7ad user: js tags: trunk
2024-05-05
19:04
OFStdIOStream: Add special case for column 0 check-in: 1c2fe75e6e user: js tags: trunk
Changes

Modified src/OFBitSetCharacterSet.h from [9f3314050d] to [ba3d4f6a9d].

19
20
21
22
23
24
25
26
27
28
29
30
31

#import "OFCharacterSet.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFBitSetCharacterSet: OFCharacterSet
{
	unsigned char *_bitset;
	size_t _size;
}
@end

OF_ASSUME_NONNULL_END







|





19
20
21
22
23
24
25
26
27
28
29
30
31

#import "OFCharacterSet.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFBitSetCharacterSet: OFCharacterSet
{
	unsigned long *_bitSet;
	size_t _size;
}
@end

OF_ASSUME_NONNULL_END

Modified src/OFBitSetCharacterSet.m from [b1982608cc] to [9db9ebbd67].

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
		void *pool = objc_autoreleasePoolPush();
		const OFUnichar *characters = string.characters;
		size_t length = string.length;

		for (size_t i = 0; i < length; i++) {
			OFUnichar c = characters[i];

			if (c / CHAR_BIT >= _size) {
				size_t newSize;

				if (UINT32_MAX - c < 1)
					@throw [OFOutOfRangeException
					    exception];

				newSize = OFRoundUpToPowerOf2(CHAR_BIT, c + 1) /
				    CHAR_BIT;

				_bitset = OFResizeMemory(_bitset, newSize, 1);

				memset(_bitset + _size, '\0', newSize - _size);


				_size = newSize;
			}

			OFBitsetSet(_bitset, c);
		}

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

	return self;
}

- (void)dealloc
{
	OFFreeMemory(_bitset);

	[super dealloc];
}

- (bool)characterIsMember: (OFUnichar)character
{
	if (character / CHAR_BIT >= _size)
		return false;

	return OFBitsetIsSet(_bitset, character);
}
@end







|






|
|

|
>
|
>




|













|






|


|


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
		void *pool = objc_autoreleasePoolPush();
		const OFUnichar *characters = string.characters;
		size_t length = string.length;

		for (size_t i = 0; i < length; i++) {
			OFUnichar c = characters[i];

			if (c / OF_ULONG_BIT >= _size) {
				size_t newSize;

				if (UINT32_MAX - c < 1)
					@throw [OFOutOfRangeException
					    exception];

				newSize = OFRoundUpToPowerOf2(OF_ULONG_BIT,
				    c + 1) / OF_ULONG_BIT;

				_bitSet = OFResizeMemory(_bitSet, newSize,
				    sizeof(unsigned long));
				memset(_bitSet + _size, '\0',
				    (newSize - _size) * sizeof(unsigned long));

				_size = newSize;
			}

			OFBitSetSet(_bitSet, c);
		}

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

	return self;
}

- (void)dealloc
{
	OFFreeMemory(_bitSet);

	[super dealloc];
}

- (bool)characterIsMember: (OFUnichar)character
{
	if (character / OF_ULONG_BIT >= _size)
		return false;

	return OFBitSetIsSet(_bitSet, character);
}
@end

Modified src/OFSecureData.m from [5df33e3bf5] to [d0c4634748].

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#import "OFOutOfRangeException.h"

#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
static const size_t chunkSize = 16;

struct Page {
	struct Page *next, *previous;
	void *map;
	unsigned char *page;
};

# if defined(OF_HAVE_COMPILER_TLS)
static thread_local struct Page *firstPage = NULL;
static thread_local struct Page *lastPage = NULL;
static thread_local struct Page **preallocatedPages = NULL;







|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#import "OFOutOfRangeException.h"

#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
static const size_t chunkSize = 16;

struct Page {
	struct Page *next, *previous;
	unsigned long *map;
	unsigned char *page;
};

# if defined(OF_HAVE_COMPILER_TLS)
static thread_local struct Page *firstPage = NULL;
static thread_local struct Page *lastPage = NULL;
static thread_local struct Page **preallocatedPages = NULL;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
	munmap(pointer, numPages * pageSize);
}

static struct Page *
addPage(bool allowPreallocated)
{
	size_t pageSize = [OFSystemInfo pageSize];
	size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
	    CHAR_BIT;
	struct Page *page;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	struct Page *lastPage;
# endif

	if (allowPreallocated) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)







|
|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
	munmap(pointer, numPages * pageSize);
}

static struct Page *
addPage(bool allowPreallocated)
{
	size_t pageSize = [OFSystemInfo pageSize];
	size_t mapSize = OFRoundUpToPowerOf2(OF_ULONG_BIT,
	    pageSize / chunkSize) / OF_ULONG_BIT;
	struct Page *page;
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
	struct Page *lastPage;
# endif

	if (allowPreallocated) {
# if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS)
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

			return page;
		}
	}

	page = OFAllocMemory(1, sizeof(*page));
	@try {
		page->map = OFAllocZeroedMemory(1, mapSize);
	} @catch (id e) {
		OFFreeMemory(page);
		@throw e;
	}
	@try {
		page->page = mapPages(1);
	} @catch (id e) {







|







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

			return page;
		}
	}

	page = OFAllocMemory(1, sizeof(*page));
	@try {
		page->map = OFAllocZeroedMemory(mapSize, sizeof(unsigned long));
	} @catch (id e) {
		OFFreeMemory(page);
		@throw e;
	}
	@try {
		page->page = mapPages(1);
	} @catch (id e) {
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

	return page;
}

static void
removePageIfEmpty(struct Page *page)
{
	unsigned char *map = page->map;
	size_t pageSize = [OFSystemInfo pageSize];
	size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) /
	    CHAR_BIT;

	for (size_t i = 0; i < mapSize; i++)
		if (map[i] != 0)
			return;

	unmapPages(page->page, 1);
	OFFreeMemory(page->map);







|

|
|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

	return page;
}

static void
removePageIfEmpty(struct Page *page)
{
	unsigned long *map = page->map;
	size_t pageSize = [OFSystemInfo pageSize];
	size_t mapSize = OFRoundUpToPowerOf2(OF_ULONG_BIT,
	    pageSize / chunkSize) / OF_ULONG_BIT;

	for (size_t i = 0; i < mapSize; i++)
		if (map[i] != 0)
			return;

	unmapPages(page->page, 1);
	OFFreeMemory(page->map);
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

	bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
	chunks = chunksLeft = bytes / chunkSize;
	firstChunk = 0;
	pageSize = [OFSystemInfo pageSize];

	for (i = 0; i < pageSize / chunkSize; i++) {
		if (OFBitsetIsSet(page->map, i)) {
			chunksLeft = chunks;
			firstChunk = i + 1;
			continue;
		}

		if (--chunksLeft == 0)
			break;
	}

	if (chunksLeft == 0) {
		for (size_t j = firstChunk; j < firstChunk + chunks; j++)
			OFBitsetSet(page->map, j);

		return page->page + (chunkSize * firstChunk);
	}

	return NULL;
}

static void
freeMemory(struct Page *page, void *pointer, size_t bytes)
{
	size_t chunks, chunkIndex;

	bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
	chunks = bytes / chunkSize;
	chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / chunkSize;

	OFZeroMemory(pointer, bytes);

	for (size_t i = 0; i < chunks; i++)
		OFBitsetClear(page->map, chunkIndex + i);
}
#endif

@implementation OFSecureData
@synthesize allowsSwappableMemory = _allowsSwappableMemory;

#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) && \







|











|



















|







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

	bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
	chunks = chunksLeft = bytes / chunkSize;
	firstChunk = 0;
	pageSize = [OFSystemInfo pageSize];

	for (i = 0; i < pageSize / chunkSize; i++) {
		if (OFBitSetIsSet(page->map, i)) {
			chunksLeft = chunks;
			firstChunk = i + 1;
			continue;
		}

		if (--chunksLeft == 0)
			break;
	}

	if (chunksLeft == 0) {
		for (size_t j = firstChunk; j < firstChunk + chunks; j++)
			OFBitSetSet(page->map, j);

		return page->page + (chunkSize * firstChunk);
	}

	return NULL;
}

static void
freeMemory(struct Page *page, void *pointer, size_t bytes)
{
	size_t chunks, chunkIndex;

	bytes = OFRoundUpToPowerOf2(chunkSize, bytes);
	chunks = bytes / chunkSize;
	chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / chunkSize;

	OFZeroMemory(pointer, bytes);

	for (size_t i = 0; i < chunks; i++)
		OFBitSetClear(page->map, chunkIndex + i);
}
#endif

@implementation OFSecureData
@synthesize allowsSwappableMemory = _allowsSwappableMemory;

#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) && \

Modified src/macros.h from [e71e68e9ff] to [3c8f4714cc].

936
937
938
939
940
941
942


943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
 * @param pow2 The power of 2 to round up to
 * @param value The value to round up to the specified power of two
 * @return The specified value rounded up to the specified power of two
 */
#define OFRoundUpToPowerOf2(pow2, value)	\
    (((value) + (pow2) - 1) & ~((pow2) - 1))



static OF_INLINE bool
OFBitsetIsSet(unsigned char *_Nonnull storage, size_t idx)
{
	return storage[idx / CHAR_BIT] & (1u << (idx % CHAR_BIT));
}

static OF_INLINE void
OFBitsetSet(unsigned char *_Nonnull storage, size_t idx)
{
	storage[idx / CHAR_BIT] |= (1u << (idx % CHAR_BIT));
}

static OF_INLINE void
OFBitsetClear(unsigned char *_Nonnull storage, size_t idx)
{
	storage[idx / CHAR_BIT] &= ~(1u << (idx % CHAR_BIT));
}

static OF_INLINE void
OFZeroMemory(void *_Nonnull buffer_, size_t length)
{
	volatile unsigned char *buffer = (volatile unsigned char *)buffer_;








>
>

|

|



|

|



|

|







936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
 * @param pow2 The power of 2 to round up to
 * @param value The value to round up to the specified power of two
 * @return The specified value rounded up to the specified power of two
 */
#define OFRoundUpToPowerOf2(pow2, value)	\
    (((value) + (pow2) - 1) & ~((pow2) - 1))

#define OF_ULONG_BIT (sizeof(unsigned long) * CHAR_BIT)

static OF_INLINE bool
OFBitSetIsSet(unsigned long *_Nonnull storage, size_t idx)
{
	return storage[idx / OF_ULONG_BIT] & (1ul << (idx % OF_ULONG_BIT));
}

static OF_INLINE void
OFBitSetSet(unsigned long *_Nonnull storage, size_t idx)
{
	storage[idx / OF_ULONG_BIT] |= (1ul << (idx % OF_ULONG_BIT));
}

static OF_INLINE void
OFBitSetClear(unsigned long *_Nonnull storage, size_t idx)
{
	storage[idx / OF_ULONG_BIT] &= ~(1ul << (idx % OF_ULONG_BIT));
}

static OF_INLINE void
OFZeroMemory(void *_Nonnull buffer_, size_t length)
{
	volatile unsigned char *buffer = (volatile unsigned char *)buffer_;