Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/include/library.h
39507 views
1
/*
2
* *****************************************************************************
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2018-2025 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
400
401