aboutsummaryrefslogtreecommitdiffstats
path: root/spec/rubyspec/optional/capi/ext/bignum_spec.c
blob: ab3b36eadcea1c0e0c7f1e326b756e5f5df42b09 (plain)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "ruby.h"
#include "rubyspec.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef HAVE_RB_BIG2DBL
static VALUE bignum_spec_rb_big2dbl(VALUE self, VALUE num) {
  return rb_float_new(rb_big2dbl(num));
}
#endif

#ifdef HAVE_RB_DBL2BIG
static VALUE bignum_spec_rb_dbl2big(VALUE self, VALUE num) {
  double dnum = NUM2DBL(num);

  return rb_dbl2big(dnum);
}
#endif

#ifdef HAVE_RB_BIG2LL
static VALUE bignum_spec_rb_big2ll(VALUE self, VALUE num) {
  return rb_ll2inum(rb_big2ll(num));
}
#endif

#ifdef HAVE_RB_BIG2LONG
static VALUE bignum_spec_rb_big2long(VALUE self, VALUE num) {
  return LONG2NUM(rb_big2long(num));
}
#endif

#ifdef HAVE_RB_BIG2STR
static VALUE bignum_spec_rb_big2str(VALUE self, VALUE num, VALUE base) {
  return rb_big2str(num, FIX2INT(base));
}
#endif

#ifdef HAVE_RB_BIG2ULONG
static VALUE bignum_spec_rb_big2ulong(VALUE self, VALUE num) {
  return ULONG2NUM(rb_big2ulong(num));
}
#endif

#ifdef HAVE_RB_BIG_CMP
static VALUE bignum_spec_rb_big_cmp(VALUE self, VALUE x, VALUE y) {
  return rb_big_cmp(x, y);
}
#endif

#ifdef HAVE_RB_BIG_PACK
static VALUE bignum_spec_rb_big_pack(VALUE self, VALUE val) {
  unsigned long buff;

  rb_big_pack(val, &buff, 1);

  return ULONG2NUM(buff);
}
#endif

#if HAVE_ABSINT_SIZE
static VALUE bignum_spec_rb_big_pack_length(VALUE self, VALUE val) {
  long long_len;
  int leading_bits = 0;
  int divisor = SIZEOF_LONG;
  size_t len = rb_absint_size(val, &leading_bits);
  if (leading_bits == 0) {
    len += 1;
  }

  long_len = len / divisor + ((len % divisor == 0) ? 0 : 1);
  return LONG2NUM(long_len);
}
#endif

#ifdef HAVE_RB_BIG_PACK
static VALUE bignum_spec_rb_big_pack_array(VALUE self, VALUE val, VALUE len) {
  int i;
  long long_len = NUM2LONG(len);

  VALUE ary = rb_ary_new_capa(long_len);
  unsigned long *buf = malloc(long_len * SIZEOF_LONG);

  /* The array should be filled with recognisable junk so we can check
     it is all cleared properly. */

  for (i = 0; i < long_len; i++) {
#if SIZEOF_LONG == 8
    buf[i] = 0xfedcba9876543210L;
#else
    buf[i] = 0xfedcba98L;
#endif
  }

  rb_big_pack(val, buf, long_len);
  for (i = 0; i < long_len; i++) {
    rb_ary_store(ary, i, ULONG2NUM(buf[i]));
  }
  free(buf);
  return ary;
}
#endif

void Init_bignum_spec(void) {
  VALUE cls;
  cls = rb_define_class("CApiBignumSpecs", rb_cObject);

#ifdef HAVE_RB_BIG2DBL
  rb_define_method(cls, "rb_big2dbl", bignum_spec_rb_big2dbl, 1);
#endif

#ifdef HAVE_RB_DBL2BIG
  rb_define_method(cls, "rb_dbl2big", bignum_spec_rb_dbl2big, 1);
#endif

#ifdef HAVE_RB_BIG2LL
  rb_define_method(cls, "rb_big2ll", bignum_spec_rb_big2ll, 1);
#endif

#ifdef HAVE_RB_BIG2LONG
  rb_define_method(cls, "rb_big2long", bignum_spec_rb_big2long, 1);
#endif

#ifdef HAVE_RB_BIG2STR
  rb_define_method(cls, "rb_big2str", bignum_spec_rb_big2str, 2);
#endif

#ifdef HAVE_RB_BIG2ULONG
  rb_define_method(cls, "rb_big2ulong", bignum_spec_rb_big2ulong, 1);
#endif

#ifdef HAVE_RB_BIG_CMP
  rb_define_method(cls, "rb_big_cmp", bignum_spec_rb_big_cmp, 2);
#endif

#ifdef HAVE_RB_BIG_PACK
  rb_define_method(cls, "rb_big_pack", bignum_spec_rb_big_pack, 1);
  rb_define_method(cls, "rb_big_pack_array", bignum_spec_rb_big_pack_array, 2);
#endif

#ifdef HAVE_ABSINT_SIZE
  rb_define_method(cls, "rb_big_pack_length", bignum_spec_rb_big_pack_length, 1);
#endif
}

#ifdef __cplusplus
extern "C" {
#endif