utils/bits.h: Add macros for swapping endianness in place.
[mLib] / utils / bits.3
CommitLineData
b6b9d458 1.\" -*-nroff-*-
fbf20b5b 2.TH bits 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library"
a9779382
MW
3.ie t \{\
4. ds ss \s8\u
5. ds se \d\s0
6.\}
7.el \{\
8. ds ss ^
9. ds se
10.\}
b6b9d458 11.SH NAME
12bits \- portable bit manipulation macros
a9779382
MW
13.\" octet
14.\" uint16
15.\" uint24
16.\" uint32
17.\" uint64
18.\" kludge64
19.\"
20.\" MASK_8
21.\" MASK_16
22.\" MASK_16_L
23.\" MASK_16_B
24.\" MASK_24
25.\" MASK_24_L
26.\" MASK_24_B
27.\" MASK_32
28.\" MASK_32_L
29.\" MASK_32_B
30.\" MASK_64
31.\" MASK_64_L
32.\" MASK_64_B
33.\"
34.\" SZ_8
35.\" SZ_16
36.\" SZ_16_L
37.\" SZ_16_B
38.\" SZ_24
39.\" SZ_24_L
40.\" SZ_24_B
41.\" SZ_32
42.\" SZ_32_L
43.\" SZ_32_B
44.\" SZ_64
45.\" SZ_64_L
46.\" SZ_64_B
47.\"
48.\" TY_8
49.\" TY_16
50.\" TY_16_L
51.\" TY_16_B
52.\" TY_24
53.\" TY_24_L
54.\" TY_24_B
55.\" TY_32
56.\" TY_32_L
57.\" TY_32_B
58.\" TY_64
59.\" TY_64_L
60.\" TY_64_B
61.\"
62.\" DOUINTSZ
63.\" DOUINTCONV
64.\"
08da152e 65.\" @U8
66.\" @U16
a9779382 67.\" @U24
08da152e 68.\" @U32
a9779382
MW
69.\" @U64
70.\" @U64_
08da152e 71.\"
72.\" @LSL8
73.\" @LSR8
74.\" @LSL16
75.\" @LSR16
a9779382
MW
76.\" @LSL24
77.\" @LSR24
08da152e 78.\" @LSL32
79.\" @LSR32
a9779382
MW
80.\" @LSL64
81.\" @LSR64
82.\" @LSL64_
83.\" @LSR64_
08da152e 84.\"
85.\" @ROL8
86.\" @ROR8
87.\" @ROL16
88.\" @ROR16
a9779382
MW
89.\" @ROL24
90.\" @ROR24
91.\" @ROL32
08da152e 92.\" @ROL32
a9779382
MW
93.\" @ROL64
94.\" @ROR64
95.\" @ROL64_
96.\" @ROR64_
08da152e 97.\"
374bb459
MW
98.\" ENDSWAP16
99.\" ENDSWAP32
100.\" ENDSWAP64
101.\"
102.\" BTOH16
103.\" LTOH16
104.\" HTOB16
105.\" HTOL16
106.\" BTOH32
107.\" LTOH32
108.\" HTOB32
109.\" HTOL32
110.\" BTOH64
111.\" LTOH64
112.\" HTOB64
113.\" HTOL64
114.\"
08da152e 115.\" @GETBYTE
116.\" @PUTBYTE
117.\"
118.\" @LOAD8
119.\" @STORE8
120.\"
121.\" @LOAD16_L
122.\" @LOAD16_B
123.\" @LOAD16
124.\" @STORE16_L
125.\" @STORE16_B
126.\" @STORE16
127.\"
a9779382
MW
128.\" @LOAD24_L
129.\" @LOAD24_B
130.\" @LOAD24
131.\" @STORE24_L
132.\" @STORE24_B
133.\" @STORE24
134.\"
08da152e 135.\" @LOAD32_L
136.\" @LOAD32_B
137.\" @LOAD32
138.\" @STORE32_L
139.\" @STORE32_B
140.\" @STORE32
141.\"
a9779382
MW
142.\" @LOAD64_L
143.\" @LOAD64_B
144.\" @LOAD64
145.\" @STORE64_L
146.\" @STORE64_B
147.\" @STORE64
148.\"
149.\" @LOAD64_L_
150.\" @LOAD64_B_
151.\" @LOAD64_
152.\" @STORE64_L_
153.\" @STORE64_B_
154.\" @STORE64_
155.\"
156.\" @SET64
157.\" @X64
158.\" @ASSIGN64
159.\" @HI64
160.\" @LO64
161.\" @GET64
162.\" @AND64
163.\" @OR64
164.\" @XOR64
165.\" @CPL64
166.\" @ADD64
167.\" @SUB64
168.\" @CMP64
169.\" @ZERO64
b6b9d458 170.SH SYNOPSIS
171.nf
172.B "#include <mLib/bits.h>"
173
a9779382
MW
174.BR "typedef " ... " octet;"
175.BR "typedef " ... " uint16;"
176.BR "typedef " ... " uint24;"
177.BR "typedef " ... " uint32;"
178.BR "typedef " ... " uint64;"
179.BR "typedef " ... " kludge64;"
180
181.BI "#define TY_" we " " type
182.BI "#define SZ_" we " \fR..."
183.BI "#define MASK_" we " \fR..."
b6b9d458 184
a9779382
MW
185.BI "#define DOUINTSZ(" f ") \fR..."
186.BI "#define DOUINTCONV(" f ") \fR..."
b6b9d458 187
a9779382 188.IB type " U" w ( v );
b6b9d458 189
a9779382
MW
190.IB type " LSL" w ( type " " v ", int " s );
191.IB type " LSR" w ( type " " v ", int " s );
192.IB type " ROL" w ( type " " v ", int " s );
193.IB type " ROR" w ( type " " v ", int " s );
b6b9d458 194
a9779382
MW
195.BI "octet GETBYTE(void *" p ", size_t " o );
196.BI "void PUTBYTE(void *" p ", size_t " o ", octet " v );
b6b9d458 197
a9779382
MW
198.IB type " LOAD" we "(void *" p );
199.BI "void STORE" we "(void *" p ", " type " " v );
b6b9d458 200
a9779382
MW
201.BI "void SET64(kludge64 &" d ", uint32 " h ", uint32 " l );
202.BI "kludge64 X64(" hexh ", " hexl );
203.BI "void ASSIGN64(kludge64 &" d ", " x );
204.BI "uint32 HI64(kludge64" x );
205.BI "uint32 LO64(kludge64" x );
206.IB ty " GET64(" ty ", kludge64 " x );
207.BI "void AND64(kludge64 &" d ", kludge64 " x ", kludge64 " y );
208.BI "void OR64(kludge64 &" d ", kludge64 " x ", kludge64 " y );
209.BI "void XOR64(kludge64 &" d ", kludge64 " x ", kludge64 " y );
210.BI "void CPL64(kludge64 &" d ", kludge64 " x );
211.BI "void ADD64(kludge64 &" d ", kludge64 " x ", kludge64 " y );
212.BI "void SUB64(kludge64 &" d ", kludge64 " x ", kludge64 " y );
213.BI "int CMP64(kludge64 " x ", " op ", kludge64 " y );
214.BI "int ZERO64(kludge64 " x );
b6b9d458 215.fi
216.SH DESCRIPTION
217The header file
218.B <mLib/bits.h>
219contains a number of useful definitions for portably dealing with bit-
a9779382
MW
220and byte-level manipulation of larger quantities. The various macros
221and types are named fairly systematically.
222.PP
223The header provides utilities for working with 64-bit quantities, but a
22464-bit integer type is not guaranteed to exist under C89 rules. This
225header takes two approaches. Firstly, if a 64-bit type is found, the
226header defines the macro
227.B HAVE_UINT64
228and defines the various
229.RB ... 64
230macros as described below. Secondly, it unconditionally defines a type
231.B kludge64
232and a family of macros for working with them. See below for details.
233.
234.SS "Type definitions"
235A number of types are defined.
b6b9d458 236.TP
237.B octet
238Equivalent to
239.BR "unsigned char" .
240This is intended to be used when a character array is used to represent
241the octets of some external data format. Note that on some
242architectures the
243.B "unsigned char"
244type may occupy more than 8 bits.
245.TP
246.B uint16
247Equivalent to
248.BR "unsigned short" .
249Intended to be used when a 16-bit value is required. This type is
250always capable of representing any 16-bit unsigned value, but the actual
251type may be wider than 16 bits and will require masking.
252.TP
a9779382
MW
253.B uint24
254Equivalent to some (architecture-dependent) standard type. Capable of
255representing any unsigned 24-bit value, although the the actual type may
256be wider than 24 bits.
257.TP
b6b9d458 258.B uint32
259Equivalent to some (architecture-dependent) standard type. Capable of
260representing any unsigned 32-bit value, although the the actual type may
261be wider than 32 bits.
a9779382
MW
262pp.TP
263.B uint64
264Equivalent to some (architecture-dependent) standard type, if it exists.
265Capable of representing any unsigned 64-bit value, although the the
266actual type may be wider than 64 bits.
267.
268.SS "Size/endianness suffixes"
269Let
270.I w
271be one of the size suffixes: 8, 16, 24, 32, and (if available) 64.
272Furthermore, let
273.I we
274be one of the size-and-endian suffixes
275.IR w ,
276or, where
277.IR w \~>\~8,
278.IB w _L
279or
280.IB w _B \fR,
281where
282.RB ` _L '
283denotes little-endian (Intel, VAX) representation, and
284.RB ` _B '
285denotes big-endian (IBM, network) representation; omitting an explicit
286suffix gives big-endian order by default, since this is most common in
287portable data formats.
b6b9d458 288.PP
a9779382
MW
289The macro invocation
290.BI DOUINTSZ( f )
291invokes a given macro
292.I f
293repeatedly, as
294.IB f ( w )
295for each size suffix
296.I w
297listed above.
b6b9d458 298.PP
a9779382
MW
299The macro invocation
300.BI DOUINTCONV( f )
301invokes a given macro
302.I f
303repeatedly, as
304.IR f ( w ", " we ", " suff )
b6b9d458 305where
a9779382
MW
306.I we
307ranges over size-and-endian suffixes as described above,
308.I w
309is just the corresponding bit width, as an integer, and
310.I suff
311is a suffix
312.IR w ,
313.IB w l\fR,
b6b9d458 314or
a9779382
MW
315.IB w b\fR,
316suitable for a C function name.
b6b9d458 317.PP
a9779382
MW
318These macros are intended to be used to define families of related
319functions.
320.
321.SS "Utility macros"
322For each size-and-endian suffix
323.IR we ,
324the following macros are defined.
325.TP
326.BI TY_ we
327A synonym for the appropriate one of the types
328.BR octet ,
329.BR uint32 ,
330etc.\& listed above.
331.TP
332.BI SZ_ we
333The number of octets needed to represent a value of the corresponding
334type; i.e., this is
335.IR w /8.
336.TP
337.BI MASK_ we
338The largest integer representable in the corresponding type; i.e., this
339is
340.RI 2\*(ss w \*(se\~\-\~1.
341.PP
342(Note that the endianness suffix is irrelevant in the above
343definitions.)
344.PP
345For each size suffix
346.IR w ,
347the macro invocation
348.BI U w ( x )
349coerces an integer
350.I x
351to the appropriate type; specifically, it returns the smallest
352nonnegative integer congruent to
353.I x
354(modulo
355.RI 2\*(ss w \*(se).
356.
357.SS "Shift and rotate"
358For each size suffix
359.IR w ,
360the macro invocations
361.BI LSL w ( x ", " n )
b6b9d458 362and
a9779382
MW
363.BI LSR w ( x ", " n )
364shift a
365.IR w -bit
366quantity
367.I x
368left or right, respectively, by
b6b9d458 369.I n
a9779382
MW
370places; if
371.IR n \~\(>=\~ w
372then
373.I n
374is reduced modulo
375.IR w .
376(This behaviour is unfortunate, but (a) it's what a number of CPUs
377provide natively, and (b) it's a cheap way to prevent undefined
378behaviour.) Similarly,
379.BI ROL w ( x ", " n )
b6b9d458 380and
a9779382
MW
381.BI ROR w ( x ", " n )
382rotate a
383.IR w -bit
384quantity
385.I x
386left or right, respectively, by
b6b9d458 387.I n
a9779382
MW
388places.
389.
374bb459
MW
390.SS "Byte order conversions"
391For each size suffix
392.IR w ,
393the macro invocation
394.BI ENDSWAP w ( x )
395returns the
396.IR w -bit
397value
398.IR x
399with its bytes reversed. The
400.B ENDSWAP8
401macro does nothing (except truncate its operand to 8 bits), but is
402provided for the sake of completeness.
403.PP
404A
405.I big-endian
406representation stores the most significant octet of an integer at the
407lowest address, with the following octets in decreasing order of
408significance. A
409.I little-endian
410representation instead stores the
411.I least
412significant octet at the lowest address, with the following octets in
413increasing order of significance. An environment has a preferred order
414for arranging the constituent octets of an integer of some given size in
415memory; this might be either the big- or little-endian representation
416just described, or something else strange.
417.PP
418It might be possible to rearrange the bits in an integer so that, when
419that integer is stored to memory in the environment's preferred manner,
420you end up with the big- or little-endian representation of the original
421integer; and, similarly, it might be possible to load a big- or
422little-endian representation of an integer into a variable using the
423environment's preferred ordering and then rearrange the bits so as to
424recover the integer value originally represented. If the environment is
425sufficiently strange, these things might not be possible, but this is
426actually quite rare.
427.PP
428Say that an integer has been converted to
429.I big-
430or
431.I "little-endian form"
432if, when it is stored in memory in the environment's preferred manner,
433one ends up with a big- or little-endian representation of the original
434integer. Equivalently, if one starts with a big- or little-endian
435representation of some integer, and loads it into a variable using the
436environment's preferred manner, one ends up with the big- or
437little-endian form of the original integer.
438.PP
439If these things are possible, then the following macros are defined.
440.TP
441.BI HTOL w ( x )
442Convert a
443.IR w -bit
444integer
445.I x
446to little-endian form.
447.TP
448.BI HTOB w ( x )
449Convert a
450.IR w -bit
451integer
452.I x
453to big-endian form.
454.TP
455.BI LTOH w ( x )
456Convert a
457.IR w -bit
458integer
459.I x
460from little-endian form.
461.TP
462.BI BTOH w ( x )
463Convert a
464.IR w -bit
465integer
466.I x
467from big-endian form.
468.
a9779382
MW
469.SS "Load and store"
470The macro invocation
471.BI GETBYTE( p ", " o )
472returns the
473.IR o th
474octet following the address
475.IR p .
476Conversely,
477.BI PUTBYTE( p ", " o ", " v)
478stores
479.I
480v in the
481.IR o th
482byte following the address
483.IR p .
484These macros always operate on byte offsets regardless of the type of
485the pointer
486.IR p .
487.PP
488For each size-and-endian suffix
489.IR we ,
490the macro invocation
491.BI LOAD we ( p )
492loads and returns a value in the corresponding format at address
493.IR p ;
494similarly,
495.BI STORE we ( p ", " x )
496stores the value
497.I x
498at address
499.I p
500in the corresponding format.
501.
502.SS "64-bit support"
503For portability to environments without native 64-bit integers, the
504structure
505.B kludge64
506is defined. If the target platform is known to have an unsigned 64-bit
507integer type, then this structure merely encapsulates a native integer,
508and a decent optimizing compiler can be expected to handle this exactly
509as if it were the native type. Otherwise, it contains two 32-bit halves
510which are processed the hard way.
511.PP
512For each of the above macros with a suffix
513.BR 64 ,
514.BR 64_L ,
b6b9d458 515or
a9779382
MW
516.BR 64_B ,
517an additional `kludge' macro is defined, whose name has an additional
518final underscore; e.g., the kludge macro corresponding to
519.B ROR64
520is
521.BR ROR64_ ;
522and that corresponding to
523.B LOAD64_L
524is
525.BR LOAD64_L_ .
526If the original macro would have
527.I returned
528a value of type
529.BR uint64 ,
530then the kludge macro has an additional first argument, denoted
531.IR d ,
532which should be an lvalue of type
533.BR kludge64 ,
534and the kludge macro will store its result in
535.IR d .
536The kludge macro's remaining arguments are the same as the original
537macro, except that where the original macro accepts an argument of type
538.BR uint64 ,
539the kludge macro accepts an argument of type
540.B kludge64
541instead.
542.PP
543Finally, a number of additional macros are provided, to make working
544with
545.B kludge64
546somewhat less awful.
547.TP
548.BI SET64( d ", " h ", " l )
549Set the high 32 bits of
550.I d
551to be
552.IR h ,
553and the low 32 bits to be
554.IR l .
555Both
556.I h
557and
558.I l
559may be arbitrary integers.
560.TP
561.BI X64( hexh ", " hexl )
562Expands to an initializer for an object of type
563.B kludge64
564where
565.I hexh
566and
567.I hexl
568encode the high and low 32-bit halves in hexadecimal, without any
569.B 0x
570prefix.
571.TP
572.BI ASSIGN( d ", " x )
573Make
574.I d
575be a copy of the
576.B kludge64
577.IR x .
578.TP
579.BI HI64( x )
580Return the high 32 bits of
581.IR x .
582.TP
583.BI LO64( x )
584Return the low 32 bits of
585.IR x .
586.TP
587.BI GET64( t ", " x )
588Return the value of
589.I x
590as a value of type
591.IR t .
592If
593.I t
594is an unsigned integer type, then the value will be truncated to fit as
595necessary; if
596.I t
597is a signed integer type, then the behaviour is undefined if the value
598of
599.I x
600is too large.
601.TP
602.BI AND64( d ", " x ", " y )
603Set
604.I d
605to be the bitwise-and of the two
606.B kludge64
607arguments
608.I x
b6b9d458 609and
a9779382
MW
610.IR y .
611.TP
612.BI OR64( d ", " x ", " y )
613Set
614.I d
615to be the bitwise-or of the two
616.B kludge64
617arguments
618.I x
619and
620.IR y .
621.TP
622.BI XOR64( d ", " x ", " y )
623Set
624.I d
625to be the bitwise-exclusive-or of the two
626.B kludge64
627arguments
628.I x
629and
630.IR y .
631.TP
632.BI CPL64( d ", " x )
633Set
634.I d
635to be the bitwise complement of the
636.B kludge64
637argument
638.IR x .
639.TP
640.BI ADD64( d ", " x ", " y )
641Set
642.I d
643to be the sum of the two
644.B kludge64
645arguments
646.I x
647and
648.IR y .
649.TP
650.BI SUB64( d ", " x ", " y )
651Set
652.I d
653to be the difference of the two
654.B kludge64
655arguments
656.I x
657and
658.IR y .
659.TP
660.BI CMP64( x ", " op ", " y )
661Here,
662.I x
663and
664.I y
665should be arguments of type
666.B kludge64
667and
668.I op
669should be one of the relational operators
670.BR == ,
671.BR < ,
672.BR <= ,
673.BR > ,
674or
675.B >=
676\(en
677.I not
678.BR !=.
679Evaluates nonzero if
680.IR x \~ op \~ y .
681.TP
682.BI ZERO64( x )
683Evaluates nonzero if the
684.B kludge64
685argument
686.I x
687is exactly zero.
08da152e 688.SH "SEE ALSO"
689.BR mLib (3).
b6b9d458 690.SH AUTHOR
9b5ac6ff 691Mark Wooding, <mdw@distorted.org.uk>
b6b9d458 692