]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | /* |
2 | * Utilities | |
3 | */ | |
4 | ||
5 | #ifndef DUK_UTIL_H_INCLUDED | |
6 | #define DUK_UTIL_H_INCLUDED | |
7 | ||
8 | #define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */ | |
9 | ||
10 | #define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f]) | |
11 | ||
12 | /* | |
13 | * Endian conversion | |
14 | */ | |
15 | ||
16 | #if defined(DUK_USE_INTEGER_LE) | |
17 | #define DUK_HTON32(x) DUK_BSWAP32((x)) | |
18 | #define DUK_NTOH32(x) DUK_BSWAP32((x)) | |
19 | #define DUK_HTON16(x) DUK_BSWAP16((x)) | |
20 | #define DUK_NTOH16(x) DUK_BSWAP16((x)) | |
21 | #elif defined(DUK_USE_INTEGER_BE) | |
22 | #define DUK_HTON32(x) (x) | |
23 | #define DUK_NTOH32(x) (x) | |
24 | #define DUK_HTON16(x) (x) | |
25 | #define DUK_NTOH16(x) (x) | |
26 | #else | |
27 | #error internal error, endianness defines broken | |
28 | #endif | |
29 | ||
30 | /* | |
31 | * Bitstream decoder | |
32 | */ | |
33 | ||
34 | struct duk_bitdecoder_ctx { | |
35 | const duk_uint8_t *data; | |
36 | duk_size_t offset; | |
37 | duk_size_t length; | |
38 | duk_uint32_t currval; | |
39 | duk_small_int_t currbits; | |
40 | }; | |
41 | ||
42 | /* | |
43 | * Bitstream encoder | |
44 | */ | |
45 | ||
46 | struct duk_bitencoder_ctx { | |
47 | duk_uint8_t *data; | |
48 | duk_size_t offset; | |
49 | duk_size_t length; | |
50 | duk_uint32_t currval; | |
51 | duk_small_int_t currbits; | |
52 | duk_small_int_t truncated; | |
53 | }; | |
54 | ||
55 | /* | |
56 | * Raw write/read macros for big endian, unaligned basic values. | |
57 | * Caller ensures there's enough space. The macros update the pointer | |
58 | * argument automatically on resizes. The idiom seems a bit odd, but | |
59 | * leads to compact code. | |
60 | */ | |
61 | ||
62 | #define DUK_RAW_WRITE_U8(ptr,val) do { \ | |
63 | *(ptr)++ = (duk_uint8_t) (val); \ | |
64 | } while (0) | |
65 | #define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val)) | |
66 | #define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val)) | |
67 | #define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val)) | |
68 | #define DUK_RAW_WRITE_XUTF8(ptr,val) do { \ | |
69 | /* 'ptr' is evaluated both as LHS and RHS. */ \ | |
70 | duk_uint8_t *duk__ptr; \ | |
71 | duk_small_int_t duk__len; \ | |
72 | duk__ptr = (duk_uint8_t *) (ptr); \ | |
73 | duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \ | |
74 | duk__ptr += duk__len; \ | |
75 | (ptr) = duk__ptr; \ | |
76 | } while (0) | |
77 | #define DUK_RAW_WRITE_CESU8(ptr,val) do { \ | |
78 | /* 'ptr' is evaluated both as LHS and RHS. */ \ | |
79 | duk_uint8_t *duk__ptr; \ | |
80 | duk_small_int_t duk__len; \ | |
81 | duk__ptr = (duk_uint8_t *) (ptr); \ | |
82 | duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \ | |
83 | duk__ptr += duk__len; \ | |
84 | (ptr) = duk__ptr; \ | |
85 | } while (0) | |
86 | ||
87 | #define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++)) | |
88 | #define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr)); | |
89 | #define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr)); | |
90 | #define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr)); | |
91 | ||
92 | /* | |
93 | * Buffer writer (dynamic buffer only) | |
94 | * | |
95 | * Helper for writing to a dynamic buffer with a concept of a "spare" area | |
96 | * to reduce resizes. You can ensure there is enough space beforehand and | |
97 | * then write for a while without further checks, relying on a stable data | |
98 | * pointer. Spare handling is automatic so call sites only indicate how | |
99 | * much data they need right now. | |
100 | * | |
101 | * There are several ways to write using bufwriter. The best approach | |
102 | * depends mainly on how much performance matters over code footprint. | |
103 | * The key issues are (1) ensuring there is space and (2) keeping the | |
104 | * pointers consistent. Fast code should ensure space for multiple writes | |
105 | * with one ensure call. Fastest inner loop code can temporarily borrow | |
106 | * the 'p' pointer but must write it back eventually. | |
107 | * | |
108 | * Be careful to ensure all macro arguments (other than static pointers like | |
109 | * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if | |
110 | * necessary (if that's not possible, there should be a note near the macro). | |
111 | * Buffer write arguments often contain arithmetic etc so this is | |
112 | * particularly important here. | |
113 | */ | |
114 | ||
115 | /* XXX: Migrate bufwriter and other read/write helpers to its own header? */ | |
116 | ||
117 | struct duk_bufwriter_ctx { | |
118 | duk_uint8_t *p; | |
119 | duk_uint8_t *p_base; | |
120 | duk_uint8_t *p_limit; | |
121 | duk_hbuffer_dynamic *buf; | |
122 | }; | |
123 | ||
124 | #define DUK_BW_SPARE_ADD 64 | |
125 | #define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */ | |
126 | ||
127 | /* Initialization and finalization (compaction), converting to other types. */ | |
128 | ||
129 | #define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \ | |
130 | duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \ | |
131 | } while (0) | |
132 | #define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \ | |
133 | duk_bw_init((thr), (bw_ctx), (buf)); \ | |
134 | } while (0) | |
135 | #define DUK_BW_COMPACT(thr,bw_ctx) do { \ | |
136 | /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \ | |
137 | duk_bw_compact((thr), (bw_ctx)); \ | |
138 | } while (0) | |
139 | #define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \ | |
140 | duk_push_lstring((duk_context *) (thr), \ | |
141 | (const char *) (bw_ctx)->p_base, \ | |
142 | (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ | |
143 | } while (0) | |
144 | /* Pointers may be NULL for a while when 'buf' size is zero and before any | |
145 | * ENSURE calls have been made. Once an ENSURE has been made, the pointers | |
146 | * are required to be non-NULL so that it's always valid to use memcpy() and | |
147 | * memmove(), even for zero size. | |
148 | */ | |
149 | #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \ | |
150 | DUK_ASSERT_EXPR((bw_ctx) != NULL && \ | |
151 | (bw_ctx)->buf != NULL && \ | |
152 | ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \ | |
153 | ((bw_ctx)->p != NULL && \ | |
154 | (bw_ctx)->p_base != NULL && \ | |
155 | (bw_ctx)->p_limit != NULL && \ | |
156 | (bw_ctx)->p_limit >= (bw_ctx)->p_base && \ | |
157 | (bw_ctx)->p >= (bw_ctx)->p_base && \ | |
158 | (bw_ctx)->p <= (bw_ctx)->p_limit))) | |
159 | #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \ | |
160 | DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \ | |
161 | } while (0) | |
162 | ||
163 | /* Working with the pointer and current size. */ | |
164 | ||
165 | #define DUK_BW_GET_PTR(thr,bw_ctx) \ | |
166 | ((bw_ctx)->p) | |
167 | #define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \ | |
168 | (bw_ctx)->p = (ptr); \ | |
169 | } while (0) | |
170 | #define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \ | |
171 | (bw_ctx)->p += (delta); \ | |
172 | } while (0) | |
173 | #define DUK_BW_GET_BASEPTR(thr,bw_ctx) \ | |
174 | ((bw_ctx)->p_base) | |
175 | #define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \ | |
176 | ((bw_ctx)->p_limit) | |
177 | #define DUK_BW_GET_SIZE(thr,bw_ctx) \ | |
178 | ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)) | |
179 | #define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \ | |
180 | DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ | |
181 | (bw_ctx)->p = (bw_ctx)->p_base + (sz); \ | |
182 | } while (0) | |
183 | #define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \ | |
184 | /* Reset to zero size, keep current limit. */ \ | |
185 | (bw_ctx)->p = (bw_ctx)->p_base; \ | |
186 | } while (0) | |
187 | #define DUK_BW_GET_BUFFER(thr,bw_ctx) \ | |
188 | ((bw_ctx)->buf) | |
189 | ||
190 | /* Ensuring (reserving) space. */ | |
191 | ||
192 | #define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \ | |
193 | duk_size_t duk__sz, duk__space; \ | |
194 | DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \ | |
195 | duk__sz = (sz); \ | |
196 | duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \ | |
197 | if (duk__space < duk__sz) { \ | |
198 | (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \ | |
199 | } \ | |
200 | } while (0) | |
201 | /* NOTE: Multiple evaluation of 'ptr' in this macro. */ | |
202 | /* XXX: Rework to use an always-inline function? */ | |
203 | #define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \ | |
204 | (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \ | |
205 | (ptr) : \ | |
206 | ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz)))) | |
207 | #define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \ | |
208 | DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p) | |
209 | #define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \ | |
210 | (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \ | |
211 | DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz))) | |
212 | #define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \ | |
213 | DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \ | |
214 | } while (0) | |
215 | ||
216 | /* Miscellaneous. */ | |
217 | ||
218 | #define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \ | |
219 | (bw_ctx)->p = (ptr); \ | |
220 | duk_bw_compact((thr), (bw_ctx)); \ | |
221 | } while (0) | |
222 | ||
223 | /* Fast write calls which assume you control the spare beforehand. | |
224 | * Multibyte write variants exist and use a temporary write pointer | |
225 | * because byte writes alias with anything: with a stored pointer | |
226 | * explicit pointer load/stores get generated (e.g. gcc -Os). | |
227 | */ | |
228 | ||
229 | #define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \ | |
230 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \ | |
231 | *(bw_ctx)->p++ = (duk_uint8_t) (val); \ | |
232 | } while (0) | |
233 | #define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \ | |
234 | duk_uint8_t *duk__p; \ | |
235 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \ | |
236 | duk__p = (bw_ctx)->p; \ | |
237 | *duk__p++ = (duk_uint8_t) (val1); \ | |
238 | *duk__p++ = (duk_uint8_t) (val2); \ | |
239 | (bw_ctx)->p = duk__p; \ | |
240 | } while (0) | |
241 | #define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \ | |
242 | duk_uint8_t *duk__p; \ | |
243 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \ | |
244 | duk__p = (bw_ctx)->p; \ | |
245 | *duk__p++ = (duk_uint8_t) (val1); \ | |
246 | *duk__p++ = (duk_uint8_t) (val2); \ | |
247 | *duk__p++ = (duk_uint8_t) (val3); \ | |
248 | (bw_ctx)->p = duk__p; \ | |
249 | } while (0) | |
250 | #define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ | |
251 | duk_uint8_t *duk__p; \ | |
252 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \ | |
253 | duk__p = (bw_ctx)->p; \ | |
254 | *duk__p++ = (duk_uint8_t) (val1); \ | |
255 | *duk__p++ = (duk_uint8_t) (val2); \ | |
256 | *duk__p++ = (duk_uint8_t) (val3); \ | |
257 | *duk__p++ = (duk_uint8_t) (val4); \ | |
258 | (bw_ctx)->p = duk__p; \ | |
259 | } while (0) | |
260 | #define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ | |
261 | duk_uint8_t *duk__p; \ | |
262 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \ | |
263 | duk__p = (bw_ctx)->p; \ | |
264 | *duk__p++ = (duk_uint8_t) (val1); \ | |
265 | *duk__p++ = (duk_uint8_t) (val2); \ | |
266 | *duk__p++ = (duk_uint8_t) (val3); \ | |
267 | *duk__p++ = (duk_uint8_t) (val4); \ | |
268 | *duk__p++ = (duk_uint8_t) (val5); \ | |
269 | (bw_ctx)->p = duk__p; \ | |
270 | } while (0) | |
271 | #define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ | |
272 | duk_uint8_t *duk__p; \ | |
273 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \ | |
274 | duk__p = (bw_ctx)->p; \ | |
275 | *duk__p++ = (duk_uint8_t) (val1); \ | |
276 | *duk__p++ = (duk_uint8_t) (val2); \ | |
277 | *duk__p++ = (duk_uint8_t) (val3); \ | |
278 | *duk__p++ = (duk_uint8_t) (val4); \ | |
279 | *duk__p++ = (duk_uint8_t) (val5); \ | |
280 | *duk__p++ = (duk_uint8_t) (val6); \ | |
281 | (bw_ctx)->p = duk__p; \ | |
282 | } while (0) | |
283 | #define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \ | |
284 | duk_ucodepoint_t duk__cp; \ | |
285 | duk_small_int_t duk__enc_len; \ | |
286 | duk__cp = (cp); \ | |
287 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \ | |
288 | duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \ | |
289 | (bw_ctx)->p += duk__enc_len; \ | |
290 | } while (0) | |
291 | #define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \ | |
292 | duk_ucodepoint_t duk__cp; \ | |
293 | duk_small_int_t duk__enc_len; \ | |
294 | duk__cp = (duk_ucodepoint_t) (cp); \ | |
295 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \ | |
296 | duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \ | |
297 | (bw_ctx)->p += duk__enc_len; \ | |
298 | } while (0) | |
299 | /* XXX: add temporary duk__p pointer here too; sharing */ | |
300 | #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ | |
301 | const void *duk__valptr; \ | |
302 | duk_size_t duk__valsz; \ | |
303 | duk__valptr = (const void *) (valptr); \ | |
304 | duk__valsz = (duk_size_t) (valsz); \ | |
305 | DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ | |
306 | (bw_ctx)->p += duk__valsz; \ | |
307 | } while (0) | |
308 | #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ | |
309 | const duk_uint8_t *duk__val; \ | |
310 | duk_size_t duk__val_len; \ | |
311 | duk__val = (const duk_uint8_t *) (val); \ | |
312 | duk__val_len = DUK_STRLEN((const char *) duk__val); \ | |
313 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ | |
314 | (bw_ctx)->p += duk__val_len; \ | |
315 | } while (0) | |
316 | #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ | |
317 | duk_size_t duk__val_len; \ | |
318 | duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ | |
319 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ | |
320 | (bw_ctx)->p += duk__val_len; \ | |
321 | } while (0) | |
322 | #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ | |
323 | duk_size_t duk__val_len; \ | |
324 | duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ | |
325 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
326 | (bw_ctx)->p += duk__val_len; \ | |
327 | } while (0) | |
328 | #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ | |
329 | duk_size_t duk__val_len; \ | |
330 | duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ | |
331 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
332 | (bw_ctx)->p += duk__val_len; \ | |
333 | } while (0) | |
334 | #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ | |
335 | duk_size_t duk__val_len; \ | |
336 | duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ | |
337 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
338 | (bw_ctx)->p += duk__val_len; \ | |
339 | } while (0) | |
340 | ||
341 | /* Append bytes from a slice already in the buffer. */ | |
342 | #define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \ | |
343 | duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len)) | |
344 | ||
345 | /* Insert bytes in the middle of the buffer from an external buffer. */ | |
346 | #define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \ | |
347 | duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len)) | |
348 | ||
349 | /* Insert bytes in the middle of the buffer from a slice already | |
350 | * in the buffer. Source offset is interpreted "before" the operation. | |
351 | */ | |
352 | #define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \ | |
353 | duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len)) | |
354 | ||
355 | /* Insert a reserved area somewhere in the buffer; caller fills it. | |
356 | * Evaluates to a (duk_uint_t *) pointing to the start of the reserved | |
357 | * area for convenience. | |
358 | */ | |
359 | #define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \ | |
360 | duk_bw_insert_raw_area((thr), (bw), (off), (len)) | |
361 | ||
362 | /* Remove a slice from inside buffer. */ | |
363 | #define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \ | |
364 | duk_bw_remove_raw_slice((thr), (bw), (off), (len)) | |
365 | ||
366 | /* Safe write calls which will ensure space first. */ | |
367 | ||
368 | #define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \ | |
369 | DUK_BW_ENSURE((thr), (bw_ctx), 1); \ | |
370 | DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \ | |
371 | } while (0) | |
372 | #define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \ | |
373 | DUK_BW_ENSURE((thr), (bw_ctx), 2); \ | |
374 | DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \ | |
375 | } while (0) | |
376 | #define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \ | |
377 | DUK_BW_ENSURE((thr), (bw_ctx), 3); \ | |
378 | DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \ | |
379 | } while (0) | |
380 | #define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ | |
381 | DUK_BW_ENSURE((thr), (bw_ctx), 4); \ | |
382 | DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \ | |
383 | } while (0) | |
384 | #define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ | |
385 | DUK_BW_ENSURE((thr), (bw_ctx), 5); \ | |
386 | DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \ | |
387 | } while (0) | |
388 | #define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ | |
389 | DUK_BW_ENSURE((thr), (bw_ctx), 6); \ | |
390 | DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \ | |
391 | } while (0) | |
392 | #define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \ | |
393 | DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \ | |
394 | DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \ | |
395 | } while (0) | |
396 | #define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \ | |
397 | DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \ | |
398 | DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ | |
399 | } while (0) | |
400 | /* XXX: add temporary duk__p pointer here too; sharing */ | |
401 | #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ | |
402 | const void *duk__valptr; \ | |
403 | duk_size_t duk__valsz; \ | |
404 | duk__valptr = (const void *) (valptr); \ | |
405 | duk__valsz = (duk_size_t) (valsz); \ | |
406 | DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ | |
407 | DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ | |
408 | (bw_ctx)->p += duk__valsz; \ | |
409 | } while (0) | |
410 | #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ | |
411 | const duk_uint8_t *duk__val; \ | |
412 | duk_size_t duk__val_len; \ | |
413 | duk__val = (const duk_uint8_t *) (val); \ | |
414 | duk__val_len = DUK_STRLEN((const char *) duk__val); \ | |
415 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ | |
416 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ | |
417 | (bw_ctx)->p += duk__val_len; \ | |
418 | } while (0) | |
419 | #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ | |
420 | duk_size_t duk__val_len; \ | |
421 | duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ | |
422 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ | |
423 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ | |
424 | (bw_ctx)->p += duk__val_len; \ | |
425 | } while (0) | |
426 | #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ | |
427 | duk_size_t duk__val_len; \ | |
428 | duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ | |
429 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ | |
430 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
431 | (bw_ctx)->p += duk__val_len; \ | |
432 | } while (0) | |
433 | #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ | |
434 | duk_size_t duk__val_len; \ | |
435 | duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ | |
436 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ | |
437 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
438 | (bw_ctx)->p += duk__val_len; \ | |
439 | } while (0) | |
440 | #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ | |
441 | duk_size_t duk__val_len; \ | |
442 | duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ | |
443 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ | |
444 | DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ | |
445 | (bw_ctx)->p += duk__val_len; \ | |
446 | } while (0) | |
447 | ||
448 | #define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \ | |
449 | duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len)) | |
450 | #define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \ | |
451 | duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len)) | |
452 | #define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \ | |
453 | duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len)) | |
454 | #define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \ | |
455 | /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \ | |
456 | duk_bw_insert_ensure_area((thr), (bw), (off), (len)) | |
457 | #define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \ | |
458 | /* No difference between raw/ensure because the buffer shrinks. */ \ | |
459 | DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len)) | |
460 | ||
461 | /* | |
462 | * Externs and prototypes | |
463 | */ | |
464 | ||
465 | #if !defined(DUK_SINGLE_FILE) | |
466 | DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; | |
467 | DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; | |
468 | DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; | |
469 | #if defined(DUK_USE_HEX_FASTPATH) | |
470 | DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; | |
471 | DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; | |
472 | #endif | |
473 | #if defined(DUK_USE_BASE64_FASTPATH) | |
474 | DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64]; | |
475 | DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256]; | |
476 | #endif | |
477 | #endif /* !DUK_SINGLE_FILE */ | |
478 | ||
479 | /* Note: assumes that duk_util_probe_steps size is 32 */ | |
480 | #if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) | |
481 | #if !defined(DUK_SINGLE_FILE) | |
482 | DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; | |
483 | #endif /* !DUK_SINGLE_FILE */ | |
484 | #endif | |
485 | ||
486 | #if defined(DUK_USE_STRHASH_DENSE) | |
487 | DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); | |
488 | #endif | |
489 | ||
490 | #if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) | |
491 | DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); | |
492 | #endif | |
493 | ||
494 | DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); | |
495 | DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); | |
496 | DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); | |
497 | ||
498 | DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); | |
499 | DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); | |
500 | ||
501 | DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n); | |
502 | DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); | |
503 | ||
504 | DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); | |
505 | DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); | |
506 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz); | |
507 | DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); | |
508 | DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); | |
509 | DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); | |
510 | DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); | |
511 | DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); | |
512 | DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); | |
513 | DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); | |
514 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); | |
515 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); | |
516 | DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); | |
517 | /* No duk_bw_remove_ensure_slice(), functionality would be identical. */ | |
518 | ||
519 | DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p); | |
520 | DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p); | |
521 | DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p); | |
522 | DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val); | |
523 | DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val); | |
524 | DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val); | |
525 | ||
526 | #if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ | |
527 | DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); | |
528 | #endif | |
529 | ||
530 | #endif /* DUK_UTIL_H_INCLUDED */ |