ObjFW  Check-in [6a0bf8be32]

Overview
Comment:Force inline tryReadBits and of_huffman_tree_walk

This gives a significant performance improvement, cutting decompression
time almost in half.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6a0bf8be32bfd09b94bac4ab6700c463ea0972e8442203ef735a45776fa1ea19
User & Date: js on 2019-03-20 21:04:36
Other Links: manifest | tags
Context
2019-03-21
23:29
ofhash: Allow calculating multiple hashes at once check-in: 0c72729961 user: js tags: trunk
2019-03-20
21:04
Force inline tryReadBits and of_huffman_tree_walk check-in: 6a0bf8be32 user: js tags: trunk
2019-03-19
22:36
OFHTTPClient: Compare port using -[isEqual:] check-in: eadd1a0c54 user: js tags: trunk
Changes

Modified src/OFInflateStream.m from [98e2dc75e9] to [5b9953e18a].

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
};
#endif
static const uint8_t codeLengthsOrder[19] = {
	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
static struct of_huffman_tree *fixedLitLenTree, *fixedDistTree;

static bool
tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count)
{
	uint16_t ret = stream->_savedBits;

	assert(stream->_savedBitsLength < count);

	for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) {
		if OF_UNLIKELY (stream->_bitIndex == 8) {

			if (stream->_bufferIndex < stream->_bufferLength)
				stream->_byte =
				    stream->_buffer[stream->_bufferIndex++];
			else {
				size_t length = [stream->_stream
				    readIntoBuffer: stream->_buffer
					    length: BUFFER_SIZE];








|








>
|







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
};
#endif
static const uint8_t codeLengthsOrder[19] = {
	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
static struct of_huffman_tree *fixedLitLenTree, *fixedDistTree;

static OF_INLINE bool
tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count)
{
	uint16_t ret = stream->_savedBits;

	assert(stream->_savedBitsLength < count);

	for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) {
		if OF_UNLIKELY (stream->_bitIndex == 8) {
			if OF_LIKELY (stream->_bufferIndex <
			    stream->_bufferLength)
				stream->_byte =
				    stream->_buffer[stream->_bufferIndex++];
			else {
				size_t length = [stream->_stream
				    readIntoBuffer: stream->_buffer
					    length: BUFFER_SIZE];

Modified src/OFLHAArchive_LHStream.m from [ee397f8bd5] to [53f546e890].

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
	STATE_DIST_TREE_SINGLE,
	STATE_BLOCK_LITLEN,
	STATE_BLOCK_DIST_LENGTH,
	STATE_BLOCK_DIST_LENGTH_EXTRA,
	STATE_BLOCK_LEN_DIST_PAIR
};

static bool
tryReadBits(OFLHAArchive_LHStream *stream, uint16_t *bits, uint8_t count)
{
	uint16_t ret = stream->_savedBits;

	assert(stream->_savedBitsLength < count);

	for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) {
		if OF_UNLIKELY (stream->_bitIndex == 8) {

			if (stream->_bufferIndex < stream->_bufferLength)
				stream->_byte =
				    stream->_buffer[stream->_bufferIndex++];
			else {
				const size_t bufferLength =
				    OF_LHA_ARCHIVE_LHSTREAM_BUFFER_SIZE;
				size_t length = [stream->_stream
				    readIntoBuffer: stream->_buffer







|








>
|







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
	STATE_DIST_TREE_SINGLE,
	STATE_BLOCK_LITLEN,
	STATE_BLOCK_DIST_LENGTH,
	STATE_BLOCK_DIST_LENGTH_EXTRA,
	STATE_BLOCK_LEN_DIST_PAIR
};

static OF_INLINE bool
tryReadBits(OFLHAArchive_LHStream *stream, uint16_t *bits, uint8_t count)
{
	uint16_t ret = stream->_savedBits;

	assert(stream->_savedBitsLength < count);

	for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) {
		if OF_UNLIKELY (stream->_bitIndex == 8) {
			if OF_LIKELY (stream->_bufferIndex <
			    stream->_bufferLength)
				stream->_byte =
				    stream->_buffer[stream->_bufferIndex++];
			else {
				const size_t bufferLength =
				    OF_LHA_ARCHIVE_LHSTREAM_BUFFER_SIZE;
				size_t length = [stream->_stream
				    readIntoBuffer: stream->_buffer

Modified src/huffman_tree.h from [c0d670c09d] to [f55f1d77c2].

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

#include <stdbool.h>
#include <stdint.h>

#import "macros.h"



OF_ASSUME_NONNULL_BEGIN

struct of_huffman_tree {
	struct of_huffman_tree *_Nullable leaves[2];
	uint16_t value;
};

























#ifdef __cplusplus
extern "C" {
#endif
extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct(
    uint8_t lengths[_Nonnull], uint16_t count);
extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct_single(
    uint16_t value);
extern bool of_huffman_tree_walk(id _Nullable stream,
    bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t),
    struct of_huffman_tree *_Nonnull *_Nonnull tree, uint16_t *_Nonnull value);
extern void of_huffman_tree_release(struct of_huffman_tree *_Nonnull tree);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END







>
>






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








<
<
<






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

#include <stdbool.h>
#include <stdint.h>

#import "macros.h"

#import "OFInvalidFormatException.h"

OF_ASSUME_NONNULL_BEGIN

struct of_huffman_tree {
	struct of_huffman_tree *_Nullable leaves[2];
	uint16_t value;
};

static OF_INLINE bool
of_huffman_tree_walk(id _Nullable stream,
    bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t),
    struct of_huffman_tree *_Nonnull *_Nonnull tree, uint16_t *_Nonnull value)
{
	struct of_huffman_tree *iter = *tree;
	uint16_t bits;

	while (iter->value == 0xFFFF) {
		if OF_UNLIKELY (!bitReader(stream, &bits, 1)) {
			*tree = iter;
			return false;
		}

		if OF_UNLIKELY (iter->leaves[bits] == NULL)
			@throw [OFInvalidFormatException exception];

		iter = iter->leaves[bits];
	}

	*value = iter->value;
	return true;
}

#ifdef __cplusplus
extern "C" {
#endif
extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct(
    uint8_t lengths[_Nonnull], uint16_t count);
extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct_single(
    uint16_t value);



extern void of_huffman_tree_release(struct of_huffman_tree *_Nonnull tree);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

Modified src/huffman_tree.m from [562e8d5f98] to [e648d95cb9].

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
	struct of_huffman_tree *tree = newTree();

	tree->value = value;

	return tree;
}

bool
of_huffman_tree_walk(id stream, bool (*bitReader)(id, uint16_t *, uint8_t),
    struct of_huffman_tree **tree, uint16_t *value)
{
	struct of_huffman_tree *iter = *tree;
	uint16_t bits;

	while (iter->value == 0xFFFF) {
		if OF_UNLIKELY (!bitReader(stream, &bits, 1)) {
			*tree = iter;
			return false;
		}

		if OF_UNLIKELY (iter->leaves[bits] == NULL)
			@throw [OFInvalidFormatException exception];

		iter = iter->leaves[bits];
	}

	*value = iter->value;
	return true;
}

void
of_huffman_tree_release(struct of_huffman_tree *tree)
{
	for (uint_fast8_t i = 0; i < 2; i++)
		if OF_LIKELY (tree->leaves[i] != NULL)
			of_huffman_tree_release(tree->leaves[i]);

	free(tree);
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









130
131
132
133
134
135
136























137
138
139
140
141
142
143
144
145
	struct of_huffman_tree *tree = newTree();

	tree->value = value;

	return tree;
}
























void
of_huffman_tree_release(struct of_huffman_tree *tree)
{
	for (uint_fast8_t i = 0; i < 2; i++)
		if OF_LIKELY (tree->leaves[i] != NULL)
			of_huffman_tree_release(tree->leaves[i]);

	free(tree);
}