Ruby: include/ruby/internal/arithmetic/long.h Source File

Ruby 3.4.4p34 (2025-05-14 revision a38531fd3f617bf734ef7d6c595325f69985ea1d)

long.h
Go to the documentation of this file.
1#ifndef RBIMPL_ARITHMETIC_LONG_H /*-*-C++-*-vi:se ft=cpp:*/
2#define RBIMPL_ARITHMETIC_LONG_H
31#include "ruby/internal/config.h"
32#include "ruby/internal/arithmetic/fixnum.h" /* FIXABLE */
33#include "ruby/internal/arithmetic/intptr_t.h" /* rb_int2big etc.*/
34#include "ruby/internal/assume.h"
35#include "ruby/internal/attr/artificial.h"
36#include "ruby/internal/attr/cold.h"
37#include "ruby/internal/attr/const.h"
38#include "ruby/internal/attr/constexpr.h"
39#include "ruby/internal/attr/noreturn.h"
40#include "ruby/internal/cast.h"
41#include "ruby/internal/dllexport.h"
42#include "ruby/internal/special_consts.h" /* FIXNUM_FLAG */
43#include "ruby/internal/value.h"
44#include "ruby/assert.h"
45
46#define FIX2LONG RB_FIX2LONG
47#define FIX2ULONG RB_FIX2ULONG
48#define INT2FIX RB_INT2FIX
49#define LONG2FIX RB_INT2FIX
50#define LONG2NUM RB_LONG2NUM
51#define NUM2LONG RB_NUM2LONG
52#define NUM2ULONG RB_NUM2ULONG
53#define RB_FIX2LONG rb_fix2long
54#define RB_FIX2ULONG rb_fix2ulong
55#define RB_LONG2FIX RB_INT2FIX
56#define RB_LONG2NUM rb_long2num_inline
57#define RB_NUM2LONG rb_num2long_inline
58#define RB_NUM2ULONG rb_num2ulong_inline
59#define RB_ULONG2NUM rb_ulong2num_inline
60#define ULONG2NUM RB_ULONG2NUM
61#define rb_fix_new RB_INT2FIX
62#define rb_long2int rb_long2int_inline
63
65#define RB_INT2FIX RB_INT2FIX
67
68 RBIMPL_SYMBOL_EXPORT_BEGIN()
69
70 RBIMPL_ATTR_NORETURN()
71 RBIMPL_ATTR_COLD()
78void rb_out_of_int(SIGNED_VALUE num);
79
88long rb_num2long(VALUE num);
89
98unsigned long rb_num2ulong(VALUE num);
99 RBIMPL_SYMBOL_EXPORT_END()
100
101 RBIMPL_ATTR_CONST_UNLESS_DEBUG()
102 RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
103 RBIMPL_ATTR_ARTIFICIAL()
110static inline VALUE
111RB_INT2FIX(long i)
112{
113 RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(i));
114
115 /* :NOTE: VALUE can be wider than long. As j being unsigned, 2j+1 is fully
116 * defined. Also it can be compiled into a single LEA instruction. */
117 const unsigned long j = RBIMPL_CAST((unsigned long)i);
118 const unsigned long k = (j << 1) + RUBY_FIXNUM_FLAG;
119 const long l = RBIMPL_CAST((long)k);
120 const SIGNED_VALUE m = l; /* Sign extend */
121 const VALUE n = RBIMPL_CAST((VALUE)m);
122
123 RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(n));
124 return n;
125}
126
134static inline int
135rb_long2int_inline(long n)
136{
137 int i = RBIMPL_CAST((int)n);
138
139 if /* constexpr */ (sizeof(long) <= sizeof(int)) {
140 RBIMPL_ASSUME(i == n);
141 }
142
143 if (i != n)
144 rb_out_of_int(n);
145
146 return i;
147}
148
149 RBIMPL_ATTR_CONST_UNLESS_DEBUG()
150 RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
161static inline long
162rbimpl_fix2long_by_idiv(VALUE x)
163{
164 RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
165
166 /* :NOTE: VALUE can be wider than long. (x-1)/2 never overflows because
167 * RB_FIXNUM_P(x) holds. Also it has no portability issue like y>>1
168 * below. */
169 const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)(x - RUBY_FIXNUM_FLAG));
170 const SIGNED_VALUE z = y / 2;
171 const long w = RBIMPL_CAST((long)z);
172
173 RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(w));
174 return w;
175}
176
177 RBIMPL_ATTR_CONST_UNLESS_DEBUG()
178 RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
189static inline long
190rbimpl_fix2long_by_shift(VALUE x)
191{
192 RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
193
194 /* :NOTE: VALUE can be wider than long. If right shift is arithmetic, this
195 * is noticeably faster than above. */
196 const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)x);
197 const SIGNED_VALUE z = y >> 1;
198 const long w = RBIMPL_CAST((long)z);
199
200 RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(w));
201 return w;
202}
203
204 RBIMPL_ATTR_CONST()
205 RBIMPL_ATTR_CONSTEXPR(CXX11)
215static inline bool
216rbimpl_right_shift_is_arithmetic_p(void)
217{
218 return (-1 >> 1) == -1;
219}
220
221 RBIMPL_ATTR_CONST_UNLESS_DEBUG()
222 RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
230static inline long
231rb_fix2long(VALUE x)
232{
233 if /* constexpr */ (rbimpl_right_shift_is_arithmetic_p()) {
234 return rbimpl_fix2long_by_shift(x);
235 }
236 else {
237 return rbimpl_fix2long_by_idiv(x);
238 }
239}
240
241 RBIMPL_ATTR_CONST_UNLESS_DEBUG()
242 RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(CXX14)
251static inline unsigned long
252rb_fix2ulong(VALUE x)
253{
254 RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
255 return RBIMPL_CAST((unsigned long)rb_fix2long(x));
256}
257
266static inline long
267rb_num2long_inline(VALUE x)
268{
269 if (RB_FIXNUM_P(x))
270 return RB_FIX2LONG(x);
271 else
272 return rb_num2long(x);
273}
274
292static inline unsigned long
293rb_num2ulong_inline(VALUE x)
294{
295 if (RB_FIXNUM_P(x))
296 return RB_FIX2ULONG(x);
297 else
298 return rb_num2ulong(x);
299}
300
307static inline VALUE
308rb_long2num_inline(long v)
309{
310 if (RB_FIXABLE(v))
311 return RB_LONG2FIX(v);
312 else
313 return rb_int2big(v);
314}
315
322static inline VALUE
323rb_ulong2num_inline(unsigned long v)
324{
325 if (RB_POSFIXABLE(v))
326 return RB_LONG2FIX(RBIMPL_CAST((long)v));
327 else
328 return rb_uint2big(v);
329}
330
339#if RBIMPL_HAS_ATTR_CONSTEXPR_CXX14
340# /* C++ can write constexpr as enum values. */
341
342#elif ! defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
343# undef INT2FIX
344# define INT2FIX(i) (RBIMPL_CAST((VALUE)(i)) << 1 | RUBY_FIXNUM_FLAG)
345
346#else
347# undef INT2FIX
348# define INT2FIX(i) \
349 __builtin_choose_expr( \
350 __builtin_constant_p(i), \
351 RBIMPL_CAST((VALUE)(i)) << 1 | RUBY_FIXNUM_FLAG, \
352 RB_INT2FIX(i))
353#endif
355
356#endif /* RBIMPL_ARITHMETIC_LONG_H */
artificial.h
Defines RBIMPL_ATTR_ARTIFICIAL.
RBIMPL_ATTR_ARTIFICIAL
#define RBIMPL_ATTR_ARTIFICIAL()
Wraps (or simulates) __attribute__((artificial))
Definition artificial.h:43
assert.h
RBIMPL_ASSERT_OR_ASSUME
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:311
cold.h
Defines RBIMPL_ATTR_COLD.
RBIMPL_ATTR_COLD
#define RBIMPL_ATTR_COLD()
Wraps (or simulates) __attribute__((cold))
Definition cold.h:34
const.h
Defines RBIMPL_ATTR_CONST.
RBIMPL_ATTR_CONST
#define RBIMPL_ATTR_CONST()
Wraps (or simulates) __attribute__((const))
Definition const.h:36
RBIMPL_ATTR_CONST_UNLESS_DEBUG
#define RBIMPL_ATTR_CONST_UNLESS_DEBUG()
Enables RBIMPL_ATTR_CONST if and only if.
Definition const.h:41
constexpr.h
RBIMPL_ATTR_CONSTEXPR.
RBIMPL_ATTR_CONSTEXPR
#define RBIMPL_ATTR_CONSTEXPR(_)
Wraps (or simulates) C++11 constexpr.
Definition constexpr.h:74
RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG
#define RBIMPL_ATTR_CONSTEXPR_UNLESS_DEBUG(_)
Enables RBIMPL_ATTR_CONSTEXPR if and only if.
Definition constexpr.h:79
dllexport.h
Tweaking visibility of C variables/functions.
RBIMPL_SYMBOL_EXPORT_END
#define RBIMPL_SYMBOL_EXPORT_END()
Counterpart of RBIMPL_SYMBOL_EXPORT_BEGIN.
Definition dllexport.h:74
RBIMPL_SYMBOL_EXPORT_BEGIN
#define RBIMPL_SYMBOL_EXPORT_BEGIN()
Shortcut macro equivalent to RUBY_SYMBOL_EXPORT_BEGIN extern "C" {.
Definition dllexport.h:65
fixnum.h
Handling of integers formerly known as Fixnums.
RB_FIXABLE
#define RB_FIXABLE(_)
Checks if the passed value is in range of fixnum.
Definition fixnum.h:52
RB_POSFIXABLE
#define RB_POSFIXABLE(_)
Checks if the passed value is in range of fixnum, assuming it is a positive number.
Definition fixnum.h:43
assume.h
Defines RBIMPL_ASSUME / RBIMPL_UNREACHABLE.
RBIMPL_ASSUME
#define RBIMPL_ASSUME(_)
Wraps (or simulates) __builtin_unreachable.
Definition assume.h:76
intptr_t.h
Arithmetic conversion between C's intptr_t and Ruby's.
rb_num2long_inline
static long rb_num2long_inline(VALUE x)
Converts an instance of rb_cNumeric into C's long.
Definition long.h:267
RB_INT2FIX
static VALUE RB_INT2FIX(long i)
Converts a C's long into an instance of rb_cInteger.
Definition long.h:111
RB_FIX2ULONG
#define RB_FIX2ULONG
Just another name of rb_fix2ulong.
Definition long.h:54
rb_num2ulong_inline
static unsigned long rb_num2ulong_inline(VALUE x)
Converts an instance of rb_cNumeric into C's unsigned long.
Definition long.h:293
rb_long2int_inline
static int rb_long2int_inline(long n)
Checks if int can hold the given integer.
Definition long.h:135
rb_ulong2num_inline
static VALUE rb_ulong2num_inline(unsigned long v)
Converts a C's unsigned long into an instance of rb_cInteger.
Definition long.h:323
rb_fix2long
static long rb_fix2long(VALUE x)
Converts a Fixnum into C's long.
Definition long.h:231
RB_FIX2LONG
#define RB_FIX2LONG
Just another name of rb_fix2long.
Definition long.h:53
rb_out_of_int
void rb_out_of_int(SIGNED_VALUE num)
This is an utility function to raise an rb_eRangeError.
Definition numeric.c:3271
rb_num2long
long rb_num2long(VALUE num)
Converts an instance of rb_cNumeric into C's long.
Definition numeric.c:3196
RB_LONG2FIX
#define RB_LONG2FIX
Just another name of RB_INT2FIX.
Definition long.h:55
rb_num2ulong
unsigned long rb_num2ulong(VALUE num)
Converts an instance of rb_cNumeric into C's unsigned long.
Definition numeric.c:3265
rb_long2num_inline
static VALUE rb_long2num_inline(long v)
Converts a C's long into an instance of rb_cInteger.
Definition long.h:308
rb_fix2ulong
static unsigned long rb_fix2ulong(VALUE x)
Converts a Fixnum into C's unsigned long.
Definition long.h:252
noreturn.h
Defines RBIMPL_ATTR_NORETURN.
RBIMPL_ATTR_NORETURN
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
inline
#define inline
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
Definition defines.h:88
special_consts.h
Defines enum ruby_special_consts.
RB_FIXNUM_P
static bool RB_FIXNUM_P(VALUE obj)
Checks if the given object is a so-called Fixnum.
Definition special_consts.h:247
RUBY_FIXNUM_FLAG
@ RUBY_FIXNUM_FLAG
Flag to denote a fixnum.
Definition special_consts.h:93
value.h
Defines VALUE and ID.
SIGNED_VALUE
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40