commit 5b10b24044b3350a19ab3d3c0b37b5e9c12365b1
Author:     Mattias Andrée <[email protected]>
AuthorDate: Sun Mar 13 23:54:56 2016 +0100
Commit:     Mattias Andrée <[email protected]>
CommitDate: Sun Mar 13 23:54:56 2016 +0100

    Multiple changes:
    
    1)  Compile test with -O0, it takes too long otherwise.
    
    2)  Add error codes: ZERROR_0_POW_0, ZERROR_0_DIV_0, ZERROR_DIV_0, 
ZERROR_NEGATIVE.
    
    3)  Add workaround for a bug in clang (src/allocator.c).
    
    4)  Cleanups.
    
    5)  Minor optimisations.
    
    6)  Add inclusion guard for zahl.h.
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/Makefile b/Makefile
index 60dda0a..80d3aa7 100644
--- a/Makefile
+++ b/Makefile
@@ -80,7 +80,7 @@ test-random.c: test-generate.py
        ./test-generate.py > test-random.c
 
 test: test.c libzahl.a test-random.c
-       $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ test.c libzahl.a
+       $(CC) $(LDFLAGS) $(CFLAGS:--O*) -O0 $(CPPFLAGS) -o $@ test.c libzahl.a
 
 ifndef BENCHMARK_LIB
 benchmark: bench/benchmark.c libzahl.a
diff --git a/man/zerror.3 b/man/zerror.3
index 837b3df..8bc0e53 100644
--- a/man/zerror.3
+++ b/man/zerror.3
@@ -37,5 +37,48 @@ The error is stored in
 (The error may not be stored in
 .I errno
 until this function is called.)
+.TP
+.B ZERROR_0_POW_0
+An attempt to calculate the zeroth power of zero was made.
+This is on indeterminate form and cannot be calculated.
+The closest matching
+.I errno
+value is
+.BR EDOM .
+.TP
+.B ZERROR_0_DIV_0
+An attempt to divide zero by zero was made.
+This is on indeterminate form and cannot be calculated.
+The closest matching
+.I errno
+value is
+.BR EDOM .
+.TP
+.B ZERROR_DIV_0
+An attempt to divide a non-zero value by zero was made.
+This is undefined and cannot be calculated.
+This occurs if a divisor or a modulator is zero, or if
+zero is raised to a negative number.
+The closest matching
+.I errno
+value is
+.BR EDOM .
+.TP
+.B ZERROR_NEGATIVE
+A function argument that must not be negative was negative.
+The closest matching
+.I errno
+values is
+.B EDOM
+and
+.BR EINVAL .
+.SH RETURN VALUE
+.B zerror
+returns the error that caused libzahl a function to fail.
+.SH NOTES
+.I errno
+is only set if
+.B ZERROR_ERRNO_SET
+is returned.
 .SH SEE ALSO
 .BR zperror (3)
diff --git a/src/allocator.c b/src/allocator.c
index 33c8677..41ce9ed 100644
--- a/src/allocator.c
+++ b/src/allocator.c
@@ -1,27 +1,47 @@
 /* See LICENSE file for copyright and license details. */
 #include "internals.h"
+#include <stdio.h>
+
+
+/* Find r such that r is a minimal power of 2 ≥ n. */
+#define NEXT_2POW(n)\
+       do if (likely((n & (~n + 1)) != n)) {\
+               size_t x;\
+               n |= n >> 1;\
+               n |= n >> 2;\
+               n |= n >> 4;\
+               for (i = sizeof(n), x = 8; i; i >>= 1, x <<= 1)\
+                       n |= n >> x;\
+               n += 1;\
+       } while (0)
+
+
+#if defined(__clang__)
+static inline __attribute__((optnone)) size_t
+clang_warkaround_next_2pow(size_t need)
+{
+       size_t i;
+       NEXT_2POW(need);
+       return need;
+}
+#endif
 
 
 void
 libzahl_realloc(z_t a, size_t need)
 {
-       size_t i, x;
+       size_t i;
        zahl_char_t *new;
 
-       /* Find n such that n is a minimal power of 2 ≥ need. */
-       if ((need & (~need + 1)) != need) {
-               need |= need >> 1;
-               need |= need >> 2;
-               need |= need >> 4;
-               for (i = sizeof(need), x = 8; i; i >>= 1, x <<= 1)
-                       need |= need >> x;
-               need += 1;
-       }
+#if defined(__clang__)
+       need = clang_warkaround_next_2pow(need);
+#else
+       NEXT_2POW(need);
+#endif
 
-       for (i = 0, x = need; x; x >>= 1)
-               i += 1;
+       i = libzahl_msb_nz_zu(need);
 
-       if (libzahl_pool_n[i]) {
+       if (likely(libzahl_pool_n[i])) {
                libzahl_pool_n[i]--;
                new = libzahl_pool[i][libzahl_pool_n[i]];
                zmemcpy(new, a->chars, a->alloced);
@@ -32,7 +52,7 @@ libzahl_realloc(z_t a, size_t need)
                if (!a->chars) {
                        if (!errno) /* sigh... */
                                errno = ENOMEM;
-                       FAILURE(errno);
+                       libzahl_failure(errno);
                }
        }
        a->alloced = need;
diff --git a/src/internals.h b/src/internals.h
index 2a947dd..c1153ea 100644
--- a/src/internals.h
+++ b/src/internals.h
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <limits.h>
 
 #define BITS_PER_CHAR                64
 #define LB_BITS_PER_CHAR             6
@@ -60,13 +61,14 @@ extern size_t libzahl_pool_n[sizeof(size_t) * 8];
 extern size_t libzahl_pool_alloc[sizeof(size_t) * 8];
 
 #if defined(__GNUC__) || defined(__clang__)
-# define EXPECT(value, expected)     __builtin_expect(value, expected)
+# define likely(value)               __builtin_expect(!!(value), 1)
+# define unlikely(value)             __builtin_expect(!!(value), 0)
 #else
-# define EXPECT(value, expected)     (value)
+# define likely(value)               (value)
+# define unlikely(value)             (value)
 #endif
 
-#define FAILURE(error)               (libzahl_error = (error), 
longjmp(libzahl_jmp_buf, 1))
-#define zmemmove(d, s, n)            memmove((d), (s), (n) * 
sizeof(zahl_char_t))
+#define libzahl_failure(error)       (libzahl_error = (error), 
longjmp(libzahl_jmp_buf, 1))
 #define SET_SIGNUM(a, signum)        ((a)->sign = (signum))
 #define SET(a, b)                    do { if ((a) != (b)) zset(a, b); } while 
(0)
 #define ENSURE_SIZE(a, n)            do { if ((a)->alloced < (n)) 
libzahl_realloc(a, (n)); } while (0)
@@ -74,6 +76,16 @@ extern size_t libzahl_pool_alloc[sizeof(size_t) * 8];
 #define MAX(a, b)                    ((a) > (b) ? (a) : (b))
 #define TRIM(a)                      for (; (a)->used && !(a)->chars[(a)->used 
- 1]; (a)->used--)
 #define TRIM_NONZERO(a)              for (; !(a)->chars[(a)->used - 1]; 
(a)->used--)
+#define TRIM_AND_ZERO(a)             do { TRIM(a); if (!(a)->used) 
SET_SIGNUM(a, 0); } while (0)
+#define znegative(a)                 (zsignum(a) < 0)
+#define znegative1(a, b)             ((zsignum(a) | zsignum(b)) < 0)
+#define znegative2(a, b)             ((zsignum(a) & zsignum(b)) < 0)
+#define zpositive(a)                 (zsignum(a) > 0)
+#define zpositive1(a, b)             (zpositive(a) + zpositive(b) > 0)
+#define zpositive2(a, b)             (zsignum(a) + zsignum(b) == 2)
+#define zzero1(a, b)                 (zzero(a) + zzero(b) > 0)
+#define zzero2(a, b)                 (!(zsignum(a) | zsignum(b)))
+#define zmemmove(d, s, n)            memmove((d), (s), (n) * 
sizeof(zahl_char_t))
 
 void libzahl_realloc(z_t a, size_t need);
 
@@ -90,3 +102,39 @@ zmemset(zahl_char_t *a, register zahl_char_t v, register 
size_t n)
        while (n--)
                a[n] = v;
 }
+
+/*
+ * libzahl_msb_nz_zu
+ *         ^^^ ^^ ^^
+ *         |   |  |
+ *         |   |  \- size_t parameter
+ *         |   \- non-zero input
+ *         \- most significant bit
+ */
+
+#if SIZE_MAX == ULONG_MAX
+# define libzahl_msb_nz_zu(x)        libzahl_msb_nz_lu(x)
+#else
+# define libzahl_msb_nz_zu(x)        libzahl_msb_nz_llu(x)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libzahl_msb_nz_lu(x)        (8 * sizeof(unsigned long int) - 
(size_t)__builtin_clzl(x));
+# define libzahl_msb_nz_llu(x)       (8 * sizeof(unsigned long long int) - 
(size_t)__builtin_clzll(x));
+#else
+static inline size_t
+libzahl_msb_nz_lu(unsigned long int x)
+{
+       size_t r = 0;
+       for (; x; x >>= 1, r++);
+       return r;
+}
+
+static inline size_t
+libzahl_msb_nz_llu(unsigned long long int x)
+{
+       size_t r = 0;
+       for (; x; x >>= 1, r++);
+       return r;
+}
+#endif
diff --git a/src/zadd.c b/src/zadd.c
index ec17ca4..9891b00 100644
--- a/src/zadd.c
+++ b/src/zadd.c
@@ -9,10 +9,10 @@ zadd_unsigned(z_t a, z_t b, z_t c)
        uint32_t carry[] = {0, 0};
        zahl_char_t *addend;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                zabs(a, c);
                return;
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                zabs(a, b);
                return;
        }
@@ -29,7 +29,7 @@ zadd_unsigned(z_t a, z_t b, z_t c)
                        zmemset(a->chars + a->used, 0, n - a->used);
                }
                addend = c->chars;
-       } else if (EXPECT(a == c, 0)) {
+       } else if (unlikely(a == c)) {
                if (a->used < b->used) {
                        n = b->used;
                        zmemset(a->chars + a->used, 0, n - a->used);
@@ -67,15 +67,15 @@ zadd_unsigned(z_t a, z_t b, z_t c)
 void
 zadd(z_t a, z_t b, z_t c)
 {
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET(a, c);
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                SET(a, b);
-       } else if (EXPECT(b == c, 0)) {
+       } else if (unlikely(b == c)) {
                zlsh(a, b, 1);
-       } else if (EXPECT((zsignum(b) | zsignum(c)) < 0, 0)) {
-               if (zsignum(b) < 0) {
-                       if (zsignum(c) < 0) {
+       } else if (unlikely(znegative1(b, c))) {
+               if (znegative(b)) {
+                       if (znegative(c)) {
                                zadd_unsigned(a, b, c);
                                SET_SIGNUM(a, -zsignum(a));
                        } else {
diff --git a/src/zand.c b/src/zand.c
index 65a8962..119f66c 100644
--- a/src/zand.c
+++ b/src/zand.c
@@ -7,7 +7,7 @@ zand(z_t a, z_t b, z_t c)
 {
        size_t n;
 
-       if (EXPECT(zzero(b) || zzero(c), 0)) {
+       if (unlikely(zzero1(b, c))) {
                SET_SIGNUM(a, 0);
                return;
        }
@@ -24,7 +24,7 @@ found_highest:
        if (a == b) {
                while (n--)
                        a->chars[n] &= c->chars[n];
-       } else if (EXPECT(a == c, 0)) {
+       } else if (unlikely(a == c)) {
                while (n--)
                        a->chars[n] &= b->chars[n];
        } else {
@@ -33,5 +33,5 @@ found_highest:
                while (n--)
                        a->chars[n] &= b->chars[n];
        }
-       SET_SIGNUM(a, (zsignum(b) > 0 || zsignum(c) > 0) * 2 - 1);
+       SET_SIGNUM(a, zpositive1(b, c) * 2 - 1);
 }
diff --git a/src/zbset.c b/src/zbset.c
index 33252c1..2874238 100644
--- a/src/zbset.c
+++ b/src/zbset.c
@@ -35,7 +35,5 @@ zbset(z_t a, z_t b, size_t bit, int action)
                a->chars[chars] &= ~mask;
        }
 
-       TRIM(a);
-       if (!a->used)
-               SET_SIGNUM(a, 0);
+       TRIM_AND_ZERO(a);
 }
diff --git a/src/zcmpi.c b/src/zcmpi.c
index 52fbaf9..54abcd9 100644
--- a/src/zcmpi.c
+++ b/src/zcmpi.c
@@ -5,9 +5,9 @@
 int
 zcmpi(z_t a, long long int b)
 {
-       if (EXPECT(!b, 0))
+       if (unlikely(!b))
                return zsignum(a);
-       if (EXPECT(zzero(a), 0))
+       if (unlikely(zzero(a)))
                return b > 0 ? -1 : b < 0;
        zseti(libzahl_tmp_cmp, b);
        return zcmp(a, libzahl_tmp_cmp);
diff --git a/src/zcmpmag.c b/src/zcmpmag.c
index 59cc415..5594502 100644
--- a/src/zcmpmag.c
+++ b/src/zcmpmag.c
@@ -6,9 +6,9 @@ int
 zcmpmag(z_t a, z_t b)
 {
        size_t i, j;
-       if (EXPECT(zzero(a), 0))
+       if (unlikely(zzero(a)))
                return -!zzero(b);
-       if (EXPECT(zzero(b), 0))
+       if (unlikely(zzero(b)))
                return 1;
        i = a->used - 1;
        j = b->used - 1;
diff --git a/src/zcmpu.c b/src/zcmpu.c
index 7da7f9a..40e33b6 100644
--- a/src/zcmpu.c
+++ b/src/zcmpu.c
@@ -5,9 +5,9 @@
 int
 zcmpu(z_t a, unsigned long long int b)
 {
-       if (EXPECT(!b, 0))
+       if (unlikely(!b))
                return zsignum(a);
-       if (EXPECT(zsignum(a) <= 0, 0))
+       if (unlikely(zsignum(a) <= 0))
                return -1;
        zsetu(libzahl_tmp_cmp, b);
        return zcmp(a, libzahl_tmp_cmp);
diff --git a/src/zdivmod.c b/src/zdivmod.c
index c77e34a..55d0e06 100644
--- a/src/zdivmod.c
+++ b/src/zdivmod.c
@@ -15,19 +15,19 @@ zdivmod(z_t a, z_t b, z_t c, z_t d)
 
        sign = zsignum(c) * zsignum(d);
 
-       if (EXPECT(!sign, 0)) {
+       if (unlikely(!sign)) {
                if (zzero(c)) {
                        if (zzero(d)) {
-                               FAILURE(EDOM); /* Indeterminate form: 0 divided 
by 0 */
+                               libzahl_failure(-ZERROR_0_DIV_0);
                        } else {
                                SET_SIGNUM(a, 0);
                                SET_SIGNUM(b, 0);
                        }
                } else {
-                       FAILURE(EDOM); /* Undefined form: Division by 0 */
+                       libzahl_failure(-ZERROR_DIV_0);
                }
                return;
-       } else if (EXPECT((cmpmag = zcmpmag(c, d)) <= 0, 0)) {
+       } else if (unlikely((cmpmag = zcmpmag(c, d)) <= 0)) {
                if (cmpmag == 0) {
                        zseti(a, sign);
                        SET_SIGNUM(b, 0);
diff --git a/src/zerror.c b/src/zerror.c
index c59b092..e4ed427 100644
--- a/src/zerror.c
+++ b/src/zerror.c
@@ -2,6 +2,13 @@
 #include "internals.h"
 
 
+#define LIST_ERRORS\
+       X(ZERROR_0_POW_0,  "indeterminate form: 0:th power of 0")\
+       X(ZERROR_0_DIV_0,  "indeterminate form: 0 divided by 0")\
+       X(ZERROR_DIV_0,    "undefined result: division by 0")\
+       X(ZERROR_NEGATIVE, "argument must be non-negative")
+
+
 enum zerror
 zerror(const char **desc)
 {
@@ -10,10 +17,16 @@ zerror(const char **desc)
                        *desc = strerror(libzahl_error);
                errno = libzahl_error;
                return ZERROR_ERRNO_SET;
-       } else {
-               /* Current, we should not be able to get here. */
-               if (desc)
+       }
+
+       if (desc) {
+               switch (-libzahl_error) {
+#define X(V, D) case V: *desc = D; break;
+               LIST_ERRORS
+#undef X
+               default:
                        abort();
-               return -libzahl_error;
+               }
        }
+       return -libzahl_error;
 }
diff --git a/src/zfree.c b/src/zfree.c
index 2a1680a..5048048 100644
--- a/src/zfree.c
+++ b/src/zfree.c
@@ -5,15 +5,13 @@
 void
 zfree(z_t a)
 {
-       size_t i = 0, x, j;
+       size_t i, x, j;
        zahl_char_t **new;
 
-       if (!a->chars)
+       if (unlikely(!a->chars))
                return;
 
-       for (x = a->alloced; x; x >>= 1)
-               i += 1;
-
+       i = libzahl_msb_nz_zu(a->alloced);
        j = libzahl_pool_n[i]++;
 
        if (j == libzahl_pool_alloc[i]) {
diff --git a/src/zgcd.c b/src/zgcd.c
index 9b1d451..7c6f2bc 100644
--- a/src/zgcd.c
+++ b/src/zgcd.c
@@ -16,22 +16,22 @@ zgcd(z_t a, z_t b, z_t c)
        zahl_char_t uv, bit;
        int neg;
 
-       if (EXPECT(!zcmp(b, c), 0)) {
+       if (unlikely(!zcmp(b, c))) {
                SET(a, b);
                return;
        }
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET(a, c);
                return;
        }
-       if (EXPECT(zzero(c), 0)) {
+       if (unlikely(zzero(c))) {
                SET(a, b);
                return;
        }
 
        zabs(u, b);
        zabs(v, c);
-       neg = zsignum(b) < 0 && zsignum(c) < 0;
+       neg = znegative2(b, c);
 
        min = MIN(u->used, v->used);
        for (; i < min; i++) {
diff --git a/src/zload.c b/src/zload.c
index 03bcbb9..877c95e 100644
--- a/src/zload.c
+++ b/src/zload.c
@@ -8,7 +8,7 @@ zload(z_t a, const void *buffer)
        const char *buf = buffer;
        a->sign = *((const int *)buf),    buf += sizeof(int);
        a->used = *((const size_t *)buf), buf += sizeof(size_t);
-       if (EXPECT(!!a->sign, 1)) {
+       if (likely(a->sign)) {
                ENSURE_SIZE(a, a->used);
                zmemcpy(a->chars, (const zahl_char_t *)buf, a->used);
        }
diff --git a/src/zlsh.c b/src/zlsh.c
index 3daa01d..42894e0 100644
--- a/src/zlsh.c
+++ b/src/zlsh.c
@@ -8,11 +8,11 @@ zlsh(z_t a, z_t b, size_t bits)
        size_t i, chars, cbits;
        zahl_char_t carry[] = {0, 0};
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
-       if (EXPECT(!bits, 0)) {
+       if (unlikely(!bits)) {
                SET(a, b);
                return;
        }
@@ -22,14 +22,14 @@ zlsh(z_t a, z_t b, size_t bits)
        cbits = BITS_PER_CHAR - bits;
 
        ENSURE_SIZE(a, b->used + chars);
-       if (EXPECT(a == b, 1))
+       if (likely(a == b))
                zmemmove(a->chars + chars, b->chars, b->used);
        else
                zmemcpy(a->chars + chars, b->chars, b->used);
        zmemset(a->chars, 0, chars);
        a->used = b->used + chars;
 
-       if (EXPECT(bits, 1)) { /* This if statement is very important in C. */
+       if (likely(bits)) { /* This if statement is very important in C. */
                for (i = chars; i < a->used; i++) {
                        carry[~i & 1] = a->chars[i] >> cbits;
                        a->chars[i] <<= bits;
diff --git a/src/zmodmul.c b/src/zmodmul.c
index bb0aa03..26d1178 100644
--- a/src/zmodmul.c
+++ b/src/zmodmul.c
@@ -6,7 +6,7 @@ void
 zmodmul(z_t a, z_t b, z_t c, z_t d)
 {
        /* TODO Montgomery modular multiplication */
-       if (EXPECT(a == d, 0)) {
+       if (unlikely(a == d)) {
                zset(libzahl_tmp_modmul, d);
                zmul(a, b, c);
                zmod(a, a, libzahl_tmp_modmul);
diff --git a/src/zmodpow.c b/src/zmodpow.c
index ed87ac5..9e002ff 100644
--- a/src/zmodpow.c
+++ b/src/zmodpow.c
@@ -12,22 +12,22 @@ zmodpow(z_t a, z_t b, z_t c, z_t d)
        size_t i, j, n, bits;
        zahl_char_t x;
 
-       if (EXPECT(zsignum(c) <= 0, 0)) {
+       if (unlikely(zsignum(c) <= 0)) {
                if (zzero(c)) {
                        if (zzero(b))
-                               FAILURE(EDOM); /* Indeterminate form: 0:th 
power of 0 */
+                               libzahl_failure(-ZERROR_0_POW_0);
                        else if (zzero(d))
-                               FAILURE(EDOM); /* Undefined form: Division by 0 
*/
+                               libzahl_failure(-ZERROR_DIV_0);
                        zsetu(a, 1);
-               } else if (zzero(b) || zzero(d)) {
-                       FAILURE(EDOM); /* Undefined form: Division by 0 */
+               } else if (zzero1(b, d)) {
+                       libzahl_failure(-ZERROR_DIV_0);
                } else {
                        SET_SIGNUM(a, 0);
                }
                return;
-       } else if (EXPECT(zzero(d), 0)) {
-               FAILURE(EDOM); /* Undefined form: Division by 0 */
-       } else if (EXPECT(zzero(b), 0)) {
+       } else if (unlikely(zzero(d))) {
+               libzahl_failure(-ZERROR_DIV_0);
+       } else if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/zmodpowu.c b/src/zmodpowu.c
index 6dcb6b7..c9c8af5 100644
--- a/src/zmodpowu.c
+++ b/src/zmodpowu.c
@@ -8,17 +8,17 @@
 void
 zmodpowu(z_t a, z_t b, unsigned long long int c, z_t d)
 {
-       if (EXPECT(!c, 0)) {
+       if (unlikely(!c)) {
                if (zzero(b))
-                       FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
+                       libzahl_failure(-ZERROR_0_POW_0);
                else if (zzero(d))
-                       FAILURE(EDOM); /* Undefined form: Division by 0 */
+                       libzahl_failure(-ZERROR_DIV_0);
                else
                        zsetu(a, 1);
                return;
-       } else if (EXPECT(zzero(d), 0)) {
-               FAILURE(EDOM); /* Undefined form: Division by 0 */
-       } else if (EXPECT(zzero(b), 0)) {
+       } else if (unlikely(zzero(d))) {
+               libzahl_failure(-ZERROR_DIV_0);
+       } else if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/zmodsqr.c b/src/zmodsqr.c
index bdf0ea2..4eb6e51 100644
--- a/src/zmodsqr.c
+++ b/src/zmodsqr.c
@@ -6,7 +6,7 @@ void
 zmodsqr(z_t a, z_t b, z_t c)
 {
        /* TODO What is the fastest way to do zmodsqr? */
-       if (EXPECT(a == c, 0)) {
+       if (unlikely(a == c)) {
                zset(libzahl_tmp_modsqr, c);
                zsqr(a, b);
                zmod(a, a, libzahl_tmp_modsqr);
diff --git a/src/zmul.c b/src/zmul.c
index c2cca10..ae02844 100644
--- a/src/zmul.c
+++ b/src/zmul.c
@@ -22,7 +22,7 @@ zmul(z_t a, z_t b, z_t c)
        b_sign = zsignum(b);
        c_sign = zsignum(c);
 
-       if (EXPECT(!b_sign || !c_sign, 0)) {
+       if (unlikely(!b_sign || !c_sign)) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/znot.c b/src/znot.c
index e1b114c..bebc55b 100644
--- a/src/znot.c
+++ b/src/znot.c
@@ -7,7 +7,7 @@ znot(z_t a, z_t b)
 {
        size_t bits, i;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
@@ -22,7 +22,5 @@ znot(z_t a, z_t b)
        if (bits)
                a->chars[a->used - 1] &= ((zahl_char_t)1 << bits) - 1;
 
-       TRIM(a);
-       if (!a->used)
-               SET_SIGNUM(a, 0);
+       TRIM_AND_ZERO(a);
 }
diff --git a/src/zor.c b/src/zor.c
index b67f5b3..4e7a2dc 100644
--- a/src/zor.c
+++ b/src/zor.c
@@ -7,13 +7,13 @@ zor(z_t a, z_t b, z_t c)
 {
        size_t n, m;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                if (zzero(c))
                        SET_SIGNUM(a, 0);
                else
                        SET(a, c);
                return;
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                SET(a, b);
                return;
        }
@@ -28,7 +28,7 @@ zor(z_t a, z_t b, z_t c)
                        zmemcpy(a->chars + n, c->chars + n, m - n);
                while (n--)
                        a->chars[n] |= c->chars[n];
-       } else if (EXPECT(a == c, 0)) {
+       } else if (unlikely(a == c)) {
                if (c->used < b->used)
                        zmemcpy(a->chars + n, b->chars + n, m - n);
                while (n--)
@@ -44,5 +44,5 @@ zor(z_t a, z_t b, z_t c)
        }
 
        a->used = m;
-       SET_SIGNUM(a, (zsignum(b) > 0 && zsignum(c) > 0) * 2 - 1);
+       SET_SIGNUM(a, zpositive2(b, c) * 2 - 1);
 }
diff --git a/src/zperror.c b/src/zperror.c
index 37bd5c7..5d5d11a 100644
--- a/src/zperror.c
+++ b/src/zperror.c
@@ -11,7 +11,11 @@ zperror(const char *prefix)
                errno = libzahl_error;
                perror(prefix);
        } else {
-               /* Current, we should not be able to get here. */
-               abort();
+               const char *desc;
+               zerror(&desc);
+               if (prefix && *prefix)
+                       fprintf(stderr, "%s: %s\n", prefix, desc);
+               else
+                       fprintf(stderr, "%s\n", desc);
        }
 }
diff --git a/src/zpow.c b/src/zpow.c
index 9eb5724..81f8098 100644
--- a/src/zpow.c
+++ b/src/zpow.c
@@ -17,18 +17,18 @@ zpow(z_t a, z_t b, z_t c)
        size_t i, j, n, bits;
        zahl_char_t x;
 
-       if (EXPECT(zsignum(c) <= 0, 0)) {
+       if (unlikely(zsignum(c) <= 0)) {
                if (zzero(c)) {
                        if (zzero(b))
-                               FAILURE(EDOM); /* Indeterminate form: 0:th 
power of 0 */
+                               libzahl_failure(-ZERROR_0_POW_0);
                        zsetu(a, 1);
                } else if (zzero(b)) {
-                       FAILURE(EDOM); /* Undefined form: Division by 0 */
+                       libzahl_failure(-ZERROR_DIV_0);
                } else {
                        SET_SIGNUM(a, 0);
                }
                return;
-       } else if (EXPECT(zzero(b), 0)) {
+       } else if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/zpowu.c b/src/zpowu.c
index 67cdc58..c4a2a64 100644
--- a/src/zpowu.c
+++ b/src/zpowu.c
@@ -7,12 +7,12 @@
 void
 zpowu(z_t a, z_t b, unsigned long long int c)
 {
-       if (EXPECT(!c, 0)) {
+       if (unlikely(!c)) {
                if (zzero(b))
-                       FAILURE(EDOM); /* Indeterminate form: 0:th power of 0 */
+                       libzahl_failure(-ZERROR_0_POW_0);
                zsetu(a, 1);
                return;
-       } else if (EXPECT(zzero(b), 0)) {
+       } else if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/zptest.c b/src/zptest.c
index d6fa80d..005a2bd 100644
--- a/src/zptest.c
+++ b/src/zptest.c
@@ -17,7 +17,7 @@ zptest(z_t witness, z_t n, int t)
 
        size_t i, r;
 
-       if (EXPECT(zcmpu(n, 3) <= 0, 0)) {
+       if (unlikely(zcmpu(n, 3) <= 0)) {
                if (zcmpu(n, 1) <= 0) {
                        if (witness)
                                SET(witness, n);
@@ -26,7 +26,7 @@ zptest(z_t witness, z_t n, int t)
                        return PRIME;
                }
        }
-       if (EXPECT(zeven(n), 0)) {
+       if (unlikely(zeven(n))) {
                if (witness)
                        SET(witness, n);
                return NONPRIME;
diff --git a/src/zrand.c b/src/zrand.c
index 48d4802..64fa7ed 100644
--- a/src/zrand.c
+++ b/src/zrand.c
@@ -27,7 +27,7 @@ zrand_get_random_bits(z_t r, size_t bits, int fd)
        for (n = chars * sizeof(zahl_char_t); n;) {
                read_just = read(fd, buf + read_total, n);
                if (read_just < 0)
-                       FAILURE(errno);
+                       libzahl_failure(errno);
                read_total += (size_t)read_just;
                n -= (size_t)read_just;
        }
@@ -62,22 +62,22 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n)
                pathname = SECURE_RANDOM_PATHNAME;
                break;
        default:
-               abort();
+               libzahl_failure(EINVAL);
        }
 
-       if (EXPECT(zzero(n), 0)) {
+       if (unlikely(zzero(n))) {
                SET_SIGNUM(r, 0);
                return;
        }
 
        fd = open(pathname, O_RDONLY);
        if (fd < 0)
-               FAILURE(errno);
+               libzahl_failure(errno);
 
        switch (dist) {
        case QUASIUNIFORM:
-               if (EXPECT(zsignum(n) < 0, 0))
-                       FAILURE(EDOM); /* n must be non-negative. */
+               if (unlikely(znegative(n)))
+                       libzahl_failure(-ZERROR_NEGATIVE);
                bits = zbits(n);
                zrand_get_random_bits(r, bits, fd);
                zadd(r, r, libzahl_const_1);
@@ -86,8 +86,8 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n)
                break;
 
        case UNIFORM:
-               if (EXPECT(zsignum(n) < 0, 0))
-                       FAILURE(EDOM); /* n must be non-negative. */
+               if (unlikely(znegative(n)))
+                       libzahl_failure(-ZERROR_NEGATIVE);
                bits = zbits(n);
                do
                        zrand_get_random_bits(r, bits, fd);
@@ -95,7 +95,7 @@ zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n)
                break;
 
        default:
-               abort();
+               libzahl_failure(EINVAL);
        }
 
        close(fd);
diff --git a/src/zrsh.c b/src/zrsh.c
index cc83ae5..163919d 100644
--- a/src/zrsh.c
+++ b/src/zrsh.c
@@ -7,14 +7,14 @@ zrsh(z_t a, z_t b, size_t bits)
 {
        size_t i, chars, cbits;
 
-       if (EXPECT(!bits, 0)) {
+       if (unlikely(!bits)) {
                SET(a, b);
                return;
        }
 
        chars = FLOOR_BITS_TO_CHARS(bits);
 
-       if (EXPECT(zzero(b) || chars >= b->used || zbits(b) <= bits, 0)) {
+       if (unlikely(zzero(b) || chars >= b->used || zbits(b) <= bits)) {
                SET_SIGNUM(a, 0);
                return;
        }
@@ -22,16 +22,16 @@ zrsh(z_t a, z_t b, size_t bits)
        bits = BITS_IN_LAST_CHAR(bits);
        cbits = BITS_PER_CHAR - bits;
 
-       if (EXPECT(chars, 1) && EXPECT(a == b, 1)) {
+       if (likely(chars) && likely(a == b)) {
                a->used -= chars;
                zmemmove(a->chars, a->chars + chars, a->used);
-       } else if (EXPECT(a != b, 0)) {
+       } else if (unlikely(a != b)) {
                a->used = b->used - chars;
                ENSURE_SIZE(a, a->used);
                zmemcpy(a->chars, b->chars + chars, a->used);
        }
 
-       if (EXPECT(bits, 0)) { /* This if statement is very important in C. */
+       if (unlikely(bits)) { /* This if statement is very important in C. */
                a->chars[0] >>= bits;
                for (i = 1; i < a->used; i++) {
                        a->chars[i - 1] |= a->chars[i] << cbits;
diff --git a/src/zsave.c b/src/zsave.c
index 07d43fa..8b08f2a 100644
--- a/src/zsave.c
+++ b/src/zsave.c
@@ -9,7 +9,7 @@ zsave(z_t a, void *buffer)
                char *buf = buffer;
                *((int *)buf)    = a->sign, buf += sizeof(int);
                *((size_t *)buf) = a->used, buf += sizeof(size_t);
-               if (EXPECT(!zzero(a), 1))
+               if (likely(!zzero(a)))
                        zmemcpy((zahl_char_t *)buf, a->chars, a->used);
        }
        return sizeof(int) + sizeof(size_t) + (zzero(a) ? 0 : a->used * 
sizeof(zahl_char_t));
diff --git a/src/zset.c b/src/zset.c
index 9bb2778..b0188fc 100644
--- a/src/zset.c
+++ b/src/zset.c
@@ -5,7 +5,7 @@
 void
 zset(z_t a, z_t b)
 {
-       if (EXPECT(b->sign == 0, 0)) {
+       if (unlikely(b->sign == 0)) {
                a->sign = 0;
        } else {
                a->sign = b->sign;
diff --git a/src/zseti.c b/src/zseti.c
index d3514fb..e1116b6 100644
--- a/src/zseti.c
+++ b/src/zseti.c
@@ -5,7 +5,7 @@
 void
 zseti(z_t a, long long int b)
 {
-       if (EXPECT(b >= 0, 0)) {
+       if (unlikely(b >= 0)) {
                zsetu(a, (unsigned long long int)b);
        } else {
                zsetu(a, (unsigned long long int)-b);
diff --git a/src/zsets.c b/src/zsets.c
index 24ca082..bddc9ec 100644
--- a/src/zsets.c
+++ b/src/zsets.c
@@ -13,12 +13,12 @@ zsets(z_t a, const char *str)
 
        str += neg || (*str == '+');
 
-       if (EXPECT(!*str, 0)) {
+       if (unlikely(!*str)) {
                errno = EINVAL;
                return -1;
        }
        for (str_end = str; *str_end; str_end++) {
-               if (EXPECT(!isdigit(*str_end), 0)) {
+               if (unlikely(!isdigit(*str_end))) {
                        errno = EINVAL;
                        return -1;
                }
diff --git a/src/zsplit.c b/src/zsplit.c
index 68810d2..ab2dc78 100644
--- a/src/zsplit.c
+++ b/src/zsplit.c
@@ -5,13 +5,13 @@
 void
 zsplit(z_t high, z_t low, z_t a, size_t delim)
 {
-       if (EXPECT(zzero(a), 0)) {
+       if (unlikely(zzero(a))) {
                SET_SIGNUM(high, 0);
                SET_SIGNUM(low, 0);
                return;
        }
 
-       if (EXPECT(high == a, 0)) {
+       if (unlikely(high == a)) {
                ztrunc(low, a, delim);
                zrsh(high, a, delim);
        } else {
diff --git a/src/zsqr.c b/src/zsqr.c
index 9601eb6..bd03128 100644
--- a/src/zsqr.c
+++ b/src/zsqr.c
@@ -13,7 +13,7 @@ zsqr(z_t a, z_t b)
        z_t z0, z1, z2, high, low;
        int sign;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
diff --git a/src/zstr.c b/src/zstr.c
index 81a9674..dfcdf23 100644
--- a/src/zstr.c
+++ b/src/zstr.c
@@ -16,16 +16,12 @@ char *
 zstr(z_t a, char *b)
 {
        char buf[19 + 1];
-       size_t n, len;
+       size_t n, len, neg;
        char overridden = 0;
-       int neg;
 
        if (zzero(a)) {
-               if (!b) {
-                       b = malloc(2);
-                       if (!b)
-                               FAILURE(errno);
-               }
+               if (!b && !(b = malloc(2)))
+                       libzahl_failure(errno);
                b[0] = '0';
                b[1] = 0;
                return b;
@@ -33,13 +29,10 @@ zstr(z_t a, char *b)
 
        n = zstr_length(a, 10);
 
-       if (!b) {
-               b = malloc(n + 1);
-               if (!b)
-                       FAILURE(errno);
-       }
+       if (!b && !(b = malloc(n + 1)))
+               libzahl_failure(errno);
 
-       neg = zsignum(a) < 0;
+       neg = znegative(a);
        zabs(num, a);
        b[0] = '-';
        b += neg;
diff --git a/src/zsub.c b/src/zsub.c
index bf918da..e769e32 100644
--- a/src/zsub.c
+++ b/src/zsub.c
@@ -10,11 +10,11 @@ zsub_unsigned(z_t a, z_t b, z_t c)
        size_t i, n;
        int magcmp;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                zabs(a, c);
                zneg(a, a);
                return;
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                zabs(a, b);
                return;
        }
@@ -61,15 +61,15 @@ zsub_unsigned(z_t a, z_t b, z_t c)
 void
 zsub(z_t a, z_t b, z_t c)
 {
-       if (EXPECT(b == c, 0)) {
+       if (unlikely(b == c)) {
                SET_SIGNUM(a, 0);
-       } else if (EXPECT(zzero(b), 0)) {
+       } else if (unlikely(zzero(b))) {
                zneg(a, c);
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                SET(a, b);
-       } else if (EXPECT((zsignum(b) | zsignum(c)) < 0, 0)) {
-               if (zsignum(b) < 0) {
-                       if (zsignum(c) < 0) {
+       } else if (unlikely(znegative1(b, c))) {
+               if (znegative(b)) {
+                       if (znegative(c)) {
                                zsub_unsigned(a, c, b);
                        } else {
                                zadd_unsigned(a, b, c);
diff --git a/src/ztrunc.c b/src/ztrunc.c
index 7dcafd9..91d2a92 100644
--- a/src/ztrunc.c
+++ b/src/ztrunc.c
@@ -8,7 +8,7 @@ ztrunc(z_t a, z_t b, size_t bits)
        zahl_char_t mask = 1;
        size_t chars;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                SET_SIGNUM(a, 0);
                return;
        }
@@ -16,14 +16,14 @@ ztrunc(z_t a, z_t b, size_t bits)
        chars = CEILING_BITS_TO_CHARS(bits);
        a->sign = b->sign;
        a->used = MIN(chars, b->used);
-       if (EXPECT(a->used < chars, 0))
+       if (unlikely(a->used < chars))
                bits = 0;
-       if (EXPECT(a != b, 1)) {
+       if (likely(a != b)) {
                ENSURE_SIZE(a, a->used);
                zmemcpy(a->chars, b->chars, a->used);
        }
        bits = BITS_IN_LAST_CHAR(bits);
-       if (EXPECT(!!bits, 1)) {
+       if (likely(bits)) {
                mask <<= bits;
                mask -= 1;
                a->chars[a->used - 1] &= mask;
diff --git a/src/zxor.c b/src/zxor.c
index da56a24..876591a 100644
--- a/src/zxor.c
+++ b/src/zxor.c
@@ -7,13 +7,13 @@ zxor(z_t a, z_t b, z_t c)
 {
        size_t n, m;
 
-       if (EXPECT(zzero(b), 0)) {
+       if (unlikely(zzero(b))) {
                if (zzero(c))
                        SET_SIGNUM(a, 0);
                else
                        SET(a, c);
                return;
-       } else if (EXPECT(zzero(c), 0)) {
+       } else if (unlikely(zzero(c))) {
                SET(a, b);
                return;
        }
@@ -28,7 +28,7 @@ zxor(z_t a, z_t b, z_t c)
                        zmemcpy(a->chars + n, c->chars + n, m - n);
                while (n--)
                        a->chars[n] ^= c->chars[n];
-       } else if (EXPECT(a == c, 0)) {
+       } else if (unlikely(a == c)) {
                if (c->used < b->used)
                        zmemcpy(a->chars + n, b->chars + n, m - n);
                while (n--)
diff --git a/test.c b/test.c
index 624abb0..c4f146c 100644
--- a/test.c
+++ b/test.c
@@ -112,7 +112,7 @@ main(void)
        assert(zodd(_2), == 0);
        assert(zzero(_2), == 0);
        assert(zsignum(_2), == 1);
-       
+
        assert((zneg(_2, _2), zsignum(_2)), == -1); zneg(_2, _2);
        assert(zsignum(_2), == 1);
 
diff --git a/zahl.h b/zahl.h
index 89fc6f8..d051bc1 100644
--- a/zahl.h
+++ b/zahl.h
@@ -3,6 +3,9 @@
 /* Warning: libzahl is not thread-safe. */
 /* Caution: Do not use libzahl for cryptographic applications, use a 
specialised library. */
 
+#ifndef ZAHL_H
+#define ZAHL_H
+
 
 #include <stddef.h>
 #include <setjmp.h>
@@ -27,7 +30,11 @@ enum zranddev { FAST_RANDOM = 0, SECURE_RANDOM };
 enum zranddist { QUASIUNIFORM = 0, UNIFORM };
 
 enum zerror {
-       ZERROR_ERRNO_SET = 0
+       ZERROR_ERRNO_SET = 0,          /* Please refer to errno. */
+       ZERROR_0_POW_0,                /* Indeterminate form: 0:th power of 0. 
(Translatable to EDOM.) */
+       ZERROR_0_DIV_0,                /* Indeterminate form: 0 divided by 0. 
(Translatable to EDOM.) */
+       ZERROR_DIV_0,                  /* Undefined result: Division by 0. 
(Translatable to EDOM.) */
+       ZERROR_NEGATIVE                /* Argument must be non-negative. 
(Translatable to EDOM or EINVAL.) */
 };
 
 
@@ -160,7 +167,7 @@ zlsb(z_t a)
                return SIZE_MAX;
        for (; !a->chars[i]; i++);
        i *= 8 * sizeof(zahl_char_t);
-       i += __builtin_ctzll(a->chars[i]);
+       i += (size_t)__builtin_ctzll(a->chars[i]);
        return i;
 }
 #else
@@ -190,7 +197,7 @@ zbits(z_t a)
                return 1;
        while (!a->chars[a->used - 1])  a->used--; /* TODO should not be 
necessary */
        rc = a->used * 8 * sizeof(zahl_char_t);
-       rc -= __builtin_clzll(a->chars[a->used - 1]);
+       rc -= (size_t)__builtin_clzll(a->chars[a->used - 1]);
        return rc;
 }
 #else
@@ -208,3 +215,6 @@ zbits(z_t a)
        return rc;
 }
 #endif
+
+
+#endif

Reply via email to