aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorPhilipp Stephani2019-11-02 10:54:57 +0100
committerPhilipp Stephani2019-12-04 21:17:10 +0100
commit096be9c4541329af259273fe604dc4f8669fbd8a (patch)
tree9a93e99ec78c598bfa42b73c30e7ff349a3bb489 /doc
parent0ca32d1270bd5d494e365f3525fa65ac423f6658 (diff)
downloademacs-096be9c4541329af259273fe604dc4f8669fbd8a.tar.gz
emacs-096be9c4541329af259273fe604dc4f8669fbd8a.zip
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP directly in the module interface has significant downsides: it couples the module interface directly to the implementation and requires module authors to link their module against the same GMP library as Emacs itself, which is often difficult and an unnecessary burden. By picking a representation for the magnitude that often matches the one used by GMP, we can avoid overhead when converting from and to GMP in most cases. Loading the test module in test/data/emacs-module and evaluating (dotimes (_ 10000) (mod-test-double (* 2 most-negative-fixnum))) under Callgrind shows that on my (GNU/Linux) machine Emacs only spends 10% of the CPU time of mod-test-double in mpz_import and mpz_export combined, even though that function does little else. (By contrast, 30% is spent in allocate_pseudovector.) * src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include gmp.h. Remove emacs_mpz structure. Instead, define type alias emacs_limb_t and macro EMACS_LIMB_MAX. * src/module-env-27.h: Change interface of extract_big_integer and make_big_integer to take a sign-magnitude representation instead of mpz_t. * src/emacs-module.c: Don't check EMACS_MODULE_GMP or EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen implementation. (module_extract_big_integer, module_make_big_integer): Reimplement without using mpz_t in the interface. * doc/lispref/internals.texi (Module Values): Adapt function documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP. * test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or EMACS_MODULE_HAVE_MPZ_T. (memory_full, extract_big_integer, make_big_integer): New helper functions, identical to example in the Info documentation. (Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
Diffstat (limited to 'doc')
-rw-r--r--doc/lispref/internals.texi218
1 files changed, 158 insertions, 60 deletions
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index e870d6e06e8..f1062a2f4d0 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -1475,6 +1475,42 @@ the widest integral data type supported by the C compiler, typically
1475@code{overflow-error}. 1475@code{overflow-error}.
1476@end deftypefn 1476@end deftypefn
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})
1479This function, which is available since Emacs 27, extracts the
1480integral value of @var{arg}. The value of @var{arg} must be an
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
1483magnitude is stored into @var{magnitude} as follows. If @var{count}
1484and @var{magnitude} are bot non-@code{NULL}, then @var{magnitude} must
1485point to an array of at least @code{*count} @code{unsigned long}
1486elements. If @var{magnitude} is large enough to hold the magnitude of
1487@var{arg}, then this function writes the magnitude into the
1488@var{magnitude} array in little-endian form, stores the number of
1489array elements written into @code{*count}, and returns @code{true}.
1490If @var{magnitude} is not large enough, it stores the required array
1491size into @code{*count}, signals an error, and returns @code{false}.
1492If @var{count} is not @code{NULL} and @var{magnitude} is @code{NULL},
1493then the function stores the required array size into @code{*count}
1494and returns @code{true}.
1495
1496Emacs guarantees that the maximum required value of @code{*count}
1497never exceeds @code{min (PTRDIFF_MAX, SIZE_MAX) / sizeof
1498(emacs_limb_t)}. This implies that you can use e.g. @code{malloc
1499((size_t) (*count * sizeof (emacs_limb_t)))} to allocate the
1500@code{magnitude} array without integer overflow.
1501@end deftypefn
1502
1503@deftp {Type alias} emacs_limb_t
1504This type is an alias to an otherwise unspecified unsigned integral
1505type. It is used as element type for the magnitude arrays for the big
1506integer conversion functions.
1507@end deftp
1508
1509@defvr Macro EMACS_LIMB_MAX
1510This macro expands to an integer literal specifying the maximum
1511possible value for an @code{emacs_limb_t} object.
1512@end defvr
1513
1478@deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg}) 1514@deftypefn Function double extract_float (emacs_env *@var{env}, emacs_value @var{arg})
1479This function returns the value of a Lisp float specified by 1515This function returns the value of a Lisp float specified by
1480@var{arg}, as a C @code{double} value. 1516@var{arg}, as a C @code{double} value.
@@ -1572,6 +1608,128 @@ limits set by @code{most-negative-fixnum} and
1572@code{most-positive-fixnum} (@pxref{Integer Basics}). 1608@code{most-positive-fixnum} (@pxref{Integer Basics}).
1573@end deftypefn 1609@end deftypefn
1574 1610
1611@deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, int sign, ptrdiff_t count, const emacs_limb_t *magnitude)
1612This function, which is available since Emacs 27, takes an
1613arbitrary-sized integer argument and returns a corresponding
1614@code{emacs_value} object. The @var{sign} argument gives the sign of
1615the return value. If @var{sign} is nonzero, then @var{magnitude} must
1616point to an array of at least @var{count} elements specifying the
1617little-endian magnitude of the return value.
1618@end deftypefn
1619
1620The following example uses the GNU Multiprecision Library (GMP) to
1621calculate the next probable prime after a given integer.
1622@xref{Top,,,gmp} for a general overview of GMP, and @pxref{Integer
1623Import and Export,,,gmp} for how to convert the @code{magnitude} array
1624to and from GMP @code{mpz_t} values.
1625
1626@example
1627#include <assert.h>
1628#include <limits.h>
1629#include <stdint.h>
1630#include <stdlib.h>
1631#include <string.h>
1632
1633#include <gmp.h>
1634
1635#include <emacs-module.h>
1636
1637static void
1638memory_full (emacs_env *env)
1639@{
1640 const char *message = "Memory exhausted";
1641 emacs_value data = env->make_string (env, message, strlen (message));
1642 env->non_local_exit_signal (env, env->intern (env, "error"),
1643 env->funcall (env, env->intern (env, "list"), 1,
1644 &data));
1645@}
1646
1647enum
1648@{
1649 max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
1650 / sizeof (emacs_limb_t))
1651@};
1652
1653static bool
1654extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
1655@{
1656 int sign;
1657 ptrdiff_t count;
1658 bool success = env->extract_big_integer (env, arg, &sign, &count, NULL);
1659 if (!success)
1660 return false;
1661 if (sign == 0)
1662 @{
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)
1670 @{
1671 memory_full (env);
1672 return false;
1673 @}
1674 success = env->extract_big_integer (env, arg, NULL, &count, magnitude);
1675 assert (success);
1676 mpz_import (result, count, order, size, endian, nails, magnitude);
1677 free (magnitude);
1678 if (sign < 0)
1679 mpz_neg (result, result);
1680 return true;
1681@}
1682
1683static emacs_value
1684make_big_integer (emacs_env *env, const mpz_t value)
1685@{
1686 if (mpz_sgn (value) == 0)
1687 return env->make_integer (env, 0);
1688 enum
1689 @{
1690 order = -1,
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)
1704 @{
1705 memory_full (env);
1706 return NULL;
1707 @}
1708 size_t written;
1709 mpz_export (magnitude, &written, order, size, endian, nails, value);
1710 assert (written == count);
1711 assert (count <= PTRDIFF_MAX);
1712 emacs_value result = env->make_big_integer (env, mpz_sgn (value),
1713 (ptrdiff_t) count, magnitude);
1714 free (magnitude);
1715 return result;
1716@}
1717
1718static emacs_value
1719next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
1720 void *data)
1721@{
1722 assert (nargs == 1);
1723 emacs_mpz p;
1724 mpz_init (p);
1725 extract_big_integer (env, args[0], p);
1726 mpz_nextprime (p, p);
1727 emacs_value result = make_big_integer (env, p);
1728 mpz_clear (p);
1729 return result;
1730@}
1731@end example
1732
1575@deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d}) 1733@deftypefn Function emacs_value make_float (emacs_env *@var{env}, double @var{d})
1576This function takes a @code{double} argument @var{d} and returns the 1734This function takes a @code{double} argument @var{d} and returns the
1577corresponding Emacs floating-point value. 1735corresponding Emacs floating-point value.
@@ -1601,66 +1759,6 @@ function raises the @code{overflow-error} error condition if
1601string. 1759string.
1602@end deftypefn 1760@end deftypefn
1603 1761
1604If you define the preprocessor macro @code{EMACS_MODULE_GMP} before
1605including the header @file{emacs-module.h}, you can also convert
1606between Emacs integers and GMP @code{mpz_t} values. @xref{GMP
1607Basics,,,gmp}. If @code{EMACS_MODULE_GMP} is defined,
1608@file{emacs-module.h} wraps @code{mpz_t} in the following structure:
1609
1610@deftp struct emacs_mpz value
1611struct emacs_mpz @{ mpz_t value; @};
1612@end deftp
1613
1614@noindent
1615Then you can use the following additional functions:
1616
1617@deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, struct emacs_mpz *@var{result})
1618This function, which is available since Emacs 27, extracts the
1619integral value of @var{arg} into @var{result}. @var{result} must not
1620be @code{NULL}. @code{@var{result}->value} must be an initialized
1621@code{mpz_t} object. @xref{Initializing Integers,,,gmp}. If
1622@var{arg} is an integer, Emacs will store its value into
1623@code{@var{result}->value}. After you have finished using
1624@code{@var{result}->value}, you should free it using @code{mpz_clear}
1625or similar.
1626@end deftypefn
1627
1628@deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, const struct emacs_mpz *@var{value})
1629This function, which is available since Emacs 27, takes an
1630arbitrary-sized integer argument and returns a corresponding
1631@code{emacs_value} object. @var{value} must not be @code{NULL}.
1632@code{@var{value}->value} must be an initialized @code{mpz_t} object.
1633@xref{Initializing Integers,,,gmp}. Emacs will return a corresponding
1634integral object. After you have finished using
1635@code{@var{value}->value}, you should free it using @code{mpz_clear}
1636or similar.
1637@end deftypefn
1638
1639The following example uses GMP to calculate the next probable prime
1640after a given integer:
1641
1642@example
1643#include <assert.h>
1644#include <gmp.h>
1645
1646#define EMACS_MODULE_GMP
1647#include <emacs-module.h>
1648
1649static emacs_value
1650next_prime (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
1651 void *data)
1652@{
1653 assert (nargs == 1);
1654 emacs_mpz p;
1655 mpz_init (p.value);
1656 env->extract_big_integer (env, args[0], &p);
1657 mpz_nextprime (p.value, p.value);
1658 emacs_value result = env->make_big_integer (env, &p);
1659 mpz_clear (p.value);
1660 return result;
1661@}
1662@end example
1663
1664The @acronym{API} does not provide functions to manipulate Lisp data 1762The @acronym{API} does not provide functions to manipulate Lisp data
1665structures, for example, create lists with @code{cons} and @code{list} 1763structures, for example, create lists with @code{cons} and @code{list}
1666(@pxref{Building Lists}), extract list members with @code{car} and 1764(@pxref{Building Lists}), extract list members with @code{car} and