Add the first rough draft of memcheck stuff in bcl
This is to help me catch bugs in client code while using bcl.
Signed-off-by: Gavin D. Howard <gavin@gavinhoward.com>
diff --git a/include/library.h b/include/library.h
index df94f1f..fa1d7b7 100644
--- a/include/library.h
+++ b/include/library.h
@@ -47,6 +47,147 @@
#include <num.h>
#include <vm.h>
+#if BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for Valgrind builds. This is to add a generation index for error
+ * checking.
+ */
+typedef struct BclNum
+{
+ /// The number.
+ BcNum n;
+
+ /// The generation index.
+ size_t gen_idx;
+
+} BclNum;
+
+/**
+ * Clears the generation byte in a BclNumber and returns the value.
+ * @param n The BclNumber.
+ * @return The value of the index.
+ */
+#define BCL_NO_GEN(n) \
+ ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)))
+
+/**
+ * Gets the generation index in a BclNumber.
+ * @param n The BclNumber.
+ * @return The generation index.
+ */
+#define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT))
+
+/**
+ * Turns a BclNumber into a BcNum.
+ * @param c The context.
+ * @param n The BclNumber.
+ */
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n)))
+
+/**
+ * Clears the generation index top byte in the BclNumber.
+ * @param n The BclNumber.
+ */
+#define BCL_CLEAR_GEN(n) \
+ do \
+ { \
+ (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \
+ } \
+ while (0)
+
+#define BCL_CHECK_NUM_GEN(c, bn) \
+ do \
+ { \
+ size_t gen_ = BCL_GET_GEN(bn); \
+ BclNum* ptr_ = BCL_NUM(c, bn); \
+ if (BCL_NUM_ARRAY(ptr_) == NULL) \
+ { \
+ bcl_nonexistentNum(); \
+ } \
+ if (gen_ != ptr_->gen_idx) \
+ { \
+ bcl_invalidGeneration(); \
+ } \
+ } \
+ while (0)
+
+
+#define BCL_CHECK_NUM_VALID(c, bn) \
+ do \
+ { \
+ size_t idx_ = BCL_NO_GEN(bn); \
+ if ((c)->nums.len <= idx_) \
+ { \
+ bcl_numIdxOutOfRange(); \
+ } \
+ BCL_CHECK_NUM_GEN(c, bn); \
+ } \
+ while (0)
+
+/**
+ * Returns the limb array of the number.
+ * @param bn The number.
+ * @return The limb array.
+ */
+#define BCL_NUM_ARRAY(bn) ((bn)->n.num)
+
+/**
+ * Returns the limb array of the number for a non-pointer.
+ * @param bn The number.
+ * @return The limb array.
+ */
+#define BCL_NUM_ARRAY_NP(bn) ((bn).n.num)
+
+/**
+ * Returns the BcNum pointer.
+ * @param bn The number.
+ * @return The BcNum pointer.
+ */
+#define BCL_NUM_NUM(bn) (&(bn)->n)
+
+/**
+ * Returns the BcNum pointer for a non-pointer.
+ * @param bn The number.
+ * @return The BcNum pointer.
+ */
+#define BCL_NUM_NUM_NP(bn) (&(bn).n)
+
+// These functions only abort. They exist to give developers some idea of what
+// went wrong when bugs are found, if they look at the Valgrind stack trace.
+
+BC_NORETURN void
+bcl_invalidGeneration(void);
+
+BC_NORETURN void
+bcl_nonexistentNum(void);
+
+BC_NORETURN void
+bcl_numIdxOutOfRange(void);
+
+#else // BC_ENABLE_MEMCHECK
+
+/**
+ * A typedef for non-Valgrind builds.
+ */
+typedef BcNum BclNum;
+
+#define BCL_NO_GEN(n) (n)
+#define BCL_GET_GEN(n) (n)
+#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i))
+#define BCL_CLEAR_GEN(n) ((void) (n))
+
+#define BCL_CHECK_NUM_GEN(c, bn)
+#define BCL_CHECK_NUM_VALID(c, n)
+
+#define BCL_NUM_ARRAY(n) ((bn)->num)
+#define BCL_NUM_ARRAY_NP(bn) ((bn).num)
+
+#define BCL_NUM_NUM(bn) (bn)
+#define BCL_NUM_NUM_NP(bn) (&(bn))
+
+#endif // BC_ENABLE_MEMCHECK
+
/**
* A header that sets a jump.
* @param vm The thread data.
@@ -88,19 +229,19 @@
* idx.
* @param c The context.
* @param e The error.
- * @param n The number.
+ * @param bn The number.
* @param idx The idx to set as the return value.
*/
-#define BC_MAYBE_SETUP(c, e, n, idx) \
- do \
- { \
- if (BC_ERR((e) != BCL_ERROR_NONE)) \
- { \
- if ((n).num != NULL) bc_num_free(&(n)); \
- idx.i = 0 - (size_t) (e); \
- } \
- else idx = bcl_num_insert(c, &(n)); \
- } \
+#define BC_MAYBE_SETUP(c, e, bn, idx) \
+ do \
+ { \
+ if (BC_ERR((e) != BCL_ERROR_NONE)) \
+ { \
+ if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \
+ idx.i = 0 - (size_t) (e); \
+ } \
+ else idx = bcl_num_insert(c, &(bn)); \
+ } \
while (0)
/**
@@ -162,11 +303,12 @@
if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
else \
{ \
- BclNumber n_num; \
- n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
- return n_num; \
+ BclNumber n_num_; \
+ n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \
+ return n_num_; \
} \
} \
+ BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
@@ -189,26 +331,24 @@
} \
else return BCL_ERROR_INVALID_NUM; \
} \
+ BCL_CHECK_NUM_GEN(c, n); \
} \
while (0)
//clang-format on
/**
- * Turns a BclNumber into a BcNum.
+ * Grows the context's nums array if necessary.
* @param c The context.
- * @param n The BclNumber.
*/
-#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
-
-#define BC_GROW_NUMS(ctxt) \
- do \
- { \
- if ((ctxt)->free_nums.len == 0) \
- { \
- bc_vec_grow(&((ctxt)->nums), 1); \
- } \
- } \
+#define BCL_GROW_NUMS(c) \
+ do \
+ { \
+ if ((c)->free_nums.len == 0) \
+ { \
+ bc_vec_grow(&((c)->nums), 1); \
+ } \
+ } \
while (0)
/**
diff --git a/src/library.c b/src/library.c
index 47e114e..71f3554 100644
--- a/src/library.c
+++ b/src/library.c
@@ -60,6 +60,28 @@
// 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.
+#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;
@@ -364,7 +386,7 @@
// 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;
@@ -446,6 +468,10 @@
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.
if (n.i >= ctxt->nums.len)
@@ -463,14 +489,14 @@
* @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));
@@ -478,10 +504,28 @@
// 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
{
+#if BC_ENABLE_MEMCHECK
+ n->gen_idx = 0;
+#endif // BC_ENABLE_MEMCHECK
+
// Just push the number onto the vector.
idx.i = ctxt->nums.len;
bc_vec_push(&ctxt->nums, n);
@@ -494,7 +538,7 @@
bcl_num_create(void)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -503,9 +547,9 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ 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:
@@ -522,26 +566,34 @@
* @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)
{
- assert(num != NULL && num->num != NULL);
+ assert(num != NULL && BCL_NUM_ARRAY(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(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);
+
+ num = BCL_NUM(ctxt, n);
bcl_num_dtor(ctxt, n, num);
}
@@ -550,24 +602,28 @@
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);
+ BCL_CHECK_NUM_VALID(ctxt, d);
+ BCL_CHECK_NUM_VALID(ctxt, s);
+
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:
@@ -580,26 +636,28 @@
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(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, s);
+
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
- assert(s.i < ctxt->nums.len);
+ assert(BCL_NO_GEN(s) < ctxt->nums.len);
- src = BC_NUM(ctxt, s);
+ src = BCL_NUM(ctxt, s);
- assert(src != NULL && src->num != NULL);
+ 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:
@@ -612,75 +670,81 @@
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(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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_NEG(num) != 0;
+ 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);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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_scale(num);
+ 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();
@@ -688,16 +752,24 @@
BC_CHECK_NUM_ERR(ctxt, n);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
BC_FUNC_HEADER(vm, err);
assert(n.i < 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:
@@ -709,41 +781,45 @@
size_t
bcl_num_len(BclNumber n)
{
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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)
{
BclError e = BCL_ERROR_NONE;
- BcNum* num;
+ BclNum* num;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ERR(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
BC_FUNC_HEADER(vm, err);
assert(n.i < 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:
@@ -757,7 +833,7 @@
bcl_bigdig2num(BclBigDig val)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -766,9 +842,9 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
- bc_num_createFromBigdig(&n, val);
+ bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val);
err:
@@ -791,9 +867,9 @@
const BcNumBinaryOpReq req)
{
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();
@@ -805,21 +881,22 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(a.i < ctxt->nums.len && b.i < 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_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:
@@ -885,8 +962,8 @@
bcl_sqrt(BclNumber a)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -897,13 +974,13 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(a.i < 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:
@@ -919,9 +996,9 @@
{
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();
@@ -932,28 +1009,29 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ 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_num_init(BCL_NUM_NUM_NP(cnum), req);
BC_UNSETJMP(vm);
BC_SETJMP(vm, err);
- bc_num_init(&dnum, req);
+ 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:
@@ -965,8 +1043,8 @@
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;
@@ -991,10 +1069,10 @@
{
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();
@@ -1007,27 +1085,29 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
assert(c.i < 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_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:
@@ -1045,65 +1125,72 @@
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);
+ BCL_CHECK_NUM_VALID(ctxt, a);
+ BCL_CHECK_NUM_VALID(ctxt, b);
+
assert(a.i < ctxt->nums.len && b.i < 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(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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_zero(nptr);
+ 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);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
assert(n.i < 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();
@@ -1113,7 +1200,7 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(val != NULL);
@@ -1130,13 +1217,17 @@
}
// 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_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:
@@ -1149,28 +1240,30 @@
char*
bcl_string(BclNumber n)
{
- BcNum* nptr;
+ BclNum* nptr;
char* str = NULL;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
BC_CHECK_CTXT_ASSERT(vm, ctxt);
+ BCL_CHECK_NUM_VALID(ctxt, n);
+
if (BC_ERR(n.i >= ctxt->nums.len)) return str;
BC_FUNC_HEADER(vm, err);
assert(n.i < 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);
// Clear the buffer.
bc_vec_popAll(&vm->out);
// Print to the buffer.
- bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
+ 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.
@@ -1190,8 +1283,8 @@
bcl_irand(BclNumber a)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1202,19 +1295,19 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(a.i < 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_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:
@@ -1275,7 +1368,7 @@
bcl_frand(size_t places)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1284,13 +1377,13 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ 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);
- bcl_frandHelper(&n, places);
+ bcl_frandHelper(BCL_NUM_NUM_NP(n), places);
err:
@@ -1339,8 +1432,8 @@
bcl_ifrand(BclNumber a, size_t places)
{
BclError e = BCL_ERROR_NONE;
- BcNum* aptr;
- BcNum b;
+ BclNum* aptr;
+ BclNum b;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1350,19 +1443,19 @@
BC_FUNC_HEADER(vm, err);
- BC_GROW_NUMS(ctxt);
+ BCL_GROW_NUMS(ctxt);
assert(a.i < 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_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:
@@ -1379,7 +1472,7 @@
bcl_rand_seedWithNum(BclNumber n)
{
BclError e = BCL_ERROR_NONE;
- BcNum* nptr;
+ BclNum* nptr;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1390,11 +1483,11 @@
assert(n.i < 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:
@@ -1442,7 +1535,7 @@
bcl_rand_seed2num(void)
{
BclError e = BCL_ERROR_NONE;
- BcNum n;
+ BclNum n;
BclNumber idx;
BclContext ctxt;
BcVm* vm = bcl_getspecific();
@@ -1452,10 +1545,10 @@
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_num_createFromRNG(&n, &vm->rng);
+ bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng);
err: