diff options
Diffstat (limited to 'contrib/bc/src/library.c')
-rw-r--r-- | contrib/bc/src/library.c | 1276 |
1 files changed, 826 insertions, 450 deletions
diff --git a/contrib/bc/src/library.c b/contrib/bc/src/library.c index b72b83589135..cc32a3a3a98c 100644 --- a/contrib/bc/src/library.c +++ b/contrib/bc/src/library.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. + * Copyright (c) 2018-2023 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,87 +45,200 @@ #include <num.h> #include <vm.h> +#ifndef _WIN32 +#include <pthread.h> +#endif // _WIN32 + // The asserts in this file are important to testing; in many cases, the test // would not work without the asserts, so don't remove them without reason. // // Also, there are many uses of bc_num_clear() here; that is because numbers are // being reused, and a clean slate is required. // -// Also, there are a bunch of BC_UNSETJMP and BC_SETJMP_LOCKED() between calls -// to bc_num_init(). That is because locals are being initialized, and unlike bc -// proper, this code cannot assume that allocation failures are fatal. So we -// have to reset the jumps every time to ensure that the locals will be correct -// after jumping. +// Also, there are a bunch of BC_UNSETJMP between calls to bc_num_init(). That +// is because locals are being initialized, and unlike bc proper, this code +// cannot assume that allocation failures are fatal. So we have to reset the +// jumps every time to ensure that the locals will be correct after jumping. -void -bcl_handleSignal(void) +#if BC_ENABLE_MEMCHECK + +BC_NORETURN void +bcl_invalidGeneration(void) +{ + abort(); +} + +BC_NORETURN void +bcl_nonexistentNum(void) +{ + abort(); +} + +BC_NORETURN void +bcl_numIdxOutOfRange(void) +{ + abort(); +} + +#endif // BC_ENABLE_MEMCHECK + +static BclTls* tls = NULL; +static BclTls tls_real; + +BclError +bcl_start(void) +{ +#ifndef _WIN32 + + int r; + + if (tls != NULL) return BCL_ERROR_NONE; + + r = pthread_key_create(&tls_real, NULL); + if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR; + +#else // _WIN32 + + if (tls != NULL) return BCL_ERROR_NONE; + + tls_real = TlsAlloc(); + if (BC_ERR(tls_real == TLS_OUT_OF_INDEXES)) + { + return BCL_ERROR_FATAL_ALLOC_ERR; + } + +#endif // _WIN32 + + tls = &tls_real; + + return BCL_ERROR_NONE; +} + +/** + * Sets the thread-specific data for the thread. + * @param vm The @a BcVm to set as the thread data. + * @return An error code, if any. + */ +static BclError +bcl_setspecific(BcVm* vm) { - // Signal already in flight, or bc is not executing. - if (vm.sig || !vm.running) return; +#ifndef _WIN32 + + int r; + + assert(tls != NULL); + + r = pthread_setspecific(tls_real, vm); + if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR; - vm.sig = 1; +#else // _WIN32 - assert(vm.jmp_bufs.len); + bool r; - if (!vm.sig_lock) BC_JMP; + assert(tls != NULL); + + r = TlsSetValue(tls_real, vm); + if (BC_ERR(!r)) return BCL_ERROR_FATAL_ALLOC_ERR; + +#endif // _WIN32 + + return BCL_ERROR_NONE; } -bool -bcl_running(void) +BcVm* +bcl_getspecific(void) { - return vm.running != 0; + BcVm* vm; + +#ifndef _WIN32 + + vm = pthread_getspecific(tls_real); + +#else // _WIN32 + + vm = TlsGetValue(tls_real); + +#endif // _WIN32 + + return vm; } BclError bcl_init(void) { BclError e = BCL_ERROR_NONE; + BcVm* vm; + + assert(tls != NULL); - BC_SIG_LOCK; + vm = bcl_getspecific(); + if (vm != NULL) + { + assert(vm->refs >= 1); - vm.refs += 1; + vm->refs += 1; - if (vm.refs > 1) + return e; + } + + vm = bc_vm_malloc(sizeof(BcVm)); + if (BC_ERR(vm == NULL)) return BCL_ERROR_FATAL_ALLOC_ERR; + + e = bcl_setspecific(vm); + if (BC_ERR(e != BCL_ERROR_NONE)) { - BC_SIG_UNLOCK; + free(vm); return e; } + memset(vm, 0, sizeof(BcVm)); + + vm->refs += 1; + + assert(vm->refs == 1); + // Setting these to NULL ensures that if an error occurs, we only free what // is necessary. - vm.ctxts.v = NULL; - vm.jmp_bufs.v = NULL; - vm.out.v = NULL; + vm->ctxts.v = NULL; + vm->jmp_bufs.v = NULL; + vm->out.v = NULL; - vm.abrt = false; + vm->abrt = false; + vm->leading_zeroes = false; + vm->digit_clamp = true; // The jmp_bufs always has to be initialized first. - bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE); + bc_vec_init(&vm->jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE); - BC_FUNC_HEADER_INIT(err); + BC_FUNC_HEADER(vm, err); bc_vm_init(); - bc_vec_init(&vm.ctxts, sizeof(BclContext), BC_DTOR_NONE); - bc_vec_init(&vm.out, sizeof(uchar), BC_DTOR_NONE); + bc_vec_init(&vm->ctxts, sizeof(BclContext), BC_DTOR_NONE); + bc_vec_init(&vm->out, sizeof(uchar), BC_DTOR_NONE); - // We need to seed this in case /dev/random and /dev/urandm don't work. +#if BC_ENABLE_EXTRA_MATH + + // We need to seed this in case /dev/random and /dev/urandom don't work. srand((unsigned int) time(NULL)); - bc_rand_init(&vm.rng); + bc_rand_init(&vm->rng); + +#endif // BC_ENABLE_EXTRA_MATH err: + + BC_FUNC_FOOTER(vm, e); + // This is why we had to set them to NULL. - if (BC_ERR(vm.err)) + if (BC_ERR(vm != NULL && vm->err)) { - if (vm.out.v != NULL) bc_vec_free(&vm.out); - if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs); - if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts); + if (vm->out.v != NULL) bc_vec_free(&vm->out); + if (vm->jmp_bufs.v != NULL) bc_vec_free(&vm->jmp_bufs); + if (vm->ctxts.v != NULL) bc_vec_free(&vm->ctxts); + bcl_setspecific(NULL); + free(vm); } - BC_FUNC_FOOTER_UNLOCK(e); - - assert(!vm.running && !vm.sig && !vm.sig_lock); - return e; } @@ -133,108 +246,153 @@ BclError bcl_pushContext(BclContext ctxt) { BclError e = BCL_ERROR_NONE; + BcVm* vm = bcl_getspecific(); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_push(&vm.ctxts, &ctxt); + bc_vec_push(&vm->ctxts, &ctxt); err: - BC_FUNC_FOOTER_UNLOCK(e); + + BC_FUNC_FOOTER(vm, e); return e; } void bcl_popContext(void) { - if (vm.ctxts.len) bc_vec_pop(&vm.ctxts); + BcVm* vm = bcl_getspecific(); + + if (vm->ctxts.len) bc_vec_pop(&vm->ctxts); +} + +static BclContext +bcl_contextHelper(BcVm* vm) +{ + if (!vm->ctxts.len) return NULL; + return *((BclContext*) bc_vec_top(&vm->ctxts)); } BclContext bcl_context(void) { - if (!vm.ctxts.len) return NULL; - return *((BclContext*) bc_vec_top(&vm.ctxts)); + BcVm* vm = bcl_getspecific(); + return bcl_contextHelper(vm); } void bcl_free(void) { size_t i; + BcVm* vm = bcl_getspecific(); - BC_SIG_LOCK; + vm->refs -= 1; + if (vm->refs) return; - vm.refs -= 1; +#if BC_ENABLE_EXTRA_MATH + bc_rand_free(&vm->rng); +#endif // BC_ENABLE_EXTRA_MATH + bc_vec_free(&vm->out); - if (vm.refs) + for (i = 0; i < vm->ctxts.len; ++i) { - BC_SIG_UNLOCK; - return; - } - - bc_rand_free(&vm.rng); - bc_vec_free(&vm.out); - - for (i = 0; i < vm.ctxts.len; ++i) - { - BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i)); + BclContext ctxt = *((BclContext*) bc_vec_item(&vm->ctxts, i)); bcl_ctxt_free(ctxt); } - bc_vec_free(&vm.ctxts); + bc_vec_free(&vm->ctxts); bc_vm_atexit(); - BC_SIG_UNLOCK; + free(vm); + bcl_setspecific(NULL); +} + +void +bcl_end(void) +{ +#ifndef _WIN32 - memset(&vm, 0, sizeof(BcVm)); + // We ignore the return value. + pthread_key_delete(tls_real); - assert(!vm.running && !vm.sig && !vm.sig_lock); +#else // _WIN32 + + // We ignore the return value. + TlsFree(tls_real); + +#endif // _WIN32 + + tls = NULL; } void bcl_gc(void) { - BC_SIG_LOCK; bc_vm_freeTemps(); - BC_SIG_UNLOCK; } bool bcl_abortOnFatalError(void) { - return vm.abrt; + BcVm* vm = bcl_getspecific(); + + return vm->abrt; } void bcl_setAbortOnFatalError(bool abrt) { - vm.abrt = abrt; + BcVm* vm = bcl_getspecific(); + + vm->abrt = abrt; } bool bcl_leadingZeroes(void) { - return vm.leading_zeroes; + BcVm* vm = bcl_getspecific(); + + return vm->leading_zeroes; } void bcl_setLeadingZeroes(bool leadingZeroes) { - vm.leading_zeroes = leadingZeroes; + BcVm* vm = bcl_getspecific(); + + vm->leading_zeroes = leadingZeroes; +} + +bool +bcl_digitClamp(void) +{ + BcVm* vm = bcl_getspecific(); + + return vm->digit_clamp; +} + +void +bcl_setDigitClamp(bool digitClamp) +{ + BcVm* vm = bcl_getspecific(); + + vm->digit_clamp = digitClamp; } BclContext bcl_ctxt_create(void) { + BcVm* vm = bcl_getspecific(); BclContext ctxt = NULL; - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); // We want the context to be free of any interference of other parties, so // malloc() is appropriate here. ctxt = bc_vm_malloc(sizeof(BclCtxt)); - bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM); + bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM); bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE); ctxt->scale = 0; @@ -242,16 +400,15 @@ bcl_ctxt_create(void) ctxt->obase = 10; err: - if (BC_ERR(vm.err && ctxt != NULL)) + + if (BC_ERR(vm->err && ctxt != NULL)) { if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums); free(ctxt); ctxt = NULL; } - BC_FUNC_FOOTER_NO_ERR; - - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER_NO_ERR(vm); return ctxt; } @@ -259,11 +416,9 @@ err: void bcl_ctxt_free(BclContext ctxt) { - BC_SIG_LOCK; bc_vec_free(&ctxt->free_nums); bc_vec_free(&ctxt->nums); free(ctxt); - BC_SIG_UNLOCK; } void @@ -315,8 +470,13 @@ BclError bcl_err(BclNumber n) { BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ERR(ctxt); + BC_CHECK_CTXT_ERR(vm, ctxt); + + // We need to clear the top byte in memcheck mode. We can do this because + // the parameter is a copy. + BCL_CLEAR_GEN(n); // Errors are encoded as (0 - error_code). If the index is in that range, it // is an encoded error. @@ -335,14 +495,14 @@ bcl_err(BclNumber n) * @return The resulting BclNumber from the insert. */ static BclNumber -bcl_num_insert(BclContext ctxt, BcNum* restrict n) +bcl_num_insert(BclContext ctxt, BclNum* restrict n) { BclNumber idx; // If there is a free spot... if (ctxt->free_nums.len) { - BcNum* ptr; + BclNum* ptr; // Get the index of the free spot and remove it. idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums)); @@ -350,17 +510,34 @@ bcl_num_insert(BclContext ctxt, BcNum* restrict n) // Copy the number into the spot. ptr = bc_vec_item(&ctxt->nums, idx.i); - memcpy(ptr, n, sizeof(BcNum)); + + memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum)); + +#if BC_ENABLE_MEMCHECK + + ptr->gen_idx += 1; + + if (ptr->gen_idx == UCHAR_MAX) + { + ptr->gen_idx = 0; + } + + idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT)); + +#endif // BC_ENABLE_MEMCHECK } else { - // Just push the number onto the vector. +#if BC_ENABLE_MEMCHECK + n->gen_idx = 0; +#endif // BC_ENABLE_MEMCHECK + + // Just push the number onto the vector because the generation index is + // 0. idx.i = ctxt->nums.len; bc_vec_push(&ctxt->nums, n); } - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } @@ -368,23 +545,23 @@ BclNumber bcl_num_create(void) { BclError e = BCL_ERROR_NONE; - BcNum n; + BclNum n; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - bc_num_init(&n, BC_NUM_DEF_SIZE); + bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); err: - BC_FUNC_FOOTER_UNLOCK(e); - BC_MAYBE_SETUP(ctxt, e, n, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, n, idx); return idx; } @@ -396,61 +573,68 @@ err: * @param num The number to destroy. */ static void -bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum* restrict num) +bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num) { - BC_SIG_ASSERT_LOCKED; + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); - assert(num != NULL && num->num != NULL); + BCL_CLEAR_GEN(n); bcl_num_destruct(num); bc_vec_push(&ctxt->free_nums, &n); + +#if BC_ENABLE_MEMCHECK + num->n.num = NULL; +#endif // BC_ENABLE_MEMCHECK } void bcl_num_free(BclNumber n) { - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ASSERT(ctxt); + BC_CHECK_CTXT_ASSERT(vm, ctxt); - BC_SIG_LOCK; + BCL_CHECK_NUM_VALID(ctxt, n); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - num = BC_NUM(ctxt, n); + num = BCL_NUM(ctxt, n); bcl_num_dtor(ctxt, n, num); - - BC_SIG_UNLOCK; } BclError bcl_copy(BclNumber d, BclNumber s) { BclError e = BCL_ERROR_NONE; - BcNum* dest; - BcNum* src; + BclNum* dest; + BclNum* src; BclContext ctxt; + BcVm* vm = bcl_getspecific(); + + BC_CHECK_CTXT_ERR(vm, ctxt); - BC_CHECK_CTXT_ERR(ctxt); + BCL_CHECK_NUM_VALID(ctxt, d); + BCL_CHECK_NUM_VALID(ctxt, s); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len); + assert(BCL_NO_GEN(d) < ctxt->nums.len); + assert(BCL_NO_GEN(s) < ctxt->nums.len); - dest = BC_NUM(ctxt, d); - src = BC_NUM(ctxt, s); + dest = BCL_NUM(ctxt, d); + src = BCL_NUM(ctxt, s); assert(dest != NULL && src != NULL); - assert(dest->num != NULL && src->num != NULL); + assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL); - bc_num_copy(dest, src); + bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src)); err: - BC_FUNC_FOOTER_UNLOCK(e); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); return e; } @@ -459,31 +643,33 @@ BclNumber bcl_dup(BclNumber s) { BclError e = BCL_ERROR_NONE; - BcNum *src, dest; + BclNum *src, dest; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BCL_CHECK_NUM_VALID(ctxt, s); - bc_vec_grow(&ctxt->nums, 1); + BC_FUNC_HEADER(vm, err); - assert(s.i < ctxt->nums.len); + BCL_GROW_NUMS(ctxt); - src = BC_NUM(ctxt, s); + assert(BCL_NO_GEN(s) < ctxt->nums.len); - assert(src != NULL && src->num != NULL); + src = BCL_NUM(ctxt, s); + + assert(src != NULL && BCL_NUM_NUM(src) != NULL); // Copy the number. - bc_num_clear(&dest); - bc_num_createCopy(&dest, src); + bc_num_clear(BCL_NUM_NUM(&dest)); + bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src)); err: - BC_FUNC_FOOTER_UNLOCK(e); - BC_MAYBE_SETUP(ctxt, e, dest, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, dest, idx); return idx; } @@ -491,94 +677,110 @@ err: void bcl_num_destruct(void* num) { - BcNum* n = (BcNum*) num; + BclNum* n = (BclNum*) num; assert(n != NULL); - if (n->num == NULL) return; + if (BCL_NUM_ARRAY(n) == NULL) return; - bc_num_free(num); - bc_num_clear(num); + bc_num_free(BCL_NUM_NUM(n)); + bc_num_clear(BCL_NUM_NUM(n)); } bool bcl_num_neg(BclNumber n) { - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ASSERT(ctxt); + BC_CHECK_CTXT_ASSERT(vm, ctxt); - assert(n.i < ctxt->nums.len); + BCL_CHECK_NUM_VALID(ctxt, n); - num = BC_NUM(ctxt, n); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - assert(num != NULL && num->num != NULL); + num = BCL_NUM(ctxt, n); - return BC_NUM_NEG(num) != 0; + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); + + return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0; } void bcl_num_setNeg(BclNumber n, bool neg) { - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); + + BC_CHECK_CTXT_ASSERT(vm, ctxt); - BC_CHECK_CTXT_ASSERT(ctxt); + BCL_CHECK_NUM_VALID(ctxt, n); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - num = BC_NUM(ctxt, n); + num = BCL_NUM(ctxt, n); - assert(num != NULL && num->num != NULL); + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); - num->rdx = BC_NUM_NEG_VAL(num, neg); + BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg); } size_t bcl_num_scale(BclNumber n) { - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ASSERT(ctxt); + BC_CHECK_CTXT_ASSERT(vm, ctxt); - assert(n.i < ctxt->nums.len); + BCL_CHECK_NUM_VALID(ctxt, n); - num = BC_NUM(ctxt, n); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - assert(num != NULL && num->num != NULL); + num = BCL_NUM(ctxt, n); - return bc_num_scale(num); + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); + + return bc_num_scale(BCL_NUM_NUM(num)); } BclError bcl_num_setScale(BclNumber n, size_t scale) { BclError e = BCL_ERROR_NONE; - BcNum* nptr; + BclNum* nptr; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ERR(ctxt); + BC_CHECK_CTXT_ERR(vm, ctxt); BC_CHECK_NUM_ERR(ctxt, n); - BC_FUNC_HEADER(err); + BCL_CHECK_NUM_VALID(ctxt, n); + + BC_FUNC_HEADER(vm, err); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - nptr = BC_NUM(ctxt, n); + nptr = BCL_NUM(ctxt, n); - assert(nptr != NULL && nptr->num != NULL); + assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL); - if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale); - else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale); + if (scale > BCL_NUM_NUM(nptr)->scale) + { + bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale); + } + else if (scale < BCL_NUM_NUM(nptr)->scale) + { + bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale); + } err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); return e; } @@ -586,420 +788,542 @@ err: size_t bcl_num_len(BclNumber n) { - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); + + BC_CHECK_CTXT_ASSERT(vm, ctxt); - BC_CHECK_CTXT_ASSERT(ctxt); + BCL_CHECK_NUM_VALID(ctxt, n); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - num = BC_NUM(ctxt, n); + num = BCL_NUM(ctxt, n); - assert(num != NULL && num->num != NULL); + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); - return bc_num_len(num); + return bc_num_len(BCL_NUM_NUM(num)); } -BclError -bcl_bigdig(BclNumber n, BclBigDig* result) +static BclError +bcl_bigdig_helper(BclNumber n, BclBigDig* result, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* num; + BclNum* num; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ERR(ctxt); + BC_CHECK_CTXT_ERR(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BCL_CHECK_NUM_VALID(ctxt, n); - assert(n.i < ctxt->nums.len); + BC_FUNC_HEADER(vm, err); + + assert(BCL_NO_GEN(n) < ctxt->nums.len); assert(result != NULL); - num = BC_NUM(ctxt, n); + num = BCL_NUM(ctxt, n); - assert(num != NULL && num->num != NULL); + assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); - *result = bc_num_bigdig(num); + *result = bc_num_bigdig(BCL_NUM_NUM(num)); err: - bcl_num_dtor(ctxt, n, num); - BC_FUNC_FOOTER_UNLOCK(e); - assert(!vm.running && !vm.sig && !vm.sig_lock); + if (destruct) + { + bcl_num_dtor(ctxt, n, num); + } + + BC_FUNC_FOOTER(vm, e); return e; } +BclError +bcl_bigdig(BclNumber n, BclBigDig* result) +{ + return bcl_bigdig_helper(n, result, true); +} + +BclError +bcl_bigdig_keep(BclNumber n, BclBigDig* result) +{ + return bcl_bigdig_helper(n, result, false); +} + BclNumber bcl_bigdig2num(BclBigDig val) { BclError e = BCL_ERROR_NONE; - BcNum n; + BclNum n; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - bc_num_createFromBigdig(&n, val); + bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val); err: - BC_FUNC_FOOTER_UNLOCK(e); - BC_MAYBE_SETUP(ctxt, e, n, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, n, idx); return idx; } /** * Sets up and executes a binary operator operation. - * @param a The first operand. - * @param b The second operand. - * @param op The operation. - * @param req The function to get the size of the result for preallocation. - * @return The result of the operation. + * @param a The first operand. + * @param b The second operand. + * @param op The operation. + * @param req The function to get the size of the result for + * preallocation. + * @param destruct True if the parameters should be consumed, false otherwise. + * @return The result of the operation. */ static BclNumber bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op, - const BcNumBinaryOpReq req) + const BcNumBinaryOpReq req, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* aptr; - BcNum* bptr; - BcNum c; + BclNum* aptr; + BclNum* bptr; + BclNum c; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); BC_CHECK_NUM(ctxt, a); BC_CHECK_NUM(ctxt, b); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); - bptr = BC_NUM(ctxt, b); + aptr = BCL_NUM(ctxt, a); + bptr = BCL_NUM(ctxt, b); assert(aptr != NULL && bptr != NULL); - assert(aptr->num != NULL && bptr->num != NULL); + assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL); // Clear and initialize the result. - bc_num_clear(&c); - bc_num_init(&c, req(aptr, bptr, ctxt->scale)); - - BC_SIG_UNLOCK; + bc_num_clear(BCL_NUM_NUM_NP(c)); + bc_num_init(BCL_NUM_NUM_NP(c), + req(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale)); - op(aptr, bptr, &c, ctxt->scale); + op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale); err: - BC_SIG_MAYLOCK; - - // Eat the operands. - bcl_num_dtor(ctxt, a, aptr); - if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); + if (destruct) + { + // Eat the operands. + bcl_num_dtor(ctxt, a, aptr); + if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); + } - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); BC_MAYBE_SETUP(ctxt, e, c, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } BclNumber bcl_add(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_add, bc_num_addReq); + return bcl_binary(a, b, bc_num_add, bc_num_addReq, true); +} + +BclNumber +bcl_add_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_add, bc_num_addReq, false); } BclNumber bcl_sub(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_sub, bc_num_addReq); + return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true); +} + +BclNumber +bcl_sub_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false); } BclNumber bcl_mul(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_mul, bc_num_mulReq); + return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true); +} + +BclNumber +bcl_mul_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false); } BclNumber bcl_div(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_div, bc_num_divReq); + return bcl_binary(a, b, bc_num_div, bc_num_divReq, true); +} + +BclNumber +bcl_div_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_div, bc_num_divReq, false); } BclNumber bcl_mod(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_mod, bc_num_divReq); + return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true); +} + +BclNumber +bcl_mod_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false); } BclNumber bcl_pow(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_pow, bc_num_powReq); + return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true); +} + +BclNumber +bcl_pow_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false); } BclNumber bcl_lshift(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq); + return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true); +} + +BclNumber +bcl_lshift_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false); } BclNumber bcl_rshift(BclNumber a, BclNumber b) { - return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq); + return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true); } BclNumber -bcl_sqrt(BclNumber a) +bcl_rshift_keep(BclNumber a, BclNumber b) +{ + return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false); +} + +static BclNumber +bcl_sqrt_helper(BclNumber a, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* aptr; - BcNum b; + BclNum* aptr; + BclNum b; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); BC_CHECK_NUM(ctxt, a); - BC_FUNC_HEADER(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - assert(a.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); + aptr = BCL_NUM(ctxt, a); - bc_num_sqrt(aptr, &b, ctxt->scale); + bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale); err: - BC_SIG_MAYLOCK; - bcl_num_dtor(ctxt, a, aptr); - BC_FUNC_FOOTER(e); - BC_MAYBE_SETUP(ctxt, e, b, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + if (destruct) + { + bcl_num_dtor(ctxt, a, aptr); + } + + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, b, idx); return idx; } -BclError -bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d) +BclNumber +bcl_sqrt(BclNumber a) +{ + return bcl_sqrt_helper(a, true); +} + +BclNumber +bcl_sqrt_keep(BclNumber a) +{ + return bcl_sqrt_helper(a, false); +} + +static BclError +bcl_divmod_helper(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d, + bool destruct) { BclError e = BCL_ERROR_NONE; size_t req; - BcNum* aptr; - BcNum* bptr; - BcNum cnum, dnum; + BclNum* aptr; + BclNum* bptr; + BclNum cnum, dnum; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ERR(ctxt); + BC_CHECK_CTXT_ERR(vm, ctxt); BC_CHECK_NUM_ERR(ctxt, a); BC_CHECK_NUM_ERR(ctxt, b); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 2); + BCL_GROW_NUMS(ctxt); assert(c != NULL && d != NULL); - aptr = BC_NUM(ctxt, a); - bptr = BC_NUM(ctxt, b); + aptr = BCL_NUM(ctxt, a); + bptr = BCL_NUM(ctxt, b); assert(aptr != NULL && bptr != NULL); - assert(aptr->num != NULL && bptr->num != NULL); + assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL); - bc_num_clear(&cnum); - bc_num_clear(&dnum); + bc_num_clear(BCL_NUM_NUM_NP(cnum)); + bc_num_clear(BCL_NUM_NUM_NP(dnum)); - req = bc_num_divReq(aptr, bptr, ctxt->scale); + req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale); // Initialize the numbers. - bc_num_init(&cnum, req); - BC_UNSETJMP; - BC_SETJMP_LOCKED(err); - bc_num_init(&dnum, req); - - BC_SIG_UNLOCK; + bc_num_init(BCL_NUM_NUM_NP(cnum), req); + BC_UNSETJMP(vm); + BC_SETJMP(vm, err); + bc_num_init(BCL_NUM_NUM_NP(dnum), req); - bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale); + bc_num_divmod(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(cnum), + BCL_NUM_NUM_NP(dnum), ctxt->scale); err: - BC_SIG_MAYLOCK; - // Eat the operands. - bcl_num_dtor(ctxt, a, aptr); - if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); + if (destruct) + { + // Eat the operands. + bcl_num_dtor(ctxt, a, aptr); + if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); + } // If there was an error... - if (BC_ERR(vm.err)) + if (BC_ERR(vm->err)) { // Free the results. - if (cnum.num != NULL) bc_num_free(&cnum); - if (dnum.num != NULL) bc_num_free(&dnum); + if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&cnum); + if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&dnum); // Make sure the return values are invalid. c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM; d->i = c->i; - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); } else { - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); // Insert the results into the context. *c = bcl_num_insert(ctxt, &cnum); *d = bcl_num_insert(ctxt, &dnum); } - assert(!vm.running && !vm.sig && !vm.sig_lock); - return e; } -BclNumber -bcl_modexp(BclNumber a, BclNumber b, BclNumber c) +BclError +bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d) +{ + return bcl_divmod_helper(a, b, c, d, true); +} + +BclError +bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d) +{ + return bcl_divmod_helper(a, b, c, d, false); +} + +static BclNumber +bcl_modexp_helper(BclNumber a, BclNumber b, BclNumber c, bool destruct) { BclError e = BCL_ERROR_NONE; size_t req; - BcNum* aptr; - BcNum* bptr; - BcNum* cptr; - BcNum d; + BclNum* aptr; + BclNum* bptr; + BclNum* cptr; + BclNum d; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); BC_CHECK_NUM(ctxt, a); BC_CHECK_NUM(ctxt, b); BC_CHECK_NUM(ctxt, c); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); - assert(c.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); + assert(BCL_NO_GEN(c) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); - bptr = BC_NUM(ctxt, b); - cptr = BC_NUM(ctxt, c); + aptr = BCL_NUM(ctxt, a); + bptr = BCL_NUM(ctxt, b); + cptr = BCL_NUM(ctxt, c); assert(aptr != NULL && bptr != NULL && cptr != NULL); - assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL); + assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr) != NULL && + BCL_NUM_NUM(cptr) != NULL); // Prepare the result. - bc_num_clear(&d); + bc_num_clear(BCL_NUM_NUM_NP(d)); - req = bc_num_divReq(aptr, cptr, 0); + req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0); // Initialize the result. - bc_num_init(&d, req); + bc_num_init(BCL_NUM_NUM_NP(d), req); - BC_SIG_UNLOCK; - - bc_num_modexp(aptr, bptr, cptr, &d); + bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr), + BCL_NUM_NUM_NP(d)); err: - BC_SIG_MAYLOCK; - // Eat the operands. - bcl_num_dtor(ctxt, a, aptr); - if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); - if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); + if (destruct) + { + // Eat the operands. + bcl_num_dtor(ctxt, a, aptr); + if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); + if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); + } - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); BC_MAYBE_SETUP(ctxt, e, d, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } +BclNumber +bcl_modexp(BclNumber a, BclNumber b, BclNumber c) +{ + return bcl_modexp_helper(a, b, c, true); +} + +BclNumber +bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c) +{ + return bcl_modexp_helper(a, b, c, false); +} + ssize_t bcl_cmp(BclNumber a, BclNumber b) { - BcNum* aptr; - BcNum* bptr; + BclNum* aptr; + BclNum* bptr; BclContext ctxt; + BcVm* vm = bcl_getspecific(); + + BC_CHECK_CTXT_ASSERT(vm, ctxt); - BC_CHECK_CTXT_ASSERT(ctxt); + BCL_CHECK_NUM_VALID(ctxt, a); + BCL_CHECK_NUM_VALID(ctxt, b); - assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); - bptr = BC_NUM(ctxt, b); + aptr = BCL_NUM(ctxt, a); + bptr = BCL_NUM(ctxt, b); assert(aptr != NULL && bptr != NULL); - assert(aptr->num != NULL && bptr->num != NULL); + assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr)); - return bc_num_cmp(aptr, bptr); + return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr)); } void bcl_zero(BclNumber n) { - BcNum* nptr; + BclNum* nptr; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ASSERT(ctxt); + BC_CHECK_CTXT_ASSERT(vm, ctxt); - assert(n.i < ctxt->nums.len); + BCL_CHECK_NUM_VALID(ctxt, n); - nptr = BC_NUM(ctxt, n); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - assert(nptr != NULL && nptr->num != NULL); + nptr = BCL_NUM(ctxt, n); - bc_num_zero(nptr); + assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); + + bc_num_zero(BCL_NUM_NUM(nptr)); } void bcl_one(BclNumber n) { - BcNum* nptr; + BclNum* nptr; BclContext ctxt; + BcVm* vm = bcl_getspecific(); + + BC_CHECK_CTXT_ASSERT(vm, ctxt); - BC_CHECK_CTXT_ASSERT(ctxt); + BCL_CHECK_NUM_VALID(ctxt, n); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - nptr = BC_NUM(ctxt, n); + nptr = BCL_NUM(ctxt, n); - assert(nptr != NULL && nptr->num != NULL); + assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); - bc_num_one(nptr); + bc_num_one(BCL_NUM_NUM(nptr)); } BclNumber bcl_parse(const char* restrict val) { BclError e = BCL_ERROR_NONE; - BcNum n; + BclNum n; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); bool neg; - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); assert(val != NULL); @@ -1011,119 +1335,146 @@ bcl_parse(const char* restrict val) if (!bc_num_strValid(val)) { - vm.err = BCL_ERROR_PARSE_INVALID_STR; + vm->err = BCL_ERROR_PARSE_INVALID_STR; goto err; } // Clear and initialize the number. - bc_num_clear(&n); - bc_num_init(&n, BC_NUM_DEF_SIZE); - - BC_SIG_UNLOCK; + bc_num_clear(BCL_NUM_NUM_NP(n)); + bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); - bc_num_parse(&n, val, (BcBigDig) ctxt->ibase); + bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase); // Set the negative. +#if BC_ENABLE_MEMCHECK + n.n.rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM_NP(n), neg); +#else // BC_ENABLE_MEMCHECK n.rdx = BC_NUM_NEG_VAL_NP(n, neg); +#endif // BC_ENABLE_MEMCHECK err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); - BC_MAYBE_SETUP(ctxt, e, n, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, n, idx); return idx; } -char* -bcl_string(BclNumber n) +static char* +bcl_string_helper(BclNumber n, bool destruct) { - BcNum* nptr; + BclNum* nptr; char* str = NULL; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ASSERT(ctxt); + BC_CHECK_CTXT_ASSERT(vm, ctxt); - if (BC_ERR(n.i >= ctxt->nums.len)) return str; + BCL_CHECK_NUM_VALID(ctxt, n); - BC_FUNC_HEADER(err); + if (BC_ERR(BCL_NO_GEN(n) >= ctxt->nums.len)) return str; - assert(n.i < ctxt->nums.len); + BC_FUNC_HEADER(vm, err); - nptr = BC_NUM(ctxt, n); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - assert(nptr != NULL && nptr->num != NULL); + nptr = BCL_NUM(ctxt, n); + + assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); // Clear the buffer. - bc_vec_popAll(&vm.out); + bc_vec_popAll(&vm->out); // Print to the buffer. - bc_num_print(nptr, (BcBigDig) ctxt->obase, false); - bc_vec_pushByte(&vm.out, '\0'); - - BC_SIG_LOCK; + bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false); + bc_vec_pushByte(&vm->out, '\0'); // Just dup the string; the caller is responsible for it. - str = bc_vm_strdup(vm.out.v); + str = bc_vm_strdup(vm->out.v); err: - // Eat the operand. - bcl_num_dtor(ctxt, n, nptr); - - BC_FUNC_FOOTER_NO_ERR; + if (destruct) + { + // Eat the operand. + bcl_num_dtor(ctxt, n, nptr); + } - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER_NO_ERR(vm); return str; } -BclNumber -bcl_irand(BclNumber a) +char* +bcl_string(BclNumber n) +{ + return bcl_string_helper(n, true); +} + +char* +bcl_string_keep(BclNumber n) +{ + return bcl_string_helper(n, false); +} + +#if BC_ENABLE_EXTRA_MATH + +static BclNumber +bcl_irand_helper(BclNumber a, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* aptr; - BcNum b; + BclNum* aptr; + BclNum b; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); BC_CHECK_NUM(ctxt, a); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - assert(a.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); + aptr = BCL_NUM(ctxt, a); - assert(aptr != NULL && aptr->num != NULL); + assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL); // Clear and initialize the result. - bc_num_clear(&b); - bc_num_init(&b, BC_NUM_DEF_SIZE); - - BC_SIG_UNLOCK; + bc_num_clear(BCL_NUM_NUM_NP(b)); + bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE); - bc_num_irand(aptr, &b, &vm.rng); + bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng); err: - BC_SIG_MAYLOCK; - // Eat the operand. - bcl_num_dtor(ctxt, a, aptr); + if (destruct) + { + // Eat the operand. + bcl_num_dtor(ctxt, a, aptr); + } - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); BC_MAYBE_SETUP(ctxt, e, b, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } +BclNumber +bcl_irand(BclNumber a) +{ + return bcl_irand_helper(a, true); +} + +BclNumber +bcl_irand_keep(BclNumber a) +{ + return bcl_irand_helper(a, false); +} + /** * Helps bcl_frand(). This is separate because the error handling is easier that * way. It is also easier to do ifrand that way. @@ -1136,6 +1487,7 @@ bcl_frandHelper(BcNum* restrict b, size_t places) BcNum exp, pow, ten; BcDig exp_digs[BC_NUM_BIGDIG_LOG10]; BcDig ten_digs[BC_NUM_BIGDIG_LOG10]; + BcVm* vm = bcl_getspecific(); // Set up temporaries. bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10); @@ -1149,58 +1501,50 @@ bcl_frandHelper(BcNum* restrict b, size_t places) // Clear the temporary that might need to grow. bc_num_clear(&pow); - BC_SIG_LOCK; - // Initialize the temporary that might need to grow. bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0)); - BC_SETJMP_LOCKED(err); - - BC_SIG_UNLOCK; + BC_SETJMP(vm, err); // Generate the number. bc_num_pow(&ten, &exp, &pow, 0); - bc_num_irand(&pow, b, &vm.rng); + bc_num_irand(&pow, b, &vm->rng); // Make the number entirely fraction. bc_num_shiftRight(b, places); err: - BC_SIG_MAYLOCK; + bc_num_free(&pow); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } BclNumber bcl_frand(size_t places) { BclError e = BCL_ERROR_NONE; - BcNum n; + BclNum n; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); // Clear and initialize the number. - bc_num_clear(&n); - bc_num_init(&n, BC_NUM_DEF_SIZE); + bc_num_clear(BCL_NUM_NUM_NP(n)); + bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); - BC_SIG_UNLOCK; - - bcl_frandHelper(&n, places); + bcl_frandHelper(BCL_NUM_NUM_NP(n), places); err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); BC_MAYBE_SETUP(ctxt, e, n, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } @@ -1215,114 +1559,140 @@ static void bcl_ifrandHelper(BcNum* restrict a, BcNum* restrict b, size_t places) { BcNum ir, fr; + BcVm* vm = bcl_getspecific(); // Clear the integer and fractional numbers. bc_num_clear(&ir); bc_num_clear(&fr); - BC_SIG_LOCK; - // Initialize the integer and fractional numbers. bc_num_init(&ir, BC_NUM_DEF_SIZE); bc_num_init(&fr, BC_NUM_DEF_SIZE); - BC_SETJMP_LOCKED(err); - - BC_SIG_UNLOCK; + BC_SETJMP(vm, err); - bc_num_irand(a, &ir, &vm.rng); + bc_num_irand(a, &ir, &vm->rng); bcl_frandHelper(&fr, places); bc_num_add(&ir, &fr, b, 0); err: - BC_SIG_MAYLOCK; + bc_num_free(&fr); bc_num_free(&ir); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); } -BclNumber -bcl_ifrand(BclNumber a, size_t places) +static BclNumber +bcl_ifrand_helper(BclNumber a, size_t places, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* aptr; - BcNum b; + BclNum* aptr; + BclNum b; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); BC_CHECK_NUM(ctxt, a); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); - bc_vec_grow(&ctxt->nums, 1); + BCL_GROW_NUMS(ctxt); - assert(a.i < ctxt->nums.len); + assert(BCL_NO_GEN(a) < ctxt->nums.len); - aptr = BC_NUM(ctxt, a); + aptr = BCL_NUM(ctxt, a); - assert(aptr != NULL && aptr->num != NULL); + assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL); // Clear and initialize the number. - bc_num_clear(&b); - bc_num_init(&b, BC_NUM_DEF_SIZE); - - BC_SIG_UNLOCK; + bc_num_clear(BCL_NUM_NUM_NP(b)); + bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE); - bcl_ifrandHelper(aptr, &b, places); + bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places); err: - BC_SIG_MAYLOCK; - // Eat the oprand. - bcl_num_dtor(ctxt, a, aptr); + if (destruct) + { + // Eat the oprand. + bcl_num_dtor(ctxt, a, aptr); + } - BC_FUNC_FOOTER(e); + BC_FUNC_FOOTER(vm, e); BC_MAYBE_SETUP(ctxt, e, b, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); - return idx; } -BclError -bcl_rand_seedWithNum(BclNumber n) +BclNumber +bcl_ifrand(BclNumber a, size_t places) +{ + return bcl_ifrand_helper(a, places, true); +} + +BclNumber +bcl_ifrand_keep(BclNumber a, size_t places) +{ + return bcl_ifrand_helper(a, places, false); +} + +static BclError +bcl_rand_seedWithNum_helper(BclNumber n, bool destruct) { BclError e = BCL_ERROR_NONE; - BcNum* nptr; + BclNum* nptr; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT_ERR(ctxt); + BC_CHECK_CTXT_ERR(vm, ctxt); BC_CHECK_NUM_ERR(ctxt, n); - BC_FUNC_HEADER(err); + BC_FUNC_HEADER(vm, err); - assert(n.i < ctxt->nums.len); + assert(BCL_NO_GEN(n) < ctxt->nums.len); - nptr = BC_NUM(ctxt, n); + nptr = BCL_NUM(ctxt, n); - assert(nptr != NULL && nptr->num != NULL); + assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); - bc_num_rng(nptr, &vm.rng); + bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng); err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); - assert(!vm.running && !vm.sig && !vm.sig_lock); + if (destruct) + { + // Eat the oprand. + bcl_num_dtor(ctxt, n, nptr); + } + + BC_FUNC_FOOTER(vm, e); return e; } BclError +bcl_rand_seedWithNum(BclNumber n) +{ + return bcl_rand_seedWithNum_helper(n, true); +} + +BclError +bcl_rand_seedWithNum_keep(BclNumber n) +{ + return bcl_rand_seedWithNum_helper(n, false); +} + +BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) { BclError e = BCL_ERROR_NONE; size_t i; ulong vals[BCL_SEED_ULONGS]; + BcVm* vm = bcl_getspecific(); - BC_FUNC_HEADER(err); + BC_FUNC_HEADER(vm, err); // Fill the array. for (i = 0; i < BCL_SEED_SIZE; ++i) @@ -1332,46 +1702,46 @@ bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) vals[i / sizeof(long)] |= val; } - bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]); + bc_rand_seed(&vm->rng, vals[0], vals[1], vals[2], vals[3]); err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); + + BC_FUNC_FOOTER(vm, e); + return e; } void bcl_rand_reseed(void) { - bc_rand_srand(bc_vec_top(&vm.rng.v)); + BcVm* vm = bcl_getspecific(); + + bc_rand_srand(bc_vec_top(&vm->rng.v)); } BclNumber bcl_rand_seed2num(void) { BclError e = BCL_ERROR_NONE; - BcNum n; + BclNum n; BclNumber idx; BclContext ctxt; + BcVm* vm = bcl_getspecific(); - BC_CHECK_CTXT(ctxt); + BC_CHECK_CTXT(vm, ctxt); - BC_FUNC_HEADER_LOCK(err); + BC_FUNC_HEADER(vm, err); // Clear and initialize the number. - bc_num_clear(&n); - bc_num_init(&n, BC_NUM_DEF_SIZE); + bc_num_clear(BCL_NUM_NUM_NP(n)); + bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); - BC_SIG_UNLOCK; - - bc_num_createFromRNG(&n, &vm.rng); + bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng); err: - BC_SIG_MAYLOCK; - BC_FUNC_FOOTER(e); - BC_MAYBE_SETUP(ctxt, e, n, idx); - assert(!vm.running && !vm.sig && !vm.sig_lock); + BC_FUNC_FOOTER(vm, e); + BC_MAYBE_SETUP(ctxt, e, n, idx); return idx; } @@ -1379,14 +1749,20 @@ err: BclRandInt bcl_rand_int(void) { - return (BclRandInt) bc_rand_int(&vm.rng); + BcVm* vm = bcl_getspecific(); + + return (BclRandInt) bc_rand_int(&vm->rng); } BclRandInt bcl_rand_bounded(BclRandInt bound) { + BcVm* vm = bcl_getspecific(); + if (bound <= 1) return 0; - return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound); + return (BclRandInt) bc_rand_bounded(&vm->rng, (BcRand) bound); } +#endif // BC_ENABLE_EXTRA_MATH + #endif // BC_ENABLE_LIBRARY |