2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * *****************************************************************************
32 * The private header for the bc library.
36 #ifndef LIBBC_PRIVATE_H
37 #define LIBBC_PRIVATE_H
50 #if BC_ENABLE_MEMCHECK
53 * A typedef for Valgrind builds. This is to add a generation index for error
61 /// The generation index.
67 * Clears the generation byte in a BclNumber and returns the value.
68 * @param n The BclNumber.
69 * @return The value of the index.
71 #define BCL_NO_GEN(n) \
72 ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
75 * Gets the generation index in a BclNumber.
76 * @param n The BclNumber.
77 * @return The generation index.
79 #define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
82 * Turns a BclNumber into a BcNum.
83 * @param c The context.
84 * @param n The BclNumber.
86 #define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
89 * Clears the generation index top byte in the BclNumber.
90 * @param n The BclNumber.
92 #define BCL_CLEAR_GEN(n) \
95 (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
99 #define BCL_CHECK_NUM_GEN(c, bn) \
102 size_t gen_ = BCL_GET_GEN(bn); \
103 BclNum* ptr_ = BCL_NUM(c, bn); \
104 if (BCL_NUM_ARRAY(ptr_) == NULL) \
106 bcl_nonexistentNum(); \
108 if (gen_ != ptr_->gen_idx) \
110 bcl_invalidGeneration(); \
115 #define BCL_CHECK_NUM_VALID(c, bn) \
118 size_t idx_ = BCL_NO_GEN(bn); \
119 if ((c)->nums.len <= idx_) \
121 bcl_numIdxOutOfRange(); \
123 BCL_CHECK_NUM_GEN(c, bn); \
128 * Returns the limb array of the number.
129 * @param bn The number.
130 * @return The limb array.
132 #define BCL_NUM_ARRAY(bn) ((bn)->n.num)
135 * Returns the limb array of the number for a non-pointer.
136 * @param bn The number.
137 * @return The limb array.
139 #define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
142 * Returns the BcNum pointer.
143 * @param bn The number.
144 * @return The BcNum pointer.
146 #define BCL_NUM_NUM(bn) (&(bn)->n)
149 * Returns the BcNum pointer for a non-pointer.
150 * @param bn The number.
151 * @return The BcNum pointer.
153 #define BCL_NUM_NUM_NP(bn) (&(bn).n)
155 // These functions only abort. They exist to give developers some idea of what
156 // went wrong when bugs are found, if they look at the Valgrind stack trace.
159 bcl_invalidGeneration(void);
162 bcl_nonexistentNum(void);
165 bcl_numIdxOutOfRange(void);
167 #else // BC_ENABLE_MEMCHECK
170 * A typedef for non-Valgrind builds.
172 typedef BcNum BclNum;
174 #define BCL_NO_GEN(n) ((n).i)
175 #define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i))
176 #define BCL_CLEAR_GEN(n) ((void) (n))
178 #define BCL_CHECK_NUM_GEN(c, bn)
179 #define BCL_CHECK_NUM_VALID(c, n)
181 #define BCL_NUM_ARRAY(bn) ((bn)->num)
182 #define BCL_NUM_ARRAY_NP(bn) ((bn).num)
184 #define BCL_NUM_NUM(bn) (bn)
185 #define BCL_NUM_NUM_NP(bn) (&(bn))
187 #endif // BC_ENABLE_MEMCHECK
190 * A header that sets a jump.
191 * @param vm The thread data.
192 * @param l The label to jump to on error.
194 #define BC_FUNC_HEADER(vm, l) \
198 vm->err = BCL_ERROR_NONE; \
203 * A footer for functions that do not return an error code.
205 #define BC_FUNC_FOOTER_NO_ERR(vm) \
213 * A footer for functions that *do* return an error code.
214 * @param vm The thread data.
215 * @param e The error variable to set.
217 #define BC_FUNC_FOOTER(vm, e) \
221 BC_FUNC_FOOTER_NO_ERR(vm); \
226 * A footer that sets up n based the value of e and sets up the return value in
228 * @param c The context.
229 * @param e The error.
230 * @param bn The number.
231 * @param idx The idx to set as the return value.
233 #define BC_MAYBE_SETUP(c, e, bn, idx) \
236 if (BC_ERR((e) != BCL_ERROR_NONE)) \
238 if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
239 idx.i = 0 - (size_t) (e); \
241 else idx = bcl_num_insert(c, &(bn)); \
246 * A header to check the context and return an error encoded in a number if it
248 * @param c The context.
250 #define BC_CHECK_CTXT(vm, c) \
253 c = bcl_contextHelper(vm); \
254 if (BC_ERR(c == NULL)) \
257 n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
264 * A header to check the context and return an error directly if it is bad.
265 * @param c The context.
267 #define BC_CHECK_CTXT_ERR(vm, c) \
270 c = bcl_contextHelper(vm); \
271 if (BC_ERR(c == NULL)) \
273 return BCL_ERROR_INVALID_CONTEXT; \
279 * A header to check the context and abort if it is bad.
280 * @param c The context.
282 #define BC_CHECK_CTXT_ASSERT(vm, c) \
285 c = bcl_contextHelper(vm); \
291 * A header to check the number in the context and return an error encoded as a
292 * @param c The context.
293 * number if it is bad.
294 * @param n The BclNumber.
296 #define BC_CHECK_NUM(c, n) \
299 size_t no_gen_ = BCL_NO_GEN(n); \
300 if (BC_ERR(no_gen_ >= (c)->nums.len)) \
302 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
306 n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
310 BCL_CHECK_NUM_GEN(c, n); \
317 * A header to check the number in the context and return an error directly if
319 * @param c The context.
320 * @param n The BclNumber.
322 #define BC_CHECK_NUM_ERR(c, n) \
325 size_t no_gen_ = BCL_NO_GEN(n); \
326 if (BC_ERR(no_gen_ >= (c)->nums.len)) \
328 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
330 return (BclError) (0 - (n).i); \
332 else return BCL_ERROR_INVALID_NUM; \
334 BCL_CHECK_NUM_GEN(c, n); \
341 * Grows the context's nums array if necessary.
342 * @param c The context.
344 #define BCL_GROW_NUMS(c) \
347 if ((c)->free_nums.len == 0) \
349 bc_vec_grow(&((c)->nums), 1); \
355 * Frees a BcNum for bcl. This is a destructor.
356 * @param num The BcNum to free, as a void pointer.
359 bcl_num_destruct(void* num);
361 /// The actual context struct.
362 typedef struct BclCtxt
364 /// The context's scale.
367 /// The context's ibase.
370 /// The context's obase.
373 /// A vector of BcNum numbers.
376 /// A vector of BclNumbers. These are the indices in nums that are currently
377 /// not used (because they were freed).
383 * Returns the @a BcVm for the current thread.
384 * @return The vm for the current thread.
387 bcl_getspecific(void);
391 typedef pthread_key_t BclTls;
395 typedef DWORD BclTls;
399 #endif // LIBBC_PRIVATE_H