_site/cover/scran_number.COVER.html

1 %% Copyright (c) 2023 Peter Morgan <peter.james.morgan@gmail.com>
2 %%
3 %% Licensed under the Apache License, Version 2.0 (the "License");
4 %% you may not use this file except in compliance with the License.
5 %% You may obtain a copy of the License at
6 %%
7 %% http://www.apache.org/licenses/LICENSE-2.0
8 %%
9 %% Unless required by applicable law or agreed to in writing, software
10 %% distributed under the License is distributed on an "AS IS" BASIS,
11 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 %% See the License for the specific language governing permissions and
13 %% limitations under the License.
14
15
16 %% @doc Parser combinators that return numbers from big or little
17 %% endian bytes.
18
19 -module(scran_number).
20
21 -feature(maybe_expr, enable).
22
23 -export([f/2]).
24 -export([f104/1]).
25 -export([f112/1]).
26 -export([f120/1]).
27 -export([f128/1]).
28 -export([f16/1]).
29 -export([f24/1]).
30 -export([f32/1]).
31 -export([f40/1]).
32 -export([f48/1]).
33 -export([f56/1]).
34 -export([f64/1]).
35 -export([f72/1]).
36 -export([f8/1]).
37 -export([f80/1]).
38 -export([f88/1]).
39 -export([f96/1]).
40 -export([i/2]).
41 -export([i104/1]).
42 -export([i112/1]).
43 -export([i120/1]).
44 -export([i128/1]).
45 -export([i16/1]).
46 -export([i24/1]).
47 -export([i32/1]).
48 -export([i40/1]).
49 -export([i48/1]).
50 -export([i56/1]).
51 -export([i64/1]).
52 -export([i72/1]).
53 -export([i8/1]).
54 -export([i80/1]).
55 -export([i88/1]).
56 -export([i96/1]).
57 -export([precision/1]).
58 -export([u/2]).
59 -export([u104/1]).
60 -export([u112/1]).
61 -export([u120/1]).
62 -export([u128/1]).
63 -export([u16/1]).
64 -export([u24/1]).
65 -export([u32/1]).
66 -export([u40/1]).
67 -export([u48/1]).
68 -export([u56/1]).
69 -export([u64/1]).
70 -export([u72/1]).
71 -export([u8/1]).
72 -export([u80/1]).
73 -export([u88/1]).
74 -export([u96/1]).
75 -export_type([bit_size/0]).
76 -export_type([endianess/0]).
77 -export_type([fparser/0]).
78 -export_type([iparser/0]).
79 -export_type([uparser/0]).
80
81
82 -type endianess() :: little | big.
83
84 -type bit_size() :: pos_integer().
85
86 -type iparser() :: scran:parser(binary(), integer()).
87 -type fparser() :: scran:parser(binary(), float()).
88
89
90 -spec i8(endianess()) -> iparser().
91 -spec i16(endianess()) -> iparser().
92 -spec i24(endianess()) -> iparser().
93 -spec i32(endianess()) -> iparser().
94 -spec i40(endianess()) -> iparser().
95 -spec i48(endianess()) -> iparser().
96 -spec i56(endianess()) -> iparser().
97 -spec i64(endianess()) -> iparser().
98 -spec i72(endianess()) -> iparser().
99 -spec i80(endianess()) -> iparser().
100 -spec i88(endianess()) -> iparser().
101 -spec i96(endianess()) -> iparser().
102 -spec i104(endianess()) -> iparser().
103 -spec i112(endianess()) -> iparser().
104 -spec i120(endianess()) -> iparser().
105 -spec i128(endianess()) -> iparser().
106
107
108 %% @doc return a signed integer from an 8 bit little or big endian
109 %% quantity.
110 16 i8(Endianess) -> i(Endianess, 8).
111
112
113 %% @doc return a signed integer from a 16 bit little or big endian
114 %% quantity.
115 16 i16(Endianess) -> i(Endianess, 16).
116
117
118 %% @doc return a signed integer from a 24 bit little or big endian
119 %% quantity.
120 16 i24(Endianess) -> i(Endianess, 24).
121
122 %% @doc return a signed integer from a 32 bit little or big endian
123 %% quantity.
124 16 i32(Endianess) -> i(Endianess, 32).
125
126 %% @doc return a signed integer from a 40 bit little or big endian
127 %% quantity.
128 16 i40(Endianess) -> i(Endianess, 40).
129
130 %% @doc return a signed integer from a 48 bit little or big endian
131 %% quantity.
132 16 i48(Endianess) -> i(Endianess, 48).
133
134 %% @doc return a signed integer from a 56 bit little or big endian
135 %% quantity.
136 16 i56(Endianess) -> i(Endianess, 56).
137
138 %% @doc return a signed integer from a 64 bit little or big endian
139 %% quantity.
140 16 i64(Endianess) -> i(Endianess, 64).
141
142 %% @doc return a signed integer from a 72 bit little or big endian
143 %% quantity.
144 16 i72(Endianess) -> i(Endianess, 72).
145
146 %% @doc return a signed integer from an 80 bit little or big endian
147 %% quantity.
148 16 i80(Endianess) -> i(Endianess, 80).
149
150 %% @doc return a signed integer from an 88 bit little or big endian
151 %% quantity.
152 16 i88(Endianess) -> i(Endianess, 88).
153
154 %% @doc return a signed integer from a 96 bit little or big endian
155 %% quantity.
156 16 i96(Endianess) -> i(Endianess, 96).
157
158 %% @doc return a signed integer from a 104 bit little or big endian
159 %% quantity.
160 16 i104(Endianess) -> i(Endianess, 104).
161
162 %% @doc return a signed integer from a 112 bit little or big endian
163 %% quantity.
164 16 i112(Endianess) -> i(Endianess, 112).
165
166 %% @doc return a signed integer from a 120 bit little or big endian
167 %% quantity.
168 16 i120(Endianess) -> i(Endianess, 120).
169
170 %% @doc return a signed integer from a 128 bit little or big endian
171 %% quantity.
172 18 i128(Endianess) -> i(Endianess, 128).
173
174
175 -spec i(endianess(), bit_size()) -> iparser().
176
177 %% @doc return a signed integer from a little or big endian quantity.
178 1026 i(Endianess, Size) -> int(Endianess, signed, Size).
179
180 -type uparser() :: scran:parser(binary(), non_neg_integer()).
181
182 -spec u8(endianess()) -> uparser().
183 -spec u16(endianess()) -> uparser().
184 -spec u24(endianess()) -> uparser().
185 -spec u32(endianess()) -> uparser().
186 -spec u40(endianess()) -> uparser().
187 -spec u48(endianess()) -> uparser().
188 -spec u56(endianess()) -> uparser().
189 -spec u64(endianess()) -> uparser().
190 -spec u72(endianess()) -> uparser().
191 -spec u80(endianess()) -> uparser().
192 -spec u88(endianess()) -> uparser().
193 -spec u96(endianess()) -> uparser().
194 -spec u104(endianess()) -> uparser().
195 -spec u112(endianess()) -> uparser().
196 -spec u120(endianess()) -> uparser().
197 -spec u128(endianess()) -> uparser().
198
199
200 %% @doc return an unsigned integer from an 8 bit little or big endian
201 %% quantity.
202 12 u8(Endianess) -> u(Endianess, 8).
203
204 %% @doc return an unsigned integer from a 16 bit little or big endian
205 %% quantity.
206 12 u16(Endianess) -> u(Endianess, 16).
207
208 %% @doc return an unsigned integer from a 24 bit little or big endian
209 %% quantity.
210 12 u24(Endianess) -> u(Endianess, 24).
211
212 %% @doc return an unsigned integer from a 32 bit little or big endian
213 %% quantity.
214 12 u32(Endianess) -> u(Endianess, 32).
215
216 %% @doc return an unsigned integer from a 40 bit little or big endian
217 %% quantity.
218 12 u40(Endianess) -> u(Endianess, 40).
219
220 %% @doc return an unsigned integer from a 48 bit little or big endian
221 %% quantity.
222 12 u48(Endianess) -> u(Endianess, 48).
223
224 %% @doc return an unsigned integer from a 56 bit little or big endian
225 %% quantity.
226 12 u56(Endianess) -> u(Endianess, 56).
227
228 %% @doc return an unsigned integer from a 64 bit little or big endian
229 %% quantity.
230 12 u64(Endianess) -> u(Endianess, 64).
231
232 %% @doc return an unsigned integer from a 72 bit little or big endian
233 %% quantity.
234 12 u72(Endianess) -> u(Endianess, 72).
235
236 %% @doc return an unsigned integer from an 80 bit little or big endian
237 %% quantity.
238 12 u80(Endianess) -> u(Endianess, 80).
239
240 %% @doc return an unsigned integer from an 88 bit little or big endian
241 %% quantity.
242 12 u88(Endianess) -> u(Endianess, 88).
243
244 %% @doc return an unsigned integer from a 96 bit little or big endian
245 %% quantity.
246 12 u96(Endianess) -> u(Endianess, 96).
247
248 %% @doc return an unsigned integer from a 104 bit little or big endian
249 %% quantity.
250 12 u104(Endianess) -> u(Endianess, 104).
251
252 %% @doc return an unsigned integer from a 112 bit little or big endian
253 %% quantity.
254 12 u112(Endianess) -> u(Endianess, 112).
255
256 %% @doc return an unsigned integer from a 120 bit little or big endian
257 %% quantity.
258 12 u120(Endianess) -> u(Endianess, 120).
259
260 %% @doc return an unsigned integer from a 128 bit little or big endian
261 %% quantity.
262 12 u128(Endianess) -> u(Endianess, 128).
263
264
265 %% @doc return an unsigned integer from a little or big endian
266 %% quantity.
267
268 -spec u(endianess(), bit_size()) -> uparser().
269
270 797 u(Endianess, Size) -> int(Endianess, unsigned, Size).
271
272
273 -spec int(endianess(), signed | unsigned, bit_size()) -> iparser() | uparser().
274
275 int(little, signed, Size) ->
276 514 fun
277 (<<I:Size/little-signed, Remaining/bits>>) ->
278 386 {Remaining, I};
279
280 (L) when is_list(L), length(L) * 8 >= Size ->
281
:-(
{Taken, Remaining} = lists:split(Size div 8, L),
282
:-(
<<I:Size/little-signed>> = list_to_binary(Taken),
283
:-(
{Remaining, I};
284
285 (_) ->
286 128 nomatch
287 end;
288
289 int(little, unsigned, Size) ->
290 385 fun
291 (<<I:Size/little, Remaining/bits>>) ->
292 257 {Remaining, I};
293
294 (L) when is_list(L), length(L) * 8 >= Size ->
295
:-(
{Taken, Remaining} = lists:split(Size div 8, L),
296
:-(
<<I:Size/little>> = list_to_binary(Taken),
297
:-(
{Remaining, I};
298
299 (_) ->
300 128 nomatch
301 end;
302
303 int(big, signed, Size) ->
304 512 fun
305 (<<I:Size/signed, Remaining/bits>>) ->
306 384 {Remaining, I};
307
308 (L) when is_list(L), length(L) * 8 >= Size ->
309
:-(
{Taken, Remaining} = lists:split(Size div 8, L),
310
:-(
<<I:Size/signed>> = list_to_binary(Taken),
311
:-(
{Remaining, I};
312
313 (_) ->
314 128 nomatch
315 end;
316
317 int(big, unsigned, Size) ->
318 412 fun
319 (<<I:Size, Remaining/bits>>) ->
320 274 {Remaining, I};
321
322 (L) when is_list(L), length(L) * 8 >= Size ->
323 4 {Taken, Remaining} = lists:split(Size div 8, L),
324 4 <<I:Size>> = list_to_binary(Taken),
325 4 {Remaining, I};
326
327 (_) ->
328 134 nomatch
329 end.
330
331
332 %% @doc return a signed float from an 8 bit little or big endian
333 %% quantity.
334
:-(
f8(Endianess) -> f(Endianess, 8).
335
336
337 %% @doc return a signed float from a 16 bit little or big endian
338 %% quantity.
339
:-(
f16(Endianess) -> f(Endianess, 16).
340
341
342 %% @doc return a signed float from a 24 bit little or big endian
343 %% quantity.
344
:-(
f24(Endianess) -> f(Endianess, 24).
345
346 %% @doc return a signed float from a 32 bit little or big endian
347 %% quantity.
348
:-(
f32(Endianess) -> f(Endianess, 32).
349
350 %% @doc return a signed float from a 40 bit little or big endian
351 %% quantity.
352
:-(
f40(Endianess) -> f(Endianess, 40).
353
354 %% @doc return a signed float from a 48 bit little or big endian
355 %% quantity.
356
:-(
f48(Endianess) -> f(Endianess, 48).
357
358 %% @doc return a signed float from a 56 bit little or big endian
359 %% quantity.
360
:-(
f56(Endianess) -> f(Endianess, 56).
361
362 %% @doc return a signed float from a 64 bit little or big endian
363 %% quantity.
364
:-(
f64(Endianess) -> f(Endianess, 64).
365
366 %% @doc return a signed float from a 72 bit little or big endian
367 %% quantity.
368
:-(
f72(Endianess) -> f(Endianess, 72).
369
370 %% @doc return a signed float from an 80 bit little or big endian
371 %% quantity.
372
:-(
f80(Endianess) -> f(Endianess, 80).
373
374 %% @doc return a signed float from an 88 bit little or big endian
375 %% quantity.
376
:-(
f88(Endianess) -> f(Endianess, 88).
377
378 %% @doc return a signed float from a 96 bit little or big endian
379 %% quantity.
380
:-(
f96(Endianess) -> f(Endianess, 96).
381
382 %% @doc return a signed float from a 104 bit little or big endian
383 %% quantity.
384
:-(
f104(Endianess) -> f(Endianess, 104).
385
386 %% @doc return a signed float from a 112 bit little or big endian
387 %% quantity.
388
:-(
f112(Endianess) -> f(Endianess, 112).
389
390 %% @doc return a signed float from a 120 bit little or big endian
391 %% quantity.
392
:-(
f120(Endianess) -> f(Endianess, 120).
393
394 %% @doc return a signed float from a 128 bit little or big endian
395 %% quantity.
396
:-(
f128(Endianess) -> f(Endianess, 128).
397
398
399 -spec f(endianess(), bit_size()) -> fparser().
400
401 f(little, Size) ->
402
:-(
fun
403 (<<I:Size/float-little, Remaining/bits>>) ->
404
:-(
{Remaining, I};
405
406 (L) when is_list(L), length(L) * 8 >= Size ->
407
:-(
{Taken, Remaining} = lists:split(Size div 8, L),
408
:-(
<<I:Size/float-little>> = list_to_binary(Taken),
409
:-(
{Remaining, I};
410
411 (_) ->
412
:-(
nomatch
413 end;
414
415 f(big, Size) ->
416
:-(
fun
417 (<<I:Size/float, Remaining/bits>>) ->
418
:-(
{Remaining, I};
419
420 (L) when is_list(L), length(L) * 8 >= Size ->
421
:-(
{Taken, Remaining} = lists:split(Size div 8, L),
422
:-(
<<I:Size/float>> = list_to_binary(Taken),
423
:-(
{Remaining, I};
424
425 (_) ->
426
:-(
nomatch
427 end.
428
429
430 -spec precision(pos_integer()) -> fparser().
431
432 %% @doc Truncate a floating point value to a number of decimal digits.
433 precision(Digits) ->
434
:-(
fun
435 (Value) ->
436
:-(
Decimals = float_to_binary(
437 Value,
438 [{decimals,
439 Digits - trunc(
440 math:ceil(
441 math:log10(
442 trunc(abs(Value)) + 1)))}]),
443
444
:-(
case binary:split(Decimals, <<".">>) of
445 [_, _] ->
446
:-(
binary_to_float(Decimals);
447
448 [_] ->
449
:-(
binary_to_float(<<Decimals/bytes, ".0">>)
450 end
451 end.
Line Hits Source