diff options
| author | Paul Eggert | 2019-12-09 15:39:28 -0800 |
|---|---|---|
| committer | Paul Eggert | 2019-12-09 15:41:02 -0800 |
| commit | 5063e38921de8cb872965abda32bcc6fd8894532 (patch) | |
| tree | 9773bacdffa337b6ce5385e91fe9200f7b93ba97 | |
| parent | bb8f46d55bb369589ae475e47ad948da88c0d31d (diff) | |
| download | emacs-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.texi | 111 |
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}) |
| 1470 | This function returns the value of a Lisp integer specified by | 1470 | This 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 |
| 1472 | the widest integral data type supported by the C compiler, typically | 1472 | the 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}) |
| 1479 | This function, which is available since Emacs 27, extracts the | 1479 | This function, which is available since Emacs 27, extracts the |
| 1480 | integral value of @var{arg}. The value of @var{arg} must be an | 1480 | integer value of @var{arg}. The value of @var{arg} must be an |
| 1481 | integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it | 1481 | integer (fixnum or bignum). If @var{sign} is not @code{NULL}, it |
| 1482 | stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The | 1482 | stores the sign of @var{arg} (-1, 0, or +1) into @code{*sign}. The |
| 1483 | magnitude is stored into @var{magnitude} as follows. If @var{count} | 1483 | magnitude is stored into @var{magnitude} as follows. If @var{count} |
| 1484 | and @var{magnitude} are bot non-@code{NULL}, then @var{magnitude} must | 1484 | and @var{magnitude} are both non-@code{NULL}, then @var{magnitude} must |
| 1485 | point to an array of at least @code{*count} @code{unsigned long} | 1485 | point to an array of at least @code{*count} @code{unsigned long} |
| 1486 | elements. If @var{magnitude} is large enough to hold the magnitude of | 1486 | elements. 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 | ||
| 1496 | Emacs guarantees that the maximum required value of @code{*count} | 1496 | Emacs guarantees that the maximum required value of @code{*count} |
| 1497 | never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof | 1497 | never 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 | 1499 | to allocate the @code{magnitude} array without worrying about integer |
| 1500 | @code{magnitude} array without integer overflow. | 1500 | overflow 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 |
| 1504 | This type is an alias to an otherwise unspecified unsigned integral | 1504 | This is an unsigned integer type, |
| 1505 | type. It is used as element type for the magnitude arrays for the big | 1505 | used as the element type for the magnitude arrays for the big |
| 1506 | integer conversion functions. | 1506 | integer conversion functions. |
| 1507 | @end deftp | 1507 | @end deftp |
| 1508 | 1508 | ||
| 1509 | @defvr Macro EMACS_LIMB_MAX | 1509 | @defvr Macro EMACS_LIMB_MAX |
| 1510 | This macro expands to an integer literal specifying the maximum | 1510 | This macro expands to a constant expression specifying the maximum |
| 1511 | possible value for an @code{emacs_limb_t} object. | 1511 | possible value for an @code{emacs_limb_t} object. |
| 1512 | The 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 | |||
| 1538 | function truncates it to nanosecond precision towards negative | 1539 | function truncates it to nanosecond precision towards negative |
| 1539 | infinity. This function signals an error if @var{time} (truncated to | 1540 | infinity. This function signals an error if @var{time} (truncated to |
| 1540 | nanoseconds) cannot be represented by @code{struct timespec}. For | 1541 | nanoseconds) cannot be represented by @code{struct timespec}. For |
| 1541 | example, if @code{time_t} is a 32-bit integral type, then a @var{time} | 1542 | example, if @code{time_t} is a 32-bit integer type, then a @var{time} |
| 1542 | value of ten billion seconds would signal an error, but a @var{time} | 1543 | value of ten billion seconds would signal an error, but a @var{time} |
| 1543 | value of 600 picoseconds would get truncated to zero. | 1544 | value 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 | |||
| 1624 | to and from GMP @code{mpz_t} values. | 1625 | to and from GMP @code{mpz_t} values. |
| 1625 | 1626 | ||
| 1626 | @example | 1627 | @example |
| 1628 | #include <emacs-module.h> | ||
| 1629 | int 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 | |||
| 1637 | static void | 1639 | static void |
| 1638 | memory_full (emacs_env *env) | 1640 | memory_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 | ||
| 1647 | enum | 1650 | enum |
| 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 | ||
| 1653 | static bool | 1658 | static bool |
| 1654 | extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) | 1659 | extract_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) | |||
| 1683 | static emacs_value | 1682 | static emacs_value |
| 1684 | make_big_integer (emacs_env *env, const mpz_t value) | 1683 | make_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 | |||
| 1719 | int | ||
| 1720 | emacs_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}) |