inlines.h (6645B)
1 /* See LICENSE file for copyright and license details. */ 2 3 ZAHL_INLINE void zinit(z_t a) { a->alloced = 0; a->chars = 0; } 4 ZAHL_INLINE int zeven(z_t a) { return !a->sign || (~a->chars[0] & 1); } 5 ZAHL_INLINE int zodd(z_t a) { return a->sign && (a->chars[0] & 1); } 6 ZAHL_INLINE int zeven_nonzero(z_t a) { return ~a->chars[0] & 1; } 7 ZAHL_INLINE int zodd_nonzero(z_t a) { return a->chars[0] & 1; } 8 ZAHL_INLINE int zzero(z_t a) { return !a->sign; } 9 ZAHL_INLINE int zsignum(z_t a) { return a->sign; } 10 ZAHL_INLINE void zneg(z_t a, z_t b) { ZAHL_SET(a, b); a->sign = -a->sign; } 11 12 #if 1 && (-1 & 1) /* In the future, tuning will select the fastest implementation. */ 13 ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); a->sign &= 1; } 14 #elif 1 15 ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); if (ZAHL_LIKELY(a->sign < 0)) a->sign = 1; } 16 #else 17 ZAHL_INLINE void zabs(z_t a, z_t b) { ZAHL_SET(a, b); a->sign = !!a->sign; } 18 #endif 19 20 21 #if ULONG_MAX != SIZE_MAX /* This variant should be equivalent to the second one if .sign was long. */ 22 ZAHL_INLINE void 23 zswap(z_t a, z_t b) 24 { 25 z_t t; 26 ZAHL_SWAP(a, b, t, sign); 27 ZAHL_SWAP(b, a, t, used); 28 ZAHL_SWAP(a, b, t, alloced); 29 ZAHL_SWAP(b, a, t, chars); 30 } 31 #else 32 ZAHL_INLINE void 33 zswap(z_t a_, z_t b_) 34 { 35 register long t; 36 long *a = (long *)a_; 37 long *b = (long *)b_; 38 t = a[0], a[0] = b[0], b[0] = t; 39 t = b[1], b[1] = a[1], a[1] = t; 40 t = a[2], a[2] = b[2], b[2] = t; 41 t = b[3], b[3] = a[3], a[3] = t; 42 } 43 #endif 44 45 46 ZAHL_INLINE void 47 zset(z_t a, z_t b) 48 { 49 if (ZAHL_UNLIKELY(b->sign == 0)) { 50 a->sign = 0; 51 } else { 52 a->sign = b->sign; 53 a->used = b->used; 54 ZAHL_ENSURE_SIZE(a, b->used); 55 libzahl_memcpy(a->chars, b->chars, b->used); 56 } 57 } 58 59 60 ZAHL_INLINE void 61 zseti(z_t a, int64_t b) 62 { 63 if (ZAHL_UNLIKELY(b >= 0)) { 64 zsetu(a, (uint64_t)b); 65 return; 66 } 67 ZAHL_ENSURE_SIZE(a, 1); 68 ZAHL_SET_SIGNUM(a, -1); 69 a->chars[0] = (zahl_char_t)-b; 70 a->used = 1; 71 } 72 73 74 ZAHL_INLINE void 75 zsetu(z_t a, uint64_t b) 76 { 77 if (ZAHL_UNLIKELY(!b)) { 78 ZAHL_SET_SIGNUM(a, 0); 79 return; 80 } 81 ZAHL_ENSURE_SIZE(a, 1); 82 ZAHL_SET_SIGNUM(a, 1); 83 a->chars[0] = (zahl_char_t)b; 84 a->used = 1; 85 } 86 87 88 ZAHL_INLINE size_t 89 zlsb(z_t a) 90 { 91 size_t i = 0; 92 if (ZAHL_UNLIKELY(zzero(a))) 93 return SIZE_MAX; 94 for (; !a->chars[i]; i++); 95 i *= 8 * sizeof(zahl_char_t); 96 ZAHL_ADD_CTZ(i, a->chars[i]); 97 return i; 98 } 99 100 101 ZAHL_INLINE size_t 102 zbits(z_t a) 103 { 104 size_t rc; 105 if (ZAHL_UNLIKELY(zzero(a))) 106 return 1; 107 while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 108 rc = a->used * 8 * sizeof(zahl_char_t); 109 ZAHL_SUB_CLZ(rc, a->chars[a->used - 1]); 110 return rc; 111 } 112 113 114 ZAHL_INLINE int 115 zcmpmag(z_t a, z_t b) 116 { 117 size_t i, j; 118 if (ZAHL_UNLIKELY(zzero(a))) return -!zzero(b); 119 if (ZAHL_UNLIKELY(zzero(b))) return 1; 120 i = a->used - 1; 121 j = b->used - 1; 122 #if 0 /* TODO this should be sufficient. */ 123 if (i != j) 124 return (i > j) * 2 - 1; 125 #else 126 for (; i > j; i--) { 127 if (a->chars[i]) 128 return +1; 129 a->used--; 130 } 131 for (; j > i; j--) { 132 if (b->chars[j]) 133 return -1; 134 b->used--; 135 } 136 #endif 137 for (; i && a->chars[i] == b->chars[i]; i--); 138 return a->chars[i] < b->chars[i] ? -1 : a->chars[i] > b->chars[i]; 139 } 140 141 142 ZAHL_INLINE int 143 zcmp(z_t a, z_t b) 144 { 145 if (zsignum(a) != zsignum(b)) 146 return zsignum(a) < zsignum(b) ? -1 : zsignum(a) > zsignum(b); 147 return zsignum(a) * zcmpmag(a, b); 148 } 149 150 151 ZAHL_INLINE int 152 zcmpu(z_t a, uint64_t b) 153 { 154 if (ZAHL_UNLIKELY(!b)) 155 return zsignum(a); 156 if (ZAHL_UNLIKELY(zsignum(a) <= 0)) 157 return -1; 158 while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 159 if (a->used > 1) 160 return +1; 161 return a->chars[0] < b ? -1 : a->chars[0] > b; 162 } 163 164 165 ZAHL_INLINE int 166 zcmpi(z_t a, int64_t b) 167 { 168 if (ZAHL_UNLIKELY(!b)) 169 return zsignum(a); 170 if (ZAHL_UNLIKELY(zzero(a))) 171 return ZAHL_LIKELY(b < 0) ? 1 : -1; 172 if (ZAHL_LIKELY(b < 0)) { 173 if (zsignum(a) > 0) 174 return +1; 175 while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 176 if (a->used > 1) 177 return -1; 178 return a->chars[0] > (zahl_char_t)-b ? -1 : a->chars[0] < (zahl_char_t)-b; 179 } else { 180 if (zsignum(a) < 0) 181 return -1; 182 while (!a->chars[a->used - 1]) a->used--; /* TODO should not be necessary */ 183 if (a->used > 1) 184 return +1; 185 return a->chars[0] < (zahl_char_t)b ? -1 : a->chars[0] > (zahl_char_t)b; 186 } 187 } 188 189 190 ZAHL_INLINE void 191 zbset(z_t a, z_t b, size_t bit, int action) 192 { 193 if (ZAHL_UNLIKELY(a != b)) 194 zset(a, b); 195 196 #ifdef ZAHL_CONST_P 197 if (ZAHL_CONST_P(action) && ZAHL_CONST_P(bit)) { 198 zahl_char_t mask = 1; 199 if (zzero(a) || ZAHL_FLOOR_BITS_TO_CHARS(bit) >= a->used) { 200 if (!action) 201 return; 202 goto fallback; 203 } 204 mask <<= ZAHL_BITS_IN_LAST_CHAR(bit); 205 if (action > 0) { 206 a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] |= mask; 207 return; 208 } else if (action < 0) { 209 a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] ^= mask; 210 } else { 211 a->chars[ZAHL_FLOOR_BITS_TO_CHARS(bit)] &= ~mask; 212 } 213 ZAHL_TRIM_AND_ZERO(a); 214 return; 215 } 216 fallback: 217 #endif 218 219 if (action > 0) 220 zbset_ll_set(a, bit); 221 else if (action < 0) 222 zbset_ll_flip(a, bit); 223 else 224 zbset_ll_clear(a, bit); 225 } 226 227 228 ZAHL_O3 ZAHL_INLINE int 229 zbtest(z_t a, size_t bit) 230 { 231 size_t chars; 232 if (ZAHL_UNLIKELY(zzero(a))) 233 return 0; 234 235 chars = ZAHL_FLOOR_BITS_TO_CHARS(bit); 236 if (ZAHL_UNLIKELY(chars >= a->used)) 237 return 0; 238 239 bit &= ZAHL_BITS_IN_LAST_CHAR(bit); 240 return (a->chars[chars] >> bit) & 1; 241 } 242 243 244 ZAHL_O3 ZAHL_INLINE void 245 zsplit(z_t high, z_t low, z_t a, size_t delim) 246 { 247 if (ZAHL_UNLIKELY(high == a)) { 248 ztrunc(low, a, delim); 249 zrsh(high, a, delim); 250 } else { 251 zrsh(high, a, delim); 252 ztrunc(low, a, delim); 253 } 254 } 255 256 257 ZAHL_INLINE size_t 258 zsave(z_t a, void *buffer) 259 { 260 if (ZAHL_LIKELY(buffer)) { 261 char *buf = buffer; 262 *((long *)buf) = a->sign, buf += sizeof(long); /* Use `long` for alignment. */ 263 *((size_t *)buf) = a->used, buf += sizeof(size_t); 264 if (ZAHL_LIKELY(!zzero(a))) { 265 a->chars[a->used + 2] = 0; 266 a->chars[a->used + 1] = 0; 267 a->chars[a->used + 0] = 0; 268 libzahl_memcpy((zahl_char_t *)buf, a->chars, a->used); 269 } 270 } 271 return sizeof(long) + sizeof(size_t) + 272 (zzero(a) ? 0 :((a->used + 3) & (size_t)~3) * sizeof(zahl_char_t)); 273 } 274 275 276 ZAHL_INLINE void 277 zmul(z_t a, z_t b, z_t c) 278 { 279 int b_sign, c_sign; 280 b_sign = b->sign, b->sign *= b_sign; 281 c_sign = c->sign, c->sign *= c_sign; 282 zmul_ll(a, b, c); 283 c->sign = c_sign; 284 b->sign = b_sign; 285 ZAHL_SET_SIGNUM(a, zsignum(b) * zsignum(c)); 286 } 287 288 289 ZAHL_INLINE void 290 zsqr(z_t a, z_t b) 291 { 292 if (ZAHL_UNLIKELY(zzero(b))) { 293 ZAHL_SET_SIGNUM(a, 0); 294 } else { 295 zsqr_ll(a, b); 296 ZAHL_SET_SIGNUM(a, 1); 297 } 298 } 299 300 301 ZAHL_INLINE void 302 zdiv(z_t a, z_t b, z_t c) 303 { 304 zdivmod(a, libzahl_tmp_div, b, c); 305 } 306 307 308 ZAHL_INLINE void 309 zmod(z_t a, z_t b, z_t c) 310 { 311 zdivmod(libzahl_tmp_mod, a, b, c); 312 }