Mini Shell
#ifndef RBIMPL_INTERN_BIGNUM_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_BIGNUM_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Public APIs related to so-called rb_cBignum.
*/
#include "ruby/internal/config.h"
#ifdef STDC_HEADERS
# include <stddef.h>
#endif
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
#include "ruby/backward/2/long_long.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
/* bignum.c */
/**
* Allocates a bignum object.
*
* @param[in] len Length of the bignum's backend storage, in words.
* @param[in] sign Sign of the bignum.
* @return An allocated new bignum instance.
* @note This only allocates an object, doesn't fill its value in.
*
* @internal
*
* @shyouhei finds it hard to use from extension libraries. `len` is per
* `BDIGIT` but its definition is hidden.
*/
VALUE rb_big_new(size_t len, int sign);
/**
* Queries if the passed bignum instance is a "bigzro". What is a bigzero?
* Well, bignums are for very big integers, but can also represent tiny ones
* like -1, 0, 1. Bigzero are instances of bignums whose values are zero.
* Knowing if a bignum is bigzero can be handy on occasions, like for instance
* detecting division by zero situation.
*
* @param[in] x A bignum.
* @retval 1 It is a bigzero.
* @retval 0 Otherwise.
*/
int rb_bigzero_p(VALUE x);
/**
* Duplicates the given bignum.
*
* @param[in] num A bignum.
* @return An allocated bignum, who is equivalent to `num`.
*/
VALUE rb_big_clone(VALUE num);
/**
* Destructively modify the passed bignum into 2's complement representation.
*
* @note By default bignums are in signed magnitude system.
*
* @param[out] num A bignum to modify.
*/
void rb_big_2comp(VALUE num);
/**
* Normalises the passed bignum. It for instance returns a fixnum of the same
* value if fixnum can represent that number.
*
* @param[out] x Target bignum (can be destructively modified).
* @return An integer of the identical value (can be `x` itself).
*/
VALUE rb_big_norm(VALUE x);
/**
* Destructively resizes the backend storage of the passed bignum.
*
* @param[out] big A bignum.
* @param[in] len New length of `big`'s backend, in words.
*/
void rb_big_resize(VALUE big, size_t len);
RBIMPL_ATTR_NONNULL(())
/**
* Parses C's string to convert into a Ruby's integer. It understands prefixes
* (e.g. `0x`) and underscores.
*
* @param[in] str Stringised representation of the return value.
* @param[in] base Base of conversion. Must be `-36..36` inclusive,
* except `1`. `2..36` means the conversion is done
* according to it, with unmatched prefix understood
* as a part of the result. `-36..-2` means the
* conversion honours prefix when present, or use
* `-base` when absent. `0` is equivalent to `-10`.
* `-1` mandates a prefix. `1` is an error.
* @param[in] badcheck Whether to raise ::rb_eArgError on failure. If
* `0` is passed here this function can return
* `INT2FIX(0)` for parse errors.
* @exception rb_eArgError Failed to parse (and `badcheck` is truthy).
* @return An instance of ::rb_cInteger, which is a numeric interpretation
* of what is written in `str`.
*
* @internal
*
* Not sure if it intentionally accepts `base == -1` or is just buggy. Nobody
* practically uses negative bases these days.
*/
VALUE rb_cstr_to_inum(const char *str, int base, int badcheck);
/**
* Identical to rb_cstr2inum(), except it takes Ruby's strings instead of C's.
*
* @param[in] str Stringised representation of the return
* value.
* @param[in] base Base of conversion. Must be `-36..36`
* inclusive, except `1`. `2..36` means the
* conversion is done according to it, with
* unmatched prefix understood as a part of the
* result. `-36..-2` means the conversion
* honours prefix when present, or use `-base`
* when absent. `0` is equivalent to `-10`.
* `-1` mandates a prefix. `1` is an error.
* @param[in] badcheck Whether to raise ::rb_eArgError on failure.
* If `0` is passed here this function can
* return `INT2FIX(0)` for parse errors.
* @exception rb_eArgError Failed to parse (and `badcheck` is truthy).
* @exception rb_eTypeError `str` is not a string.
* @exception rb_eEncCompatError `str` is not ASCII compatible.
* @return An instance of ::rb_cInteger, which is a numeric interpretation
* of what is written in `str`.
*/
VALUE rb_str_to_inum(VALUE str, int base, int badcheck);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_cstr_to_inum(), except the second argument controls the base
* and badcheck at once. It basically doesn't raise for parse errors, unless
* the base is zero.
*
* This is an older API. New codes might prefer rb_cstr_to_inum().
*
* @param[in] str Stringised representation of the return value.
* @param[in] base Base of conversion. Must be `-36..36` inclusive,
* except `1`. `2..36` means the conversion is done
* according to it, with unmatched prefix understood
* as a part of the result. `-36..-2` means the
* conversion honours prefix when present, or use
* `-base` when absent. `0` is equivalent to `-10`.
* `-1` mandates a prefix. `1` is an error.
* @exception rb_eArgError Failed to parse (and `base` is zero).
* @return An instance of ::rb_cInteger, which is a numeric interpretation
* of what is written in `str`.
*/
VALUE rb_cstr2inum(const char *str, int base);
/**
* Identical to rb_str_to_inum(), except the second argument controls the base
* and badcheck at once. It can also be seen as a routine identical to
* rb_cstr2inum(), except it takes Ruby's strings instead of C's.
*
* This is an older API. New codes might prefer rb_cstr_to_inum().
*
* @param[in] str Stringised representation of the return
* value.
* @param[in] base Base of conversion. Must be `-36..36`
* inclusive, except `1`. `2..36` means the
* conversion is done according to it, with
* unmatched prefix understood as a part of the
* result. `-36..-2` means the conversion
* honours prefix when present, or use `-base`
* when absent. `0` is equivalent to `-10`.
* `-1` mandates a prefix. `1` is an error.
* @exception rb_eArgError Failed to parse (and `base` is zero).
* @exception rb_eTypeError `str` is not a string.
* @exception rb_eEncCompatError `str` is not ASCII compatible.
* @return An instance of ::rb_cInteger, which is a numeric interpretation
* of what is written in `str`.
*/
VALUE rb_str2inum(VALUE str, int base);
/**
* Generates a place-value representation of the passed integer.
*
* @param[in] x An integer to stringify.
* @param[in] base `2` to `36` inclusive for each radix.
* @exception rb_eArgError `base` is out of range.
* @exception rb_eRangeError `x` is too big, cannot represent in string.
* @return An instance of ::rb_cString which represents `x`.
*/
VALUE rb_big2str(VALUE x, int base);
/**
* Converts a bignum into C's `long`.
*
* @param[in] x A bignum.
* @exception rb_eRangeError `x` is out of range of `long`.
* @return The passed value converted into C's `long`.
*/
long rb_big2long(VALUE x);
/** @alias{rb_big2long} */
#define rb_big2int(x) rb_big2long(x)
/**
* Converts a bignum into C's `unsigned long`.
*
* @param[in] x A bignum.
* @exception rb_eRangeError `x` is out of range of `unsigned long`.
* @return The passed value converted into C's `unsigned long`.
*
* @internal
*
* This function can generate a very large positive integer for a negative
* input. For instance applying Ruby's -4,611,686,018,427,387,905 to this
* function yields C's 13,835,058,055,282,163,711 on my machine. This is how
* it has been. Cannot change any longer.
*/
unsigned long rb_big2ulong(VALUE x);
/** @alias{rb_big2long} */
#define rb_big2uint(x) rb_big2ulong(x)
#if HAVE_LONG_LONG
/**
* Converts a bignum into C's `long long`.
*
* @param[in] x A bignum.
* @exception rb_eRangeError `x` is out of range of `long long`.
* @return The passed value converted into C's `long long`.
*/
LONG_LONG rb_big2ll(VALUE);
/**
* Converts a bignum into C's `unsigned long long`.
*
* @param[in] x A bignum.
* @exception rb_eRangeError `x` is out of range of `unsigned long long`.
* @return The passed value converted into C's `unsigned long long`.
*
* @internal
*
* This function can generate a very large positive integer for a negative
* input. For instance applying Ruby's -4,611,686,018,427,387,905 to this
* function yields C's 13,835,058,055,282,163,711 on my machine. This is how
* it has been. Cannot change any longer.
*/
unsigned LONG_LONG rb_big2ull(VALUE);
#endif /* HAVE_LONG_LONG */
RBIMPL_ATTR_NONNULL(())
/**
* Converts a bignum into a series of its parts.
*
* @param[in] val An integer.
* @param[out] buf Return buffer.
* @param[in] num_longs Number of words of `buf`.
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @post `buf` is filled with `val`'s 2's complement representation, in
* the host CPU's native byte order, from least significant word
* towards the most significant one, for `num_longs` words.
* @note The "pack" terminology comes from `Array#pack`.
*/
void rb_big_pack(VALUE val, unsigned long *buf, long num_longs);
RBIMPL_ATTR_NONNULL(())
/**
* Constructs a (possibly very big) bignum from a series of integers. `buf[0]`
* would be the return value's least significant word; `buf[num_longs-1]` would
* be that of most significant.
*
* @param[in] buf A series of integers.
* @param[in] num_longs Number of words of `buf`.
* @exception rb_eArgError Result would be too big.
* @return An instance of ::rb_cInteger which is an "unpack"-ed value of
* the parameters.
* @note The "unpack" terminology comes from `String#pack`.
*/
VALUE rb_big_unpack(unsigned long *buf, long num_longs);
/* pack.c */
RBIMPL_ATTR_NONNULL(())
/**
* Encodes a Unicode codepoint into its UTF-8 representation.
*
* @param[out] buf Return buffer, must at least be 6 bytes width.
* @param[in] uv An Unicode codepoint.
* @exception rb_eRangeError `uv` is out of Unicode.
* @return Number of bytes written to `buf`
* @post `buf` holds a UTF-8 representation of `uv`.
*/
int rb_uv_to_utf8(char buf[6], unsigned long uv);
/* bignum.c */
/**
* Converts a C's `double` into a bignum.
*
* @param[in] d A value to convert.
* @exception rb_eFloatDomainError `d` is Inf/NaN.
* @return An instance of ::rb_cInteger whose value is approximately `d`.
*
* @internal
*
* @shyouhei is not sure if the result is guaranteed to be the nearest integer
* of `d`.
*/
VALUE rb_dbl2big(double d);
/**
* Converts a bignum into C's `double`.
*
* @param[in] x A bignum.
* @return The passed value converted into C's `double`.
*
* @internal
*
* @shyouhei is not sure if the result is guaranteed to be `x`'s nearest value
* that a `double` can represent.
*/
double rb_big2dbl(VALUE x);
/**
* Compares the passed two bignums.
*
* @param[in] lhs Comparison LHS.
* @param[in] rhs Comparison RHS.
* @retval -1 `rhs` is bigger than `lhs`.
* @retval 0 They are identical.
* @retval 1 `lhs` is bigger than `rhs`.
* @see rb_num_coerce_cmp()
*/
VALUE rb_big_cmp(VALUE lhs, VALUE rhs);
/**
* Equality, in terms of `==`. This checks if the _value_ is the same, not the
* identity. For instance `1 == 1.0` must hold.
*
* @param[in] lhs Comparison LHS.
* @param[in] rhs Comparison RHS.
* @retval RUBY_Qtrue They are the same.
* @retval RUBY_Qfalse They are different.
*/
VALUE rb_big_eq(VALUE lhs, VALUE rhs);
/**
* Equality, in terms of `eql?`. Unlike rb_big_eq() it does not convert
* ::rb_cFloat etc. This function returns ::RUBY_Qtrue if and only if both
* parameters are bignums, which represent the identical numerical value.
*
* @param[in] lhs Comparison LHS.
* @param[in] rhs Comparison RHS.
* @retval RUBY_Qtrue They are identical.
* @retval RUBY_Qfalse They are distinct.
*/
VALUE rb_big_eql(VALUE lhs, VALUE rhs);
/**
* Performs addition of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x + y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_plus(VALUE x, VALUE y);
/**
* Performs subtraction of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x - y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_minus(VALUE x, VALUE y);
/**
* Performs multiplication of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x * y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_mul(VALUE x, VALUE y);
/**
* Performs division of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x / y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_div(VALUE x, VALUE y);
/**
* Performs "integer division". This is different from rb_big_div().
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x.div y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_idiv(VALUE x, VALUE y);
/**
* Performs modulo of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x % y` evaluates to.
* @see rb_num_coerce_bin()
*
* @internal
*
* There also is `rb_big_remainder()` internally, which is different from this
* one.
*/
VALUE rb_big_modulo(VALUE x, VALUE y);
/**
* Performs "divmod" operation. The operation in bignum's context is that it
* calculates rb_big_idiv() and rb_big_modulo() at once.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x.divmod y` evaluates to.
* @see rb_num_coerce_bin()
*/
VALUE rb_big_divmod(VALUE x, VALUE y);
/**
* Raises `x` to the powerof `y`.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x ** y` evaluates to.
* @see rb_num_coerce_bin()
* @note This can return an instance of ::rb_cFloat, even when both `x`
* and `y` are bignums. Or an instance of ::rb_cRational, when for
* instance `y` is negative.
*/
VALUE rb_big_pow(VALUE x, VALUE y);
/**
* Performs bitwise and of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x & y` evaluates to.
* @see rb_num_coerce_bit()
*/
VALUE rb_big_and(VALUE x, VALUE y);
/**
* Performs bitwise or of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x | y` evaluates to.
* @see rb_num_coerce_bit()
*/
VALUE rb_big_or(VALUE x, VALUE y);
/**
* Performs exclusive or of the passed two objects.
*
* @param[in] x A bignum.
* @param[in] y Arbitrary ruby object.
* @return What `x ^ y` evaluates to.
* @see rb_num_coerce_bit()
*/
VALUE rb_big_xor(VALUE x, VALUE y);
/**
* Performs shift left.
*
* @param[in] x A bignum.
* @param[in] y Shift amount.
* @exception rb_eTypeError `y` is not an integer.
* @exception rb_eArgError `y` is too big.
* @return `x` shifted left to `y` bits.
* @note `y` can be negative. Shifts right then.
*/
VALUE rb_big_lshift(VALUE x, VALUE y);
/**
* Performs shift right.
*
* @param[in] x A bignum.
* @param[in] y Shift amount.
* @exception rb_eTypeError `y` is not an integer.
* @return `x` shifted right to `y` bits.
* @note This is arithmetic. Because bignums are not bitfields there is
* no shift right logical operator.
*/
VALUE rb_big_rshift(VALUE x, VALUE y);
/**
* @name Flags for rb_integer_pack()/rb_integer_unpack()
* @{
*/
/** Stores/interprets the most significant word as the first word. */
#define INTEGER_PACK_MSWORD_FIRST 0x01
/** Stores/interprets the least significant word as the first word. */
#define INTEGER_PACK_LSWORD_FIRST 0x02
/**
* Stores/interprets the most significant byte in a word as the first byte in
* the word.
*/
#define INTEGER_PACK_MSBYTE_FIRST 0x10
/**
* Stores/interprets the least significant byte in a word as the first byte in
* the word.
*/
#define INTEGER_PACK_LSBYTE_FIRST 0x20
/**
* Means either #INTEGER_PACK_MSBYTE_FIRST or #INTEGER_PACK_LSBYTE_FIRST,
* depending on the host processor's endian.
*/
#define INTEGER_PACK_NATIVE_BYTE_ORDER 0x40
/** Uses 2's complement representation. */
#define INTEGER_PACK_2COMP 0x80
/** Uses "generic" implementation (handy on test). */
#define INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION 0x400
/**
* Always generates a bignum object even if the integer can be representable
* using fixnum scheme (unpack only)
*/
#define INTEGER_PACK_FORCE_BIGNUM 0x100
/**
* Interprets the input as a signed negative number (unpack only). If not
* specified returns a positive number.
*/
#define INTEGER_PACK_NEGATIVE 0x200
/** Little endian combination. */
#define INTEGER_PACK_LITTLE_ENDIAN \
(INTEGER_PACK_LSWORD_FIRST | \
INTEGER_PACK_LSBYTE_FIRST)
/** Big endian combination */
#define INTEGER_PACK_BIG_ENDIAN \
(INTEGER_PACK_MSWORD_FIRST | \
INTEGER_PACK_MSBYTE_FIRST)
/** @} */
RBIMPL_ATTR_NONNULL(())
/**
* Exports an integer into a buffer. This function fills the buffer specified
* by `words` and `numwords` as `val` in the format specified by `wordsize`,
* `nails` and `flags`.
*
* @param[in] val Integer or integer-like object which has
* `#to_int` method.
* @param[out] words Return buffer.
* @param[in] numwords Number of words of `words`.
* @param[in] wordsize Number of bytes per word.
* @param[in] nails Number of padding bits in a word. Most
* significant nails bits of each word are filled
* by zero.
* @param[in] flags Bitwise or of constants whose name starts
* "INTEGER_PACK_".
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
*
* Possible flags are:
*
* - #INTEGER_PACK_MSWORD_FIRST:
* Stores the most significant word as the first word.
*
* - #INTEGER_PACK_LSWORD_FIRST:
* Stores the least significant word as the first word.
*
* - #INTEGER_PACK_MSBYTE_FIRST:
* Stores the most significant byte in a word as the first byte in the
* word.
*
* - #INTEGER_PACK_LSBYTE_FIRST:
* Stores the least significant byte in a word as the first byte in the
* word.
*
* - #INTEGER_PACK_NATIVE_BYTE_ORDER:
* Either #INTEGER_PACK_MSBYTE_FIRST or #INTEGER_PACK_LSBYTE_FIRST
* corresponding to the host's endian.
*
* - #INTEGER_PACK_2COMP:
* Uses 2's complement representation.
*
* - #INTEGER_PACK_LITTLE_ENDIAN: Shorthand of
* `INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_LSBYTE_FIRST`.
*
* - #INTEGER_PACK_BIG_ENDIAN: Shorthand of
* `INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_MSBYTE_FIRST`.
*
* - #INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION:
* Uses generic implementation (for test and debug).
*
* This function fills the buffer specified by `words` as `val`'s 2's
* complement representation if #INTEGER_PACK_2COMP is specified in `flags`.
* Otherwise it fills `words` as `abs(val)` and signedness is returned via the
* return value.
*
* @return The signedness and overflow condition. The overflow condition
* depends on #INTEGER_PACK_2COMP.
*
* When #INTEGER_PACK_2COMP is not specified:
*
* - `-2` :
* Negative overflow. `val <= -2**(numwords*(wordsize*CHAR_BIT-nails))`
*
* - `-1` :
* Negative without overflow.
* `-2**(numwords*(wordsize*CHAR_BIT-nails)) < val < 0`
*
* - `0` : zero. `val == 0`
*
* - `1` :
* Positive without overflow.
* `0 < val < 2**(numwords*(wordsize*CHAR_BIT-nails))`
*
* - `2` :
* Positive overflow. `2**(numwords*(wordsize*CHAR_BIT-nails)) <= val`
*
* When #INTEGER_PACK_2COMP is specified:
*
* - `-2` :
* Negative overflow. `val < -2**(numwords*(wordsize*CHAR_BIT-nails))`
*
* - `-1` :
* Negative without overflow.
* `-2**(numwords*(wordsize*CHAR_BIT-nails)) <= val < 0`
*
* - `0` : zero. `val == 0`
*
* - `1` :
* Positive without overflow.
* `0 < val < 2**(numwords*(wordsize*CHAR_BIT-nails))`
*
* - `2` :
* Positive overflow. `2**(numwords*(wordsize*CHAR_BIT-nails)) <= val`
*
* The value, `-2**(numwords*(wordsize*CHAR_BIT-nails))`, is representable in
* 2's complement representation but not representable in absolute value. So
* `-1` is returned for the value if #INTEGER_PACK_2COMP is specified but
* returns `-2` if #INTEGER_PACK_2COMP is not specified.
*
* The least significant words are filled in the buffer when overflow occur.
*/
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags);
RBIMPL_ATTR_NONNULL(())
/**
* Import an integer from a buffer.
*
* @param[in] words Buffer to import.
* @param[in] numwords Number of words of `words`.
* @param[in] wordsize Number of bytes per word.
* @param[in] nails Number of padding bits in a word. Most
* significant nails bits of each word are ignored.
* @param[in] flags Bitwise or of constants whose name starts
* "INTEGER_PACK_".
* @exception rb_eArgError `numwords * wordsize` too big.
*
* Possible flags are:
*
* - #INTEGER_PACK_MSWORD_FIRST:
* Interpret the first word as the most significant word.
*
* - #INTEGER_PACK_LSWORD_FIRST:
* Interpret the first word as the least significant word.
*
* - #INTEGER_PACK_MSBYTE_FIRST:
* Interpret the first byte in a word as the most significant byte in the
* word.
*
* - #INTEGER_PACK_LSBYTE_FIRST:
* Interpret the first byte in a word as the least significant byte in
* the word.
*
* - #INTEGER_PACK_NATIVE_BYTE_ORDER:
* Either #INTEGER_PACK_MSBYTE_FIRST or #INTEGER_PACK_LSBYTE_FIRST
* corresponding to the host's endian.
*
* - #INTEGER_PACK_2COMP:
* Uses 2's complement representation.
*
* - #INTEGER_PACK_LITTLE_ENDIAN: Shorthand of
* `INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_LSBYTE_FIRST`
*
* - #INTEGER_PACK_BIG_ENDIAN: Shorthand of
* `INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_MSBYTE_FIRST`
*
* - #INTEGER_PACK_FORCE_BIGNUM:
* Returns a bignum even if its value is representable as a fixnum.
*
* - #INTEGER_PACK_NEGATIVE:
* Returns a non-positive value. (Returns a non-negative value if not
* specified.)
*
* - #INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION:
* Uses generic implementation (for test and debug).
*
* @return An instance of ::rb_cInteger whose value is the interpreted
* `words`. The range of the result value depends on
* #INTEGER_PACK_2COMP and #INTEGER_PACK_NEGATIVE.
*
* When #INTEGER_PACK_2COMP is not set:
*
* - `0 <= val < 2**(numwords*(wordsize*CHAR_BIT-nails))` if
* `!INTEGER_PACK_NEGATIVE`
*
* - `-2**(numwords*(wordsize*CHAR_BIT-nails)) < val <= 0` if
* `INTEGER_PACK_NEGATIVE`
*
* When #INTEGER_PACK_2COMP is set:
*
* - `-2**(numwords*(wordsize*CHAR_BIT-nails)-1)` `<= val <=`
* `2**(numwords*(wordsize*CHAR_BIT-nails)-1)-1` if
* `!INTEGER_PACK_NEGATIVE`
*
* - `-2**(numwords*(wordsize*CHAR_BIT-nails)) <= val <= -1` if
* `INTEGER_PACK_NEGATIVE`
*
* Passing #INTEGER_PACK_2COMP without #INTEGER_PACK_NEGATIVE means sign
* extension. #INTEGER_PACK_2COMP with #INTEGER_PACK_NEGATIVE means assuming
* the higher bits are `1`.
*
* Note that this function returns 0 when `numwords` is zero and
* #INTEGER_PACK_2COMP is set but #INTEGER_PACK_NEGATIVE is not set.
*/
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags);
/**
* Calculates the number of bytes needed to represent the absolute value of the
* passed integer.
*
* @param[in] val Integer or integer-like object which has
* `#to_int` method.
* @param[out] nlz_bits_ret Number of leading zero bits in the most
* significant byte is returned if not `NULL`.
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @return `((val_numbits * CHAR_BIT + CHAR_BIT - 1) / CHAR_BIT)`, where
* val_numbits is the number of bits of `abs(val)`.
* @post If `nlz_bits_ret` is not `NULL`,
* `(return_value * CHAR_BIT - val_numbits)` is stored in
* `*nlz_bits_ret`. In this case,
* `0 <= *nlz_bits_ret < CHAR_BIT`.
*
* This function should not overflow.
*/
size_t rb_absint_size(VALUE val, int *nlz_bits_ret);
/**
* Calculates the number of words needed represent the absolute value of the
* passed integer. Unlike rb_absint_size() this function can overflow. It
* returns `(size_t)-1` then.
*
* @param[in] val Integer or integer-like object which has
* `#to_int` method.
* @param[in] word_numbits Number of bits per word.
* @param[out] nlz_bits_ret Number of leading zero bits in the most
* significant word is returned if not `NULL`.
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @retval (size_t)-1 Overflowed.
* @retval otherwise
`((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
* where val_numbits is the number of bits of `abs(val)`.
* @post If `nlz_bits_ret` is not `NULL` and there is no overflow,
* `(return_value * word_numbits - val_numbits)` is stored in
* `*nlz_bits_ret`. In this case,
* `0 <= *nlz_bits_ret < word_numbits.`
*
*/
size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret);
/**
* Tests `abs(val)` consists only of a bit or not.
*
* @param[in] val Integer or integer-like object which has
* `#to_int` method.
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @retval 1 `abs(val) == 1 << n` for some `n >= 0`.
* @retval 0 Otherwise.
*
* rb_absint_singlebit_p() can be used to determine required buffer size for
* rb_integer_pack() used with #INTEGER_PACK_2COMP (two's complement).
*
* Following example calculates number of bits required to represent val in
* two's complement number, without sign bit.
*
* ```CXX
* size_t size;
* int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : BIGNUM_NEGATIVE_P(val);
* size = rb_absint_numwords(val, 1, NULL)
* if (size == (size_t)-1) ...overflow...
* if (neg && rb_absint_singlebit_p(val))
* size--;
* ```
*
* Following example calculates number of bytes required to represent val in
* two's complement number, with sign bit.
*
* ```CXX
* size_t size;
* int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : BIGNUM_NEGATIVE_P(val);
* int nlz_bits;
* size = rb_absint_size(val, &nlz_bits);
* if (nlz_bits == 0 && !(neg && rb_absint_singlebit_p(val)))
* size++;
* ```
*/
int rb_absint_singlebit_p(VALUE val);
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_BIGNUM_H */
Zerion Mini Shell 1.0