aboutsummaryrefslogtreecommitdiff
path: root/contrib/bc/src/library.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bc/src/library.c')
-rw-r--r--contrib/bc/src/library.c1276
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