From: Paul Eggert Date: Mon, 9 Dec 2019 23:39:28 +0000 (-0800) Subject: Improve module bignum doc X-Git-Tag: emacs-27.0.90~398 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5063e38921de8cb872965abda32bcc6fd8894532;p=emacs.git Improve module bignum doc * doc/lispref/internals.texi (Module Values): Tighten up wording and code, and make the long example self-contained. Fit things in margins. --- diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index f1062a2f4d0..f91d5b3423d 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -1469,7 +1469,7 @@ can be used to obtain the type of a @code{emacs_value} object. @deftypefn Function intmax_t extract_integer (emacs_env *@var{env}, emacs_value @var{arg}) This function returns the value of a Lisp integer specified by @var{arg}. The C data type of the return value, @code{intmax_t}, is -the widest integral data type supported by the C compiler, typically +the widest integer data type supported by the C compiler, typically @w{@code{long long}}. If the value of @var{arg} doesn't fit into an @code{intmax_t}, the function signals an error using the error symbol @code{overflow-error}. @@ -1477,11 +1477,11 @@ the widest integral data type supported by the C compiler, typically @deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, int *@var{sign}, ptrdiff_t *@var{count}, emacs_limb_t *@var{magnitude}) This function, which is available since Emacs 27, extracts the -integral value of @var{arg}. The value of @var{arg} must be an +integer value of @var{arg}. The value of @var{arg} must be an integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The magnitude is stored into @var{magnitude} as follows. If @var{count} -and @var{magnitude} are bot non-@code{NULL}, then @var{magnitude} must +and @var{magnitude} are both non-@code{NULL}, then @var{magnitude} must point to an array of at least @code{*count} @code{unsigned long} elements. If @var{magnitude} is large enough to hold the magnitude of @var{arg}, then this function writes the magnitude into the @@ -1495,20 +1495,21 @@ and returns @code{true}. Emacs guarantees that the maximum required value of @code{*count} never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof -(emacs_limb_t)}. This implies that you can use e.g. @code{malloc -((size_t) (*count * sizeof (emacs_limb_t)))} to allocate the -@code{magnitude} array without integer overflow. +(emacs_limb_t)}, so you can use @code{malloc (*count * sizeof *magnitude)} +to allocate the @code{magnitude} array without worrying about integer +overflow in the size calculation. @end deftypefn @deftp {Type alias} emacs_limb_t -This type is an alias to an otherwise unspecified unsigned integral -type. It is used as element type for the magnitude arrays for the big +This is an unsigned integer type, +used as the element type for the magnitude arrays for the big integer conversion functions. @end deftp @defvr Macro EMACS_LIMB_MAX -This macro expands to an integer literal specifying the maximum +This macro expands to a constant expression specifying the maximum possible value for an @code{emacs_limb_t} object. +The expression is suitable for use in @code{#if}. @end defvr @deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg}) @@ -1538,7 +1539,7 @@ If @var{time} has higher precision than nanoseconds, then this function truncates it to nanosecond precision towards negative infinity. This function signals an error if @var{time} (truncated to nanoseconds) cannot be represented by @code{struct timespec}. For -example, if @code{time_t} is a 32-bit integral type, then a @var{time} +example, if @code{time_t} is a 32-bit integer type, then a @var{time} value of ten billion seconds would signal an error, but a @var{time} value of 600 picoseconds would get truncated to zero. @@ -1624,6 +1625,9 @@ Import and Export,,,gmp} for how to convert the @code{magnitude} array to and from GMP @code{mpz_t} values. @example +#include +int plugin_is_GPL_compatible; + #include #include #include @@ -1632,48 +1636,43 @@ to and from GMP @code{mpz_t} values. #include -#include - static void memory_full (emacs_env *env) @{ - const char *message = "Memory exhausted"; - emacs_value data = env->make_string (env, message, strlen (message)); - env->non_local_exit_signal (env, env->intern (env, "error"), - env->funcall (env, env->intern (env, "list"), 1, - &data)); + static const char message[] = "Memory exhausted"; + emacs_value data = env->make_string (env, message, + strlen (message)); + env->non_local_exit_signal + (env, env->intern (env, "error"), + env->funcall (env, env->intern (env, "list"), 1, &data)); @} enum @{ - max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) - / sizeof (emacs_limb_t)) + order = -1, endian = 0, nails = 0, + limb_size = sizeof (emacs_limb_t), + max_nlimbs = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) + / limb_size) @}; static bool extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) @{ - int sign; - ptrdiff_t count; - bool success = env->extract_big_integer (env, arg, &sign, &count, NULL); - if (!success) + ptrdiff_t nlimbs; + bool ok = env->extract_big_integer (env, arg, NULL, &nlimbs, NULL); + if (!ok) return false; - if (sign == 0) - @{ - mpz_set_ui (result, 0); - return true; - @} - enum @{ order = -1, size = sizeof (emacs_limb_t), endian = 0, nails = 0 @}; - assert (0 < count && count <= max_count); - emacs_limb_t *magnitude = malloc ((size_t) (count * size)); + assert (0 < nlimbs && nlimbs <= max_nlimbs); + emacs_limb_t *magnitude = malloc (nlimbs * limb_size); if (magnitude == NULL) @{ memory_full (env); return false; @} - success = env->extract_big_integer (env, arg, NULL, &count, magnitude); - assert (success); - mpz_import (result, count, order, size, endian, nails, magnitude); + int sign; + ok = env->extract_big_integer (env, arg, &sign, &nlimbs, magnitude); + assert (ok); + mpz_import (result, nlimbs, order, limb_size, endian, nails, magnitude); free (magnitude); if (sign < 0) mpz_neg (result, result); @@ -1683,34 +1682,22 @@ extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) static emacs_value make_big_integer (emacs_env *env, const mpz_t value) @{ - if (mpz_sgn (value) == 0) - return env->make_integer (env, 0); - enum - @{ - order = -1, - size = sizeof (emacs_limb_t), - endian = 0, - nails = 0, - numb = 8 * size - nails - @}; - size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb; - if (max_count < count) - @{ - memory_full (env); - return NULL; - @} - emacs_limb_t *magnitude = malloc (count * size); + size_t nbits = mpz_sizeinbase (value, 2); + int bitsperlimb = CHAR_BIT * limb_size - nails; + size_t nlimbs = nbits / bitsperlimb + (nbits % bitsperlimb != 0); + emacs_limb_t *magnitude + = nlimbs <= max_nlimbs ? malloc (nlimbs * limb_size) : NULL; if (magnitude == NULL) @{ memory_full (env); return NULL; @} size_t written; - mpz_export (magnitude, &written, order, size, endian, nails, value); - assert (written == count); - assert (count <= PTRDIFF_MAX); + mpz_export (magnitude, &written, order, limb_size, endian, nails, value); + assert (written == nlimbs); + assert (nlimbs <= PTRDIFF_MAX); emacs_value result = env->make_big_integer (env, mpz_sgn (value), - (ptrdiff_t) count, magnitude); + nlimbs, magnitude); free (magnitude); return result; @} @@ -1720,7 +1707,7 @@ next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) @{ assert (nargs == 1); - emacs_mpz p; + mpz_t p; mpz_init (p); extract_big_integer (env, args[0], p); mpz_nextprime (p, p); @@ -1728,6 +1715,18 @@ next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args, mpz_clear (p); return result; @} + +int +emacs_module_init (struct emacs_runtime *ert) +@{ + emacs_env *env = ert->get_environment (ert); + emacs_value symbol = env->intern (env, "next-prime"); + emacs_value func + = env->make_function (env, 1, 1, next_prime, NULL, NULL); + emacs_value args[] = @{symbol, func@}; + env->funcall (env, env->intern (env, "defalias"), 2, args); + return 0; +@} @end example @deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d})