2 * Copyright (c) 2019-2020 Hartmut Brandt.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #ifndef constbuf_h_1578777513
27 #define constbuf_h_1578777513
33 #if !defined(HAVE_EXPR_IN_ARRAY_SIZE) && (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>= 9 || (__GNUC__ == 9 && __GNUC_MINOR__ >= 1))))
34 #define HAVE_EXPR_IN_ARRAY_SIZE 1
35 #pragma clang diagnostic push
36 #pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
39 #ifndef HAVE_EXPR_IN_ARRAY_SIZE
46 enum class Constbuf_mode {
56 count_comment(A c, Constbuf_mode &mode)
59 mode = Constbuf_mode::BIN;
65 count_hex(A c, Constbuf_mode &mode, std::size_t &bits)
67 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
68 (c >= 'A' && c <= 'F')) {
70 throw "unaligned hex digit";
76 mode = Constbuf_mode::BIN;
80 template<typename A, typename U>
82 handle_hex(A c, Constbuf_mode &mode, std::size_t &bit, U &n)
84 if (c >= '0' && c <= '9') {
85 n[bit / 8] |= ((c - '0') << 4) >> (bit % 8);
89 if (c >= 'a' && c <= 'f') {
90 n[bit / 8] |= ((c - 'a' + 10) << 4) >> (bit % 8);
94 if (c >= 'A' && c <= 'F') {
95 n[bit / 8] |= ((c - 'A' + 10) << 4) >> (bit % 8);
101 mode = Constbuf_mode::BIN;
107 count_check(A c, Constbuf_mode &mode, std::size_t &)
109 if (c >= '0' && c <= '9')
111 mode = Constbuf_mode::BIN;
117 handle_check(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
119 if (c >= '0' && c <= '9') {
120 addr = 10 * addr + c - '0';
123 if (bits % 8 != 0 || bits / 8 != addr)
124 throw "address check failed";
125 mode = Constbuf_mode::BIN;
131 count_goto(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
133 if (c >= '0' && c <= '9') {
134 addr = 10 * addr + c - '0';
138 throw "cannot go backwards";
140 mode = Constbuf_mode::BIN;
146 count_bin(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
148 if (c == ' ' || c == '\t' || c == '\n')
152 mode = Constbuf_mode::COMMENT;
155 if (c == 'x' || c == 'X') {
156 mode = Constbuf_mode::HEX;
160 mode = Constbuf_mode::CHECK;
164 mode = Constbuf_mode::GOTO;
168 if (c == '0' || c == '1' || c == '.') {
172 throw "bad character";
175 template<typename A, typename U>
177 handle_bin(A c, Constbuf_mode &mode, std::size_t &bit, std::size_t &addr, U &n)
179 if (c == ' ' || c == '\t' || c == '\n')
183 mode = Constbuf_mode::COMMENT;
186 if (c == 'x' || c == 'X') {
187 mode = Constbuf_mode::HEX;
191 mode = Constbuf_mode::CHECK;
196 mode = Constbuf_mode::GOTO;
200 if (c == '0' || c == '.') {
205 n[bit / 8] |= 0x80 >> (bit % 8);
209 throw "bad character";
213 * Count the bits in the test buffer. For a syntax see below.
215 * \tparam A buffer base character type
216 * \tparam a characters
218 * \return number of bits required
220 template<typename A, A ...a>
221 constexpr std::size_t
224 std::size_t bits {0};
225 std::size_t addr {0};
226 auto mode = Constbuf_mode::BIN;
228 for (auto c : {a...}) {
229 for (bool again = true; again; again = false) {
231 case Constbuf_mode::COMMENT:
232 again = count_comment(c, mode);
234 case Constbuf_mode::CHECK:
235 again = count_check(c, mode, bits);
237 case Constbuf_mode::GOTO:
238 again = count_goto(c, mode, bits, addr);
240 case Constbuf_mode::HEX:
241 again = count_hex(c, mode, bits);
243 case Constbuf_mode::BIN:
244 again = count_bin(c, mode, bits, addr);
254 template<typename A, A ...a>
255 #ifdef HAVE_EXPR_IN_ARRAY_SIZE
262 #ifdef HAVE_EXPR_IN_ARRAY_SIZE
263 std::array<uint8_t, (detail::count_bits<A, a...>() + 7) / 8> n {};
265 std::vector<uint8_t> n((detail::count_bits<A, a...>() + 7) / 8);
267 using namespace detail;
270 std::size_t addr {0};
271 auto mode = Constbuf_mode::BIN;
273 for (auto c : {a...}) {
274 for (bool again = true; again; again = false) {
276 case Constbuf_mode::COMMENT:
277 again = count_comment(c, mode);
279 case Constbuf_mode::CHECK:
280 again = handle_check(c, mode, bit, addr);
282 case Constbuf_mode::GOTO:
283 again = count_goto(c, mode, bit, addr);
285 case Constbuf_mode::HEX:
286 again = handle_hex(c, mode, bit, n);
288 case Constbuf_mode::BIN:
289 again = handle_bin(c, mode, bit, addr, n);
297 inline namespace literals {
298 inline namespace cbuf_literals {
300 #ifdef HAVE_EXPR_IN_ARRAY_SIZE
301 template<typename A, A ...a>
304 template<typename A, A ...a>
309 return test::constbuf<A, a...>();
312 } /* namespace cbuf_literals */
313 } /* namespace literals */
315 } /* namespace test */