File: bigint.h

package info (click to toggle)
mruby 3.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,584 kB
  • sloc: ansic: 51,933; ruby: 29,510; yacc: 7,077; cpp: 517; makefile: 51; sh: 42
file content (121 lines) | stat: -rw-r--r-- 3,798 bytes parent folder | download
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
** @file mruby/bigint.h - Multi-precision Integer
**
** See Copyright Notice in mruby.h
*/

#ifndef MRUBY_BIGINT_H
#define MRUBY_BIGINT_H
/*
 * FREE GMP - a public domain implementation of a subset of the
 *           gmp library
 *
 * I hereby place the file in the public domain.
 *
 * Do whatever you want with this code. Change it. Sell it. Claim you
 *  wrote it.
 * Bugs, complaints, flames, rants: please send email to
 *    Mark Henderson <markh@wimsey.bc.ca>
 * I'm already aware that fgmp is considerably slower than gmp
 *
 * CREDITS:
 *  Paul Rouse <par@r-cube.demon.co.uk> - generic bug fixes, mpz_sqrt and
 *    mpz_sqrtrem, and modifications to get fgmp to compile on a system
 *    with int and long of different sizes (specifically MS-DOS,286 compiler)
 *  Also see the file "notes" included with the fgmp distribution, for
 *    more credits.
 *
 * VERSION 1.0 - beta 5
 */

#include <sys/types.h>

#if defined(MRB_INT32) && defined(_WIN32) && !defined(MRB_NO_MPZ64BIT)
#define MRB_NO_MPZ64BIT
#endif

#ifdef MRB_NO_MPZ64BIT
typedef uint16_t mp_limb;
typedef uint32_t mp_dbl_limb;
typedef int32_t mp_dbl_limb_signed;
#define MPZ_DIG_SIZE 16
#else
typedef uint32_t mp_limb;
typedef uint64_t mp_dbl_limb;
typedef int64_t mp_dbl_limb_signed;
#define MPZ_DIG_SIZE 32
#endif

#define RBIGINT_EMBED_SIZE_MAX ((sizeof(void*) * 3) / sizeof(mp_limb))

typedef struct _mpz_t {
  mp_limb *p;
  short sn;
  size_t sz;
} mpz_t;

struct RBigint {
  MRB_OBJECT_HEADER;
  union {
    mpz_t heap;
    mp_limb ary[RBIGINT_EMBED_SIZE_MAX];
  } as;
};
#define RBIGINT(v) ((struct RBigint*)mrb_ptr(v))

/*
 *  flags of struct RBigint
 *
 *  6..:  UNUSED
 *  4..5: sign flags
 *        00: negative  (<--> -1)
 *        01: zero      (<-->  0)
 *        10: positive  (<--> +1)
 *        11: UNUSED
 *  0..3: size of embedded array; 15 means used with heap
 */

#define RBIGINT_EMBED_SIZE_MASK 0x0f
#define RBIGINT_EMBED_SIZE_OVER RBIGINT_EMBED_SIZE_MASK
#define RBIGINT_EMBED_SIZE_SHIFT 0
#define RBIGINT_EMBED_SIGN_MASK 0x03
#define RBIGINT_EMBED_SIGN_SHIFT 4

#define RBIGINT_ARY(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_ARY(m) : RBIGINT_HEAP_ARY(m))
#define RBIGINT_SIGN(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_SIGN(m) : RBIGINT_HEAP_SIGN(m))
#define RBIGINT_SIZE(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_SIZE(m) : RBIGINT_HEAP_SIZE(m))

#define RBIGINT_HEAP_ARY(m) ((m)->as.heap.p)
#define RBIGINT_HEAP_SIGN(m) ((m)->as.heap.sn)
#define RBIGINT_HEAP_SIZE(m) ((m)->as.heap.sz)
#define RBIGINT_SET_HEAP(m) do { \
  (m)->flags |= RBIGINT_EMBED_SIZE_OVER << RBIGINT_EMBED_SIZE_SHIFT; \
} while (0)
#define RBIGINT_SET_HEAP_SIGN(m, s) do { \
  (m)->as.heap.sn = (s); \
} while (0)
#define RBIGINT_SET_HEAP_SIZE(m, s) do { \
  (m)->as.heap.sz = (s); \
} while (0)

#define RBIGINT_EMBED_P(m) ((((m)->flags >> RBIGINT_EMBED_SIZE_SHIFT) & RBIGINT_EMBED_SIZE_MASK) < RBIGINT_EMBED_SIZE_OVER)
#define RBIGINT_EMBED_ARY(m) ((m)->as.ary)
#define RBIGINT_EMBED_SIGN(m) ((short)(((m)->flags >> RBIGINT_EMBED_SIGN_SHIFT) & RBIGINT_EMBED_SIGN_MASK) - 1)
#define RBIGINT_EMBED_SIZE(m) (size_t)(((m)->flags >> RBIGINT_EMBED_SIZE_SHIFT) & RBIGINT_EMBED_SIZE_MASK)
#define RBIGINT_SET_EMBED_ZERO(m) do { \
  (m)->flags &= ~(RBIGINT_EMBED_SIZE_MASK << RBIGINT_EMBED_SIZE_SHIFT); \
} while (0)
#define RBIGINT_SET_EMBED_SIGN(m, s) do { \
  (m)->flags = ((((s) + 1) & RBIGINT_EMBED_SIGN_MASK) << RBIGINT_EMBED_SIGN_SHIFT) | \
               ((m)->flags & ~(RBIGINT_EMBED_SIGN_MASK << RBIGINT_EMBED_SIGN_SHIFT)); \
} while (0)
#define RBIGINT_SET_EMBED_SIZE(m, s) do { \
  size_t s_tmp = (s); \
  mrb_assert((s_tmp) <= RBIGINT_EMBED_SIZE_MAX); \
  RBIGINT_SET_EMBED_ZERO(m); \
  (m)->flags |= (s_tmp) << RBIGINT_EMBED_SIZE_SHIFT; \
} while (0)

mrb_static_assert_object_size(struct RBigint);

#endif  /* MRUBY_BIGINT_H */