MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
endian.h
Go to the documentation of this file.
1/* MMgr - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2 * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Commercial OR LicenseRef-Educational
3 *
4 * Every use falls under AGPL-3.0-or-later unless you hold explicit permission, which is either a
5 * negotiated commercial licensing contract or an educator's license issued to you personally.
6 */
7/**
8 * @file endian.h
9 * @brief Endian reads and writes: the width enum, the argument type, the five entry points and the two
10 * order tables.
11 * @author dstroy0 (Douglas Quigg) <dquigg123@gmail.com>
12 * @date 2026-08-29
13 *
14 * @note parva_extremitas moves bytes in the host's own order and magna_extremitas in the reverse of it.
15 * Nothing here consults MMGR_HW_BIG_ENDIAN, and so the two names hold on a little endian host and
16 * stand for the opposite orders on a big endian one.
17 * @note The two tables share the table type and the rev entry. Their wr and rd differ, since one pair
18 * reverses and the other does not.
19 */
20#ifndef MMGR_ENDIAN_H
21#define MMGR_ENDIAN_H
22
23#include "mmgr.h"
24
25EMBED_BEGIN_DECLS
26
27/**
28 * @brief Width of one endian read or write, counted in bytes.
29 *
30 * @note The enumerators are the byte counts themselves, and so the implementation switches on them directly.
31 * @note One byte on every compiler, through EMBED_ENUM_BYTE.
32 * @warning Nothing holds a value to these three. The switches in endian.c test 2 and 4 and take
33 * everything else on the default arm, which moves eight bytes.
34 */
35EMBED_ENUM_BYTE(mmgr_endian_width, MMGR_ENDIAN_16 = 2, /**< Two bytes. */
36 MMGR_ENDIAN_32 = 4, /**< Four bytes. */
37 MMGR_ENDIAN_64 = 8 /**< Eight bytes. */
38);
39
40/**
41 * @brief Arguments for the endian calls, where each call reads only the members it needs.
42 *
43 * @note wr reads dst, val and width. rd reads src and width. rev reads val and width.
44 * @note width is what bounds both pointers. wr and rd touch that many bytes of the one they use, or
45 * eight when width is not one of the mmgr_endian_width enumerators. rev reads neither pointer.
46 * @warning Neither pointer is checked. endian.c passes them straight to proximus_operor, which
47 * dereferences them with no test and no assertion.
48 */
49typedef struct
50{
51 uint8_t *const dst; /**< Destination for wr [BORROWS]. */
52 const uint8_t *const src; /**< Source for rd [BORROWS]. */
53 const uint64_t val; /**< Value for wr, or the value rev reverses. */
54 const mmgr_endian_width width; /**< Bytes the call moves. */
55} EndianCfg;
56
57/**
58 * @brief Type of an endian dispatch table.
59 *
60 * @note EMBED_TABLE_LAYOUT asserts the three members sit at consecutive EMBED_FUNCTION_POINTER_BYTES offsets, with
61 * nothing else.
62 * @note Two instances share this type, one per byte order. Which one a call goes through is what sets
63 * the order, and no member takes it as an argument.
64 * @note wr hands back args->width as it was given. The other two return the value they produced.
65 */
66typedef struct
67{
68 size_t (*wr)(const EndianCfg *args); /**< Writes width bytes of val to dst in the table's order. */
69 uint64_t (*rd)(const EndianCfg *args); /**< Reads width bytes from src in the table's order. */
70 uint64_t (*rev)(const EndianCfg *args); /**< Reverses val at width bytes. */
71} EndianNs;
72EMBED_TABLE_LAYOUT(EndianNs, wr, rd, rev);
73
74/**
75 * @brief Writes args->width bytes of args->val to args->dst without reversing them.
76 *
77 * @param[in,out] args Destination, value and width [BORROWS].
78 * @return args->width.
79 * @warning args->dst must be writable for args->width bytes. Nothing checks it. endian.c hands it to
80 * proxim.put16, put32 or put64, each of which stores through it with no test.
81 * @warning args->width must be one of the mmgr_endian_width enumerators. Any other value writes eight
82 * bytes.
83 */
84size_t mmgr_wr_le(const EndianCfg *args);
85
86/**
87 * @brief Reads args->width bytes from args->src without reversing them.
88 *
89 * @param[in] args Source and width [BORROWS].
90 * @return The value read, in the low args->width bytes.
91 * @warning args->src must be readable for args->width bytes. Nothing checks it. endian.c hands it to
92 * proxim.load16, load32 or load64, each of which reads through it with no test.
93 * @warning args->width must be one of the mmgr_endian_width enumerators. Any other value reads eight
94 * bytes.
95 */
96uint64_t mmgr_rd_le(const EndianCfg *args);
97
98/**
99 * @brief Reverses args->val, then writes args->width bytes of it to args->dst.
100 *
101 * @param[in,out] args Destination, value and width [BORROWS].
102 * @return args->width.
103 * @warning args->dst must be writable for args->width bytes. Nothing checks it. endian.c hands it to
104 * proxim.put16, put32 or put64, each of which stores through it with no test.
105 * @warning args->width must be one of the mmgr_endian_width enumerators. Any other value writes eight
106 * bytes. One above eight wraps the reversal's shift count, and a width of 0 shifts by 64,
107 * which is undefined.
108 */
109size_t mmgr_wr_be(const EndianCfg *args);
110
111/**
112 * @brief Reads args->width bytes from args->src, then reverses them.
113 *
114 * @param[in] args Source and width [BORROWS].
115 * @return The reversed value, in the low args->width bytes.
116 * @warning args->src must be readable for args->width bytes. Nothing checks it. endian.c hands it to
117 * proxim.load16, load32 or load64, each of which reads through it with no test.
118 * @warning args->width must be one of the mmgr_endian_width enumerators. Any other value reads eight
119 * bytes. One above eight wraps the reversal's shift count, and a width of 0 shifts by 64,
120 * which is undefined.
121 */
122uint64_t mmgr_rd_be(const EndianCfg *args);
123
124/**
125 * @brief Reverses the byte order of args->val at args->width bytes.
126 *
127 * @param[in] args Value and width [BORROWS].
128 * @return The reversed value, right-aligned into the low args->width bytes.
129 * @note Reads args->val and args->width, alone, and so it touches no buffer and dst and src take
130 * no part.
131 * @note Both tables point rev at this one function, which reverses whatever it is given without
132 * reference to either order.
133 * @warning args->width must be one of the mmgr_endian_width enumerators. 8 minus it is unsigned. A
134 * width above eight wraps into a very large shift count, and a width of 0 shifts a 64-bit
135 * value by 64, which is undefined.
136 */
137uint64_t mmgr_endian_rev(const EndianCfg *args);
138
139/**
140 * @brief Dispatch table instance named parva_extremitas, the little endian order.
141 *
142 * @note wr and rd move bytes as they lie, and so they land in the host's own order. This module never
143 * consults MMGR_HW_BIG_ENDIAN, and so the name holds on a little endian host and this table writes
144 * big endian bytes on a big endian one.
145 * @note rev is the same function both tables use.
146 */
147EMBED_TABLE_STORAGE EndianNs parva_extremitas EMBED_UNUSED = {
148 .wr = mmgr_wr_le,
149 .rd = mmgr_rd_le,
150 .rev = mmgr_endian_rev,
151};
152
153/**
154 * @brief Dispatch table instance named magna_extremitas, the big endian order.
155 *
156 * @note wr reverses before writing and rd reverses after reading, and so the bytes land in the reverse of
157 * the host's own order. That is big endian on a little endian host, as the name
158 * records, and little endian on a big endian one.
159 * @note rev is shared with parva_extremitas.
160 */
161EMBED_TABLE_STORAGE EndianNs magna_extremitas EMBED_UNUSED = {
162 .wr = mmgr_wr_be,
163 .rd = mmgr_rd_be,
164 .rev = mmgr_endian_rev,
165};
166
167EMBED_END_DECLS
168
169#endif
uint64_t mmgr_rd_le(const EndianCfg *args)
Reads args->width bytes from args->src without reversing them.
mmgr_endian_width
Width of one endian read or write, counted in bytes.
Definition endian.h:38
@ MMGR_ENDIAN_16
Definition endian.h:38
@ MMGR_ENDIAN_64
Definition endian.h:38
@ MMGR_ENDIAN_32
Definition endian.h:38
static const EndianNs magna_extremitas
Dispatch table instance named magna_extremitas, the big endian order.
Definition endian.h:161
size_t mmgr_wr_le(const EndianCfg *args)
Writes args->width bytes of args->val to args->dst without reversing them.
static const EndianNs parva_extremitas
Dispatch table instance named parva_extremitas, the little endian order.
Definition endian.h:147
uint64_t mmgr_endian_rev(const EndianCfg *args)
Reverses the byte order of args->val at args->width bytes.
uint64_t mmgr_rd_be(const EndianCfg *args)
Reads args->width bytes from args->src, then reverses them.
size_t mmgr_wr_be(const EndianCfg *args)
Reverses args->val, then writes args->width bytes of it to args->dst.
The embedded_types headers every module builds on.
Arguments for the endian calls, where each call reads only the members it needs.
Definition endian.h:50
const mmgr_endian_width width
Definition endian.h:54
const uint64_t val
Definition endian.h:53
uint8_t *const dst
Definition endian.h:51
const uint8_t *const src
Definition endian.h:52
Type of an endian dispatch table.
Definition endian.h:67
uint64_t(*) rd(const EndianCfg *args)
Definition endian.h:69
size_t(*) wr(const EndianCfg *args)
Definition endian.h:68
uint64_t(*) rev(const EndianCfg *args)
Definition endian.h:70