emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 5063e38: Improve module bignum doc


From: Paul Eggert
Subject: master 5063e38: Improve module bignum doc
Date: Mon, 9 Dec 2019 18:41:08 -0500 (EST)

branch: master
commit 5063e38921de8cb872965abda32bcc6fd8894532
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    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.
---
 doc/lispref/internals.texi | 111 ++++++++++++++++++++++-----------------------
 1 file changed, 55 insertions(+), 56 deletions(-)

diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index f1062a2..f91d5b3 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 <emacs-module.h>
+int plugin_is_GPL_compatible;
+
 #include <assert.h>
 #include <limits.h>
 #include <stdint.h>
@@ -1632,48 +1636,43 @@ to and from GMP @code{mpz_t} values.
 
 #include <gmp.h>
 
-#include <emacs-module.h>
-
 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})



reply via email to

[Prev in Thread] Current Thread [Next in Thread]