]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/include/library.h
Import device-tree files from Linux 6.3
[FreeBSD/FreeBSD.git] / contrib / bc / include / library.h
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
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.
17  *
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.
29  *
30  * *****************************************************************************
31  *
32  * The private header for the bc library.
33  *
34  */
35
36 #ifndef LIBBC_PRIVATE_H
37 #define LIBBC_PRIVATE_H
38
39 #ifndef _WIN32
40
41 #include <pthread.h>
42
43 #endif // _WIN32
44
45 #include <bcl.h>
46
47 #include <num.h>
48 #include <vm.h>
49
50 #if BC_ENABLE_MEMCHECK
51
52 /**
53  * A typedef for Valgrind builds. This is to add a generation index for error
54  * checking.
55  */
56 typedef struct BclNum
57 {
58         /// The number.
59         BcNum n;
60
61         /// The generation index.
62         size_t gen_idx;
63
64 } BclNum;
65
66 /**
67  * Clears the generation byte in a BclNumber and returns the value.
68  * @param n  The BclNumber.
69  * @return   The value of the index.
70  */
71 #define BCL_NO_GEN(n) \
72         ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
73
74 /**
75  * Gets the generation index in a BclNumber.
76  * @param n  The BclNumber.
77  * @return   The generation index.
78  */
79 #define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
80
81 /**
82  * Turns a BclNumber into a BcNum.
83  * @param c  The context.
84  * @param n  The BclNumber.
85  */
86 #define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
87
88 /**
89  * Clears the generation index top byte in the BclNumber.
90  * @param n  The BclNumber.
91  */
92 #define BCL_CLEAR_GEN(n)                                                       \
93         do                                                                         \
94         {                                                                          \
95                 (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
96         }                                                                          \
97         while (0)
98
99 #define BCL_CHECK_NUM_GEN(c, bn)         \
100         do                                   \
101         {                                    \
102                 size_t gen_ = BCL_GET_GEN(bn);   \
103                 BclNum* ptr_ = BCL_NUM(c, bn);   \
104                 if (BCL_NUM_ARRAY(ptr_) == NULL) \
105                 {                                \
106                         bcl_nonexistentNum();        \
107                 }                                \
108                 if (gen_ != ptr_->gen_idx)       \
109                 {                                \
110                         bcl_invalidGeneration();     \
111                 }                                \
112         }                                    \
113         while (0)
114
115 #define BCL_CHECK_NUM_VALID(c, bn)    \
116         do                                \
117         {                                 \
118                 size_t idx_ = BCL_NO_GEN(bn); \
119                 if ((c)->nums.len <= idx_)    \
120                 {                             \
121                         bcl_numIdxOutOfRange();   \
122                 }                             \
123                 BCL_CHECK_NUM_GEN(c, bn);     \
124         }                                 \
125         while (0)
126
127 /**
128  * Returns the limb array of the number.
129  * @param bn  The number.
130  * @return    The limb array.
131  */
132 #define BCL_NUM_ARRAY(bn) ((bn)->n.num)
133
134 /**
135  * Returns the limb array of the number for a non-pointer.
136  * @param bn  The number.
137  * @return    The limb array.
138  */
139 #define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
140
141 /**
142  * Returns the BcNum pointer.
143  * @param bn  The number.
144  * @return    The BcNum pointer.
145  */
146 #define BCL_NUM_NUM(bn) (&(bn)->n)
147
148 /**
149  * Returns the BcNum pointer for a non-pointer.
150  * @param bn  The number.
151  * @return    The BcNum pointer.
152  */
153 #define BCL_NUM_NUM_NP(bn) (&(bn).n)
154
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.
157
158 BC_NORETURN void
159 bcl_invalidGeneration(void);
160
161 BC_NORETURN void
162 bcl_nonexistentNum(void);
163
164 BC_NORETURN void
165 bcl_numIdxOutOfRange(void);
166
167 #else // BC_ENABLE_MEMCHECK
168
169 /**
170  * A typedef for non-Valgrind builds.
171  */
172 typedef BcNum BclNum;
173
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))
177
178 #define BCL_CHECK_NUM_GEN(c, bn)
179 #define BCL_CHECK_NUM_VALID(c, n)
180
181 #define BCL_NUM_ARRAY(bn) ((bn)->num)
182 #define BCL_NUM_ARRAY_NP(bn) ((bn).num)
183
184 #define BCL_NUM_NUM(bn) (bn)
185 #define BCL_NUM_NUM_NP(bn) (&(bn))
186
187 #endif // BC_ENABLE_MEMCHECK
188
189 /**
190  * A header that sets a jump.
191  * @param vm  The thread data.
192  * @param l   The label to jump to on error.
193  */
194 #define BC_FUNC_HEADER(vm, l)     \
195         do                            \
196         {                             \
197                 BC_SETJMP(vm, l);         \
198                 vm->err = BCL_ERROR_NONE; \
199         }                             \
200         while (0)
201
202 /**
203  * A footer for functions that do not return an error code.
204  */
205 #define BC_FUNC_FOOTER_NO_ERR(vm) \
206         do                            \
207         {                             \
208                 BC_UNSETJMP(vm);          \
209         }                             \
210         while (0)
211
212 /**
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.
216  */
217 #define BC_FUNC_FOOTER(vm, e)      \
218         do                             \
219         {                              \
220                 e = vm->err;               \
221                 BC_FUNC_FOOTER_NO_ERR(vm); \
222         }                              \
223         while (0)
224
225 /**
226  * A footer that sets up n based the value of e and sets up the return value in
227  * idx.
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.
232  */
233 #define BC_MAYBE_SETUP(c, e, bn, idx)                                          \
234         do                                                                         \
235         {                                                                          \
236                 if (BC_ERR((e) != BCL_ERROR_NONE))                                     \
237                 {                                                                      \
238                         if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
239                         idx.i = 0 - (size_t) (e);                                          \
240                 }                                                                      \
241                 else idx = bcl_num_insert(c, &(bn));                                   \
242         }                                                                          \
243         while (0)
244
245 /**
246  * A header to check the context and return an error encoded in a number if it
247  * is bad.
248  * @param c  The context.
249  */
250 #define BC_CHECK_CTXT(vm, c)                                   \
251         do                                                         \
252         {                                                          \
253                 c = bcl_contextHelper(vm);                             \
254                 if (BC_ERR(c == NULL))                                 \
255                 {                                                      \
256                         BclNumber n_num_;                                  \
257                         n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
258                         return n_num_;                                     \
259                 }                                                      \
260         }                                                          \
261         while (0)
262
263 /**
264  * A header to check the context and return an error directly if it is bad.
265  * @param c  The context.
266  */
267 #define BC_CHECK_CTXT_ERR(vm, c)              \
268         do                                        \
269         {                                         \
270                 c = bcl_contextHelper(vm);            \
271                 if (BC_ERR(c == NULL))                \
272                 {                                     \
273                         return BCL_ERROR_INVALID_CONTEXT; \
274                 }                                     \
275         }                                         \
276         while (0)
277
278 /**
279  * A header to check the context and abort if it is bad.
280  * @param c  The context.
281  */
282 #define BC_CHECK_CTXT_ASSERT(vm, c) \
283         do                              \
284         {                               \
285                 c = bcl_contextHelper(vm);  \
286                 assert(c != NULL);          \
287         }                               \
288         while (0)
289
290 /**
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.
295  */
296 #define BC_CHECK_NUM(c, n)                                         \
297         do                                                             \
298         {                                                              \
299                 size_t no_gen_ = BCL_NO_GEN(n);                            \
300                 if (BC_ERR(no_gen_ >= (c)->nums.len))                      \
301                 {                                                          \
302                         if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
303                         else                                                   \
304                         {                                                      \
305                                 BclNumber n_num_;                                  \
306                                 n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM;     \
307                                 return n_num_;                                     \
308                         }                                                      \
309                 }                                                          \
310                 BCL_CHECK_NUM_GEN(c, n);                                   \
311         }                                                              \
312         while (0)
313
314 //clang-format off
315
316 /**
317  * A header to check the number in the context and return an error directly if
318  * it is bad.
319  * @param c  The context.
320  * @param n  The BclNumber.
321  */
322 #define BC_CHECK_NUM_ERR(c, n)                         \
323         do                                                 \
324         {                                                  \
325                 size_t no_gen_ = BCL_NO_GEN(n);                \
326                 if (BC_ERR(no_gen_ >= (c)->nums.len))          \
327                 {                                              \
328                         if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
329                         {                                          \
330                                 return (BclError) (0 - (n).i);         \
331                         }                                          \
332                         else return BCL_ERROR_INVALID_NUM;         \
333                 }                                              \
334                 BCL_CHECK_NUM_GEN(c, n);                       \
335         }                                                  \
336         while (0)
337
338 //clang-format on
339
340 /**
341  * Grows the context's nums array if necessary.
342  * @param c  The context.
343  */
344 #define BCL_GROW_NUMS(c)                  \
345         do                                    \
346         {                                     \
347                 if ((c)->free_nums.len == 0)      \
348                 {                                 \
349                         bc_vec_grow(&((c)->nums), 1); \
350                 }                                 \
351         }                                     \
352         while (0)
353
354 /**
355  * Frees a BcNum for bcl. This is a destructor.
356  * @param num  The BcNum to free, as a void pointer.
357  */
358 void
359 bcl_num_destruct(void* num);
360
361 /// The actual context struct.
362 typedef struct BclCtxt
363 {
364         /// The context's scale.
365         size_t scale;
366
367         /// The context's ibase.
368         size_t ibase;
369
370         /// The context's obase.
371         size_t obase;
372
373         /// A vector of BcNum numbers.
374         BcVec nums;
375
376         /// A vector of BclNumbers. These are the indices in nums that are currently
377         /// not used (because they were freed).
378         BcVec free_nums;
379
380 } BclCtxt;
381
382 /**
383  * Returns the @a BcVm for the current thread.
384  * @return  The vm for the current thread.
385  */
386 BcVm*
387 bcl_getspecific(void);
388
389 #ifndef _WIN32
390
391 typedef pthread_key_t BclTls;
392
393 #else // _WIN32
394
395 typedef DWORD BclTls;
396
397 #endif // _WIN32
398
399 #endif // LIBBC_PRIVATE_H