-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathinline.h
141 lines (124 loc) · 5 KB
/
inline.h
1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
static inline noreturn throw (struct context * context, unsigned error) {
context -> status = error;
longjmp(context -> target, 1);
}
static inline struct allocator_node * get_allocator_node (void * buffer) {
return (struct allocator_node *) ((char *) buffer - offsetof(struct allocator_node, data));
}
static inline void * ctxmalloc (struct context * context, size_t size) {
void * result = allocate(&(context -> allocator), size);
if (!result) throw(context, PLUM_ERR_OUT_OF_MEMORY);
return result;
}
static inline void * ctxcalloc (struct context * context, size_t size) {
void * result = clear_allocate(&(context -> allocator), size);
if (!result) throw(context, PLUM_ERR_OUT_OF_MEMORY);
return result;
}
static inline void * ctxrealloc (struct context * context, void * buffer, size_t size) {
void * result = reallocate(&(context -> allocator), buffer, size);
if (!result) throw(context, PLUM_ERR_OUT_OF_MEMORY);
return result;
}
static inline void ctxfree (struct context * context, void * buffer) {
deallocate(&(context -> allocator), buffer);
}
static inline uintmax_t bitnegate (uintmax_t value) {
// ensure that the value is negated correctly, without accidental unsigned-to-signed conversions getting in the way
return ~value;
}
static inline uint16_t bitextend16 (uint16_t value, unsigned width) {
uint_fast32_t result = value;
while (width < 16) {
result |= result << width;
width <<= 1;
}
return result >> (width - 16);
}
static inline void * append_output_node (struct context * context, size_t size) {
struct data_node * node = ctxmalloc(context, sizeof *node + size);
*node = (struct data_node) {.size = size, .previous = context -> output, .next = NULL};
if (context -> output) context -> output -> next = node;
context -> output = node;
return node -> data;
}
static inline void * resize_output_node (struct context * context, void * data, size_t size) {
struct data_node * node = (struct data_node *) ((char *) data - offsetof(struct data_node, data));
if (node -> size != size) {
node = ctxrealloc(context, node, sizeof *node + size);
node -> size = size;
if (node -> previous) node -> previous -> next = node;
}
return node -> data;
}
static inline bool bit_depth_less_than (uint32_t depth, uint32_t target) {
// formally "less than or equal to", but that would be a very long name
return !((target - depth) & 0x80808080u);
}
static inline int absolute_value (int value) {
return (value < 0) ? -value : value;
}
static inline uint32_t shift_in_left (struct context * context, unsigned count, uint32_t * restrict dataword, uint8_t * restrict bits,
const unsigned char ** data, size_t * restrict size) {
while (*bits < count) {
if (!*size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
*dataword |= (uint32_t) **data << *bits;
++ *data;
-- *size;
*bits += 8;
}
uint32_t result;
if (count < 32) {
result = *dataword & (((uint32_t) 1 << count) - 1);
*dataword >>= count;
} else {
result = *dataword;
*dataword = 0;
}
*bits -= count;
return result;
}
static inline uint32_t shift_in_right_JPEG (struct context * context, unsigned count, uint32_t * restrict dataword, uint8_t * restrict bits,
const unsigned char ** data, size_t * restrict size) {
// unlike shift_in_left above, this function has to account for stuffed bytes (any number of 0xFF followed by a single 0x00)
while (*bits < count) {
if (!*size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
*dataword = (*dataword << 8) | **data;
*bits += 8;
while (**data == 0xff) {
++ *data;
-- *size;
if (!*size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
}
++ *data;
-- *size;
}
*bits -= count;
uint32_t result = *dataword >> *bits;
*dataword &= ((uint32_t) 1 << *bits) - 1;
return result;
}
static inline uint64_t color_from_floats (double red, double green, double blue, double alpha) {
uint64_t outred = (red >= 0) ? red + 0.5 : 0;
if (outred >= 0x10000u) outred = 0xffffu;
uint64_t outgreen = (green >= 0) ? green + 0.5 : 0;
if (outgreen >= 0x10000u) outgreen = 0xffffu;
uint64_t outblue = (blue >= 0) ? blue + 0.5 : 0;
if (outblue >= 0x10000u) outblue = 0xffffu;
uint64_t outalpha = (alpha >= 0) ? alpha + 0.5 : 0;
if (outalpha >= 0x10000u) outalpha = 0xffffu;
return (outalpha << 48) | (outblue << 32) | (outgreen << 16) | outred;
}
static inline int16_t make_signed_16 (uint16_t value) {
// this is a no-op (since int16_t must use two's complement), but it's necessary to avoid undefined behavior
return (value >= 0x8000u) ? -(int16_t) bitnegate(value) - 1 : value;
}
static inline unsigned bit_width (uintmax_t value) {
unsigned result;
for (result = 0; value; result ++) value >>= 1;
return result;
}
static inline bool is_whitespace (unsigned char value) {
// checks if value is 0 or isspace(value), but independent of current locale and system encoding
return !value || (value >= 9 && value <= 13) || value == 32;
}