aboutsummaryrefslogtreecommitdiffstats
path: root/common.h
blob: b299fd19314f33589f831a3437d66a2c9fca007f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* See LICENSE file for copyright and license details. */
#include "libquanta.h"
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>


#define PALETTE_BASE_SIZE       offsetof(struct libquanta_palette, palette)
#define PALETTE_VALUE_TYPE      uint64_t
#define PALETTE_VALUE_SIZE      sizeof(PALETTE_VALUE_TYPE)
#define PALETTE_VALUE_MAX_BITS  64U


struct bigint {
	uintmax_t high, low;
};


#if defined(__GNUC__)
__attribute__((__visibility__("hidden")))
#endif
uintmax_t libquanta_bigint_divmod_small__(struct bigint *big, uintmax_t small);
#define bigint_divmod_small libquanta_bigint_divmod_small__


static inline void
bigint_add_small(struct bigint *big, uintmax_t small)
{
#if defined(__GNUC__)
	if (__builtin_add_overflow(big->low, small, &big->low))
		big->high += 1U;
#else
	if (big->low > UINTMAX_MAX - small)
		big->high += 1U;
	big->low += small;
#endif
}


static inline void
bigint_sub_small(struct bigint *big, uintmax_t small)
{
#if defined(__GNUC__)
	if (__builtin_sub_overflow(big->low, small, &big->low))
		big->high -= 1U;
#else
	if (big->low < small)
		big->high -= 1U;
	big->low -= small;
#endif
}


static inline void
bigint_add_big(struct bigint *res, const struct bigint *restrict other)
{
	bigint_add_small(res, other->low);
	res->high += other->high;
}


static inline void
bigint_sub_big(struct bigint *res, const struct bigint *restrict other)
{
	bigint_sub_small(res, other->low);
	res->high -= other->high;
}


static inline void
bigint_rsub_big(struct bigint *res, const struct bigint *restrict other)
{
	res->high = other->high - res->high;
#if defined(__GNUC__)
	if (__builtin_sub_overflow(other->low, res->low, &res->low))
		res->high -= 1U;
#else
	if (res->low > other->low)
		res->high -= 1U;
	res->low = other->low - res->low;
#endif
}


static inline uintmax_t
bigint_div_small(const struct bigint *big, uintmax_t small)
{
	struct bigint big_copy = *big;
	return bigint_divmod_small(&big_copy, small);
}