aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-12-09 15:39:28 -0800
committerPaul Eggert2019-12-09 15:41:02 -0800
commit5063e38921de8cb872965abda32bcc6fd8894532 (patch)
tree9773bacdffa337b6ce5385e91fe9200f7b93ba97
parentbb8f46d55bb369589ae475e47ad948da88c0d31d (diff)
downloademacs-5063e38921de8cb872965abda32bcc6fd8894532.tar.gz
emacs-5063e38921de8cb872965abda32bcc6fd8894532.zip
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.
-rw-r--r--doc/lispref/internals.texi111
1 files changed, 55 insertions, 56 deletions
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.
1469@deftypefn Function intmax_t extract_integer (emacs_env *@var{env}, emacs_value @var{arg}) 1469@deftypefn Function intmax_t extract_integer (emacs_env *@var{env}, emacs_value @var{arg})
1470This function returns the value of a Lisp integer specified by 1470This function returns the value of a Lisp integer specified by
1471@var{arg}. The C data type of the return value, @code{intmax_t}, is 1471@var{arg}. The C data type of the return value, @code{intmax_t}, is
1472the widest integral data type supported by the C compiler, typically 1472the widest integer data type supported by the C compiler, typically
1473@w{@code{long long}}. If the value of @var{arg} doesn't fit into an 1473@w{@code{long long}}. If the value of @var{arg} doesn't fit into an
1474@code{intmax_t}, the function signals an error using the error symbol 1474@code{intmax_t}, the function signals an error using the error symbol
1475@code{overflow-error}. 1475@code{overflow-error}.
@@ -1477,11 +1477,11 @@ the widest integral data type supported by the C compiler, typically
1477 1477
1478@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}) 1478@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})
1479This function, which is available since Emacs 27, extracts the 1479This function, which is available since Emacs 27, extracts the
1480integral value of @var{arg}. The value of @var{arg} must be an 1480integer value of @var{arg}. The value of @var{arg} must be an
1481integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it 1481integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it
1482stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The 1482stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The
1483magnitude is stored into @var{magnitude} as follows. If @var{count} 1483magnitude is stored into @var{magnitude} as follows. If @var{count}
1484and @var{magnitude} are bot non-@code{NULL}, then @var{magnitude} must 1484and @var{magnitude} are both non-@code{NULL}, then @var{magnitude} must
1485point to an array of at least @code{*count} @code{unsigned long} 1485point to an array of at least @code{*count} @code{unsigned long}
1486elements. If @var{magnitude} is large enough to hold the magnitude of 1486elements. If @var{magnitude} is large enough to hold the magnitude of
1487@var{arg}, then this function writes the magnitude into the 1487@var{arg}, then this function writes the magnitude into the
@@ -1495,20 +1495,21 @@ and returns @code{true}.
1495 1495
1496Emacs guarantees that the maximum required value of @code{*count} 1496Emacs guarantees that the maximum required value of @code{*count}
1497never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof 1497never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof
1498(emacs_limb_t)}. This implies that you can use e.g. @code{malloc 1498(emacs_limb_t)}, so you can use @code{malloc (*count * sizeof *magnitude)}
1499((size_t) (*count * sizeof (emacs_limb_t)))} to allocate the 1499to allocate the @code{magnitude} array without worrying about integer
1500@code{magnitude} array without integer overflow. 1500overflow in the size calculation.
1501@end deftypefn 1501@end deftypefn
1502 1502
1503@deftp {Type alias} emacs_limb_t 1503@deftp {Type alias} emacs_limb_t
1504This type is an alias to an otherwise unspecified unsigned integral 1504This is an unsigned integer type,
1505type. It is used as element type for the magnitude arrays for the big 1505used as the element type for the magnitude arrays for the big
1506integer conversion functions. 1506integer conversion functions.
1507@end deftp 1507@end deftp
1508 1508
1509@defvr Macro EMACS_LIMB_MAX 1509@defvr Macro EMACS_LIMB_MAX
1510This macro expands to an integer literal specifying the maximum 1510This macro expands to a constant expression specifying the maximum
1511possible value for an @code{emacs_limb_t} object. 1511possible value for an @code{emacs_limb_t} object.
1512The expression is suitable for use in @code{#if}.
1512@end defvr 1513@end defvr
1513 1514
1514@deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg}) 1515@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
1538function truncates it to nanosecond precision towards negative 1539function truncates it to nanosecond precision towards negative
1539infinity. This function signals an error if @var{time} (truncated to 1540infinity. This function signals an error if @var{time} (truncated to
1540nanoseconds) cannot be represented by @code{struct timespec}. For 1541nanoseconds) cannot be represented by @code{struct timespec}. For
1541example, if @code{time_t} is a 32-bit integral type, then a @var{time} 1542example, if @code{time_t} is a 32-bit integer type, then a @var{time}
1542value of ten billion seconds would signal an error, but a @var{time} 1543value of ten billion seconds would signal an error, but a @var{time}
1543value of 600 picoseconds would get truncated to zero. 1544value of 600 picoseconds would get truncated to zero.
1544 1545
@@ -1624,6 +1625,9 @@ Import and Export,,,gmp} for how to convert the @code{magnitude} array
1624to and from GMP @code{mpz_t} values. 1625to and from GMP @code{mpz_t} values.
1625 1626
1626@example 1627@example
1628#include <emacs-module.h>
1629int plugin_is_GPL_compatible;
1630
1627#include <assert.h> 1631#include <assert.h>
1628#include <limits.h> 1632#include <limits.h>
1629#include <stdint.h> 1633#include <stdint.h>
@@ -1632,48 +1636,43 @@ to and from GMP @code{mpz_t} values.
1632 1636
1633#include <gmp.h> 1637#include <gmp.h>
1634 1638
1635#include <emacs-module.h>
1636
1637static void 1639static void
1638memory_full (emacs_env *env) 1640memory_full (emacs_env *env)
1639@{ 1641@{
1640 const char *message = "Memory exhausted"; 1642 static const char message[] = "Memory exhausted";
1641 emacs_value data = env->make_string (env, message, strlen (message)); 1643 emacs_value data = env->make_string (env, message,
1642 env->non_local_exit_signal (env, env->intern (env, "error"), 1644 strlen (message));
1643 env->funcall (env, env->intern (env, "list"), 1, 1645 env->non_local_exit_signal
1644 &data)); 1646 (env, env->intern (env, "error"),
1647 env->funcall (env, env->intern (env, "list"), 1, &data));
1645@} 1648@}
1646 1649
1647enum 1650enum
1648@{ 1651@{
1649 max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) 1652 order = -1, endian = 0, nails = 0,
1650 / sizeof (emacs_limb_t)) 1653 limb_size = sizeof (emacs_limb_t),
1654 max_nlimbs = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
1655 / limb_size)
1651@}; 1656@};
1652 1657
1653static bool 1658static bool
1654extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) 1659extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
1655@{ 1660@{
1656 int sign; 1661 ptrdiff_t nlimbs;
1657 ptrdiff_t count; 1662 bool ok = env->extract_big_integer (env, arg, NULL, &nlimbs, NULL);
1658 bool success = env->extract_big_integer (env, arg, &sign, &count, NULL); 1663 if (!ok)
1659 if (!success)
1660 return false; 1664 return false;
1661 if (sign == 0) 1665 assert (0 < nlimbs && nlimbs <= max_nlimbs);
1662 @{ 1666 emacs_limb_t *magnitude = malloc (nlimbs * limb_size);
1663 mpz_set_ui (result, 0);
1664 return true;
1665 @}
1666 enum @{ order = -1, size = sizeof (emacs_limb_t), endian = 0, nails = 0 @};
1667 assert (0 < count && count <= max_count);
1668 emacs_limb_t *magnitude = malloc ((size_t) (count * size));
1669 if (magnitude == NULL) 1667 if (magnitude == NULL)
1670 @{ 1668 @{
1671 memory_full (env); 1669 memory_full (env);
1672 return false; 1670 return false;
1673 @} 1671 @}
1674 success = env->extract_big_integer (env, arg, NULL, &count, magnitude); 1672 int sign;
1675 assert (success); 1673 ok = env->extract_big_integer (env, arg, &sign, &nlimbs, magnitude);
1676 mpz_import (result, count, order, size, endian, nails, magnitude); 1674 assert (ok);
1675 mpz_import (result, nlimbs, order, limb_size, endian, nails, magnitude);
1677 free (magnitude); 1676 free (magnitude);
1678 if (sign < 0) 1677 if (sign < 0)
1679 mpz_neg (result, result); 1678 mpz_neg (result, result);
@@ -1683,34 +1682,22 @@ extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
1683static emacs_value 1682static emacs_value
1684make_big_integer (emacs_env *env, const mpz_t value) 1683make_big_integer (emacs_env *env, const mpz_t value)
1685@{ 1684@{
1686 if (mpz_sgn (value) == 0) 1685 size_t nbits = mpz_sizeinbase (value, 2);
1687 return env->make_integer (env, 0); 1686 int bitsperlimb = CHAR_BIT * limb_size - nails;
1688 enum 1687 size_t nlimbs = nbits / bitsperlimb + (nbits % bitsperlimb != 0);
1689 @{ 1688 emacs_limb_t *magnitude
1690 order = -1, 1689 = nlimbs <= max_nlimbs ? malloc (nlimbs * limb_size) : NULL;
1691 size = sizeof (emacs_limb_t),
1692 endian = 0,
1693 nails = 0,
1694 numb = 8 * size - nails
1695 @};
1696 size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb;
1697 if (max_count < count)
1698 @{
1699 memory_full (env);
1700 return NULL;
1701 @}
1702 emacs_limb_t *magnitude = malloc (count * size);
1703 if (magnitude == NULL) 1690 if (magnitude == NULL)
1704 @{ 1691 @{
1705 memory_full (env); 1692 memory_full (env);
1706 return NULL; 1693 return NULL;
1707 @} 1694 @}
1708 size_t written; 1695 size_t written;
1709 mpz_export (magnitude, &written, order, size, endian, nails, value); 1696 mpz_export (magnitude, &written, order, limb_size, endian, nails, value);
1710 assert (written == count); 1697 assert (written == nlimbs);
1711 assert (count <= PTRDIFF_MAX); 1698 assert (nlimbs <= PTRDIFF_MAX);
1712 emacs_value result = env->make_big_integer (env, mpz_sgn (value), 1699 emacs_value result = env->make_big_integer (env, mpz_sgn (value),
1713 (ptrdiff_t) count, magnitude); 1700 nlimbs, magnitude);
1714 free (magnitude); 1701 free (magnitude);
1715 return result; 1702 return result;
1716@} 1703@}
@@ -1720,7 +1707,7 @@ next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
1720 void *data) 1707 void *data)
1721@{ 1708@{
1722 assert (nargs == 1); 1709 assert (nargs == 1);
1723 emacs_mpz p; 1710 mpz_t p;
1724 mpz_init (p); 1711 mpz_init (p);
1725 extract_big_integer (env, args[0], p); 1712 extract_big_integer (env, args[0], p);
1726 mpz_nextprime (p, p); 1713 mpz_nextprime (p, p);
@@ -1728,6 +1715,18 @@ next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
1728 mpz_clear (p); 1715 mpz_clear (p);
1729 return result; 1716 return result;
1730@} 1717@}
1718
1719int
1720emacs_module_init (struct emacs_runtime *ert)
1721@{
1722 emacs_env *env = ert->get_environment (ert);
1723 emacs_value symbol = env->intern (env, "next-prime");
1724 emacs_value func
1725 = env->make_function (env, 1, 1, next_prime, NULL, NULL);
1726 emacs_value args[] = @{symbol, func@};
1727 env->funcall (env, env->intern (env, "defalias"), 2, args);
1728 return 0;
1729@}
1731@end example 1730@end example
1732 1731
1733@deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d}) 1732@deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d})