#ifndef RBIMPL_INTERN_BIGNUM_H /*-*-C++-*-vi:se ft=cpp:*/ #define RBIMPL_INTERN_BIGNUM_H /** * @file * @author Ruby developers * @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 #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 */