aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/internals.texi218
-rw-r--r--src/emacs-module.c144
-rw-r--r--src/emacs-module.h.in22
-rw-r--r--src/module-env-27.h12
-rw-r--r--test/data/emacs-module/mod-test.c111
5 files changed, 406 insertions, 101 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
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 4b991a1c744..e5c88fd814a 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -70,12 +70,6 @@ To add a new module function, proceed as follows:
70 70
71#include <config.h> 71#include <config.h>
72 72
73#ifndef HAVE_GMP
74#include "mini-gmp.h"
75#define EMACS_MODULE_HAVE_MPZ_T
76#endif
77
78#define EMACS_MODULE_GMP
79#include "emacs-module.h" 73#include "emacs-module.h"
80 74
81#include <stdarg.h> 75#include <stdarg.h>
@@ -772,21 +766,143 @@ module_make_time (emacs_env *env, struct timespec time)
772 return lisp_to_value (env, timespec_to_lisp (time)); 766 return lisp_to_value (env, timespec_to_lisp (time));
773} 767}
774 768
775static void 769/*
776module_extract_big_integer (emacs_env *env, emacs_value value, 770Big integer support.
777 struct emacs_mpz *result) 771
772There are two possible ways to support big integers in the module API
773that have been discussed:
774
7751. Exposing GMP numbers (mpz_t) directly in the API.
776
7772. Isolating the API from GMP by converting to/from a custom
778 sign-magnitude representation.
779
780Approach (1) has the advantage of being faster (no import/export
781required) and requiring less code in Emacs and in modules that would
782use GMP anyway. However, (1) also couples big integer support
783directly to the current implementation in Emacs (GMP). Also (1)
784requires each module author to ensure that their module is linked to
785the same GMP library as Emacs itself; in particular, module authors
786can't link GMP statically. (1) also requires conditional compilation
787and workarounds to ensure the module interface still works if GMP
788isn't available while including emacs-module.h. It also means that
789modules written in languages such as Go and Java that support big
790integers without GMP now have to carry an otherwise unnecessary GMP
791dependency. Approach (2), on the other hand, neatly decouples the
792module interface from the GMP-based implementation. It's not
793significantly more complex than (1) either: the additional code is
794mostly straightforward. Over all, the benefits of (2) over (1) are
795large enough to prefer it here.
796
797We use a simple sign-magnitude representation for the big integers.
798For the magnitude we pick an array of an unsigned integer type similar
799to mp_limb_t instead of e.g. unsigned char. This matches in most
800cases the representation of a GMP limb. In such cases GMP picks an
801optimized algorithm for mpz_import and mpz_export that boils down to a
802single memcpy to convert the magnitude. This way we largely avoid the
803import/export overhead on most platforms.
804*/
805
806enum
778{ 807{
779 MODULE_FUNCTION_BEGIN (); 808 /* Documented maximum count of magnitude elements. */
780 Lisp_Object o = value_to_lisp (value); 809 module_bignum_count_max = min (SIZE_MAX, PTRDIFF_MAX) / sizeof (emacs_limb_t)
810};
811
812static bool
813module_extract_big_integer (emacs_env *env, emacs_value arg, int *sign,
814 ptrdiff_t *count, emacs_limb_t *magnitude)
815{
816 MODULE_FUNCTION_BEGIN (false);
817 Lisp_Object o = value_to_lisp (arg);
781 CHECK_INTEGER (o); 818 CHECK_INTEGER (o);
782 mpz_set_integer (result->value, o); 819 int dummy;
820 if (sign == NULL)
821 sign = &dummy;
822 /* See
823 https://gmplib.org/manual/Integer-Import-and-Export.html#index-Export. */
824 enum
825 {
826 order = -1,
827 size = sizeof *magnitude,
828 bits = size * CHAR_BIT,
829 endian = 0,
830 nails = 0,
831 numb = 8 * size - nails
832 };
833 if (FIXNUMP (o))
834 {
835 EMACS_INT x = XFIXNUM (o);
836 *sign = (0 < x) - (x < 0);
837 if (x == 0 || count == NULL)
838 return true;
839 /* As a simplification we don't check how many array elements
840 are exactly required, but use a reasonable static upper
841 bound. For most architectures exactly one element should
842 suffice. */
843 EMACS_UINT u;
844 enum { required = (sizeof u + size - 1) / size };
845 verify (0 < required && required <= module_bignum_count_max);
846 if (magnitude == NULL)
847 {
848 *count = required;
849 return true;
850 }
851 if (*count < required)
852 {
853 ptrdiff_t actual = *count;
854 *count = required;
855 args_out_of_range_3 (INT_TO_INTEGER (actual),
856 INT_TO_INTEGER (required),
857 INT_TO_INTEGER (module_bignum_count_max));
858 }
859 /* Set u = abs(x). See https://stackoverflow.com/a/17313717. */
860 if (0 < x)
861 u = (EMACS_UINT) x;
862 else
863 u = -(EMACS_UINT) x;
864 verify (required * bits < PTRDIFF_MAX);
865 for (ptrdiff_t i = 0; i < required; ++i)
866 magnitude[i] = (emacs_limb_t) (u >> (i * bits));
867 return true;
868 }
869 const mpz_t *x = xbignum_val (o);
870 *sign = mpz_sgn (*x);
871 if (count == NULL)
872 return true;
873 size_t required_size = (mpz_sizeinbase (*x, 2) + numb - 1) / numb;
874 eassert (required_size <= PTRDIFF_MAX);
875 ptrdiff_t required = (ptrdiff_t) required_size;
876 eassert (required <= module_bignum_count_max);
877 if (magnitude == NULL)
878 {
879 *count = required;
880 return true;
881 }
882 if (*count < required)
883 {
884 ptrdiff_t actual = *count;
885 *count = required;
886 args_out_of_range_3 (INT_TO_INTEGER (actual), INT_TO_INTEGER (required),
887 INT_TO_INTEGER (module_bignum_count_max));
888 }
889 size_t written;
890 mpz_export (magnitude, &written, order, size, endian, nails, *x);
891 eassert (written == required_size);
892 return true;
783} 893}
784 894
785static emacs_value 895static emacs_value
786module_make_big_integer (emacs_env *env, const struct emacs_mpz *value) 896module_make_big_integer (emacs_env *env, int sign,
897 ptrdiff_t count, const unsigned long *magnitude)
787{ 898{
788 MODULE_FUNCTION_BEGIN (NULL); 899 MODULE_FUNCTION_BEGIN (NULL);
789 mpz_set (mpz[0], value->value); 900 if (sign == 0)
901 return lisp_to_value (env, make_fixed_natnum (0));
902 enum { order = -1, size = sizeof *magnitude, endian = 0, nails = 0 };
903 mpz_import (mpz[0], count, order, size, endian, nails, magnitude);
904 if (sign < 0)
905 mpz_neg (mpz[0], mpz[0]);
790 return lisp_to_value (env, make_integer_mpz ()); 906 return lisp_to_value (env, make_integer_mpz ());
791} 907}
792 908
diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in
index 9955e30eb7a..800c0188ff5 100644
--- a/src/emacs-module.h.in
+++ b/src/emacs-module.h.in
@@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
20#ifndef EMACS_MODULE_H 20#ifndef EMACS_MODULE_H
21#define EMACS_MODULE_H 21#define EMACS_MODULE_H
22 22
23#include <limits.h>
23#include <stdint.h> 24#include <stdint.h>
24#include <stddef.h> 25#include <stddef.h>
25#include <time.h> 26#include <time.h>
@@ -28,10 +29,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
28#include <stdbool.h> 29#include <stdbool.h>
29#endif 30#endif
30 31
31#if defined EMACS_MODULE_GMP && !defined EMACS_MODULE_HAVE_MPZ_T
32#include <gmp.h>
33#endif
34
35#define EMACS_MAJOR_VERSION @emacs_major_version@ 32#define EMACS_MAJOR_VERSION @emacs_major_version@
36 33
37#if defined __cplusplus && __cplusplus >= 201103L 34#if defined __cplusplus && __cplusplus >= 201103L
@@ -100,10 +97,21 @@ enum emacs_process_input_result
100 emacs_process_input_quit = 1 97 emacs_process_input_quit = 1
101}; 98};
102 99
103#ifdef EMACS_MODULE_GMP 100/*
104struct emacs_mpz { mpz_t value; }; 101Implementation note: We define emacs_limb_t so that it is likely to
102match the GMP mp_limb_t type. If the types match, GMP can use an
103optimization for mpz_import and mpz_export that boils down to a
104memcpy. According to https://gmplib.org/manual/ABI-and-ISA.html GMP
105will prefer a 64-bit limb and will default to unsigned long if that is
106wide enough. Note that this is an internal micro-optimization. Users
107shouldn't rely on the exact size of emacs_limb_t.
108*/
109#if ULONG_MAX == 0xFFFFFFFF
110typedef unsigned long long emacs_limb_t;
111# define EMACS_LIMB_MAX ULLONG_MAX
105#else 112#else
106struct emacs_mpz; /* no definition */ 113typedef unsigned long emacs_limb_t;
114# define EMACS_LIMB_MAX ULONG_MAX
107#endif 115#endif
108 116
109struct emacs_env_25 117struct emacs_env_25
diff --git a/src/module-env-27.h b/src/module-env-27.h
index 00de3009007..da8ac0e7479 100644
--- a/src/module-env-27.h
+++ b/src/module-env-27.h
@@ -9,10 +9,10 @@
9 emacs_value (*make_time) (emacs_env *env, struct timespec time) 9 emacs_value (*make_time) (emacs_env *env, struct timespec time)
10 EMACS_ATTRIBUTE_NONNULL (1); 10 EMACS_ATTRIBUTE_NONNULL (1);
11 11
12 void (*extract_big_integer) (emacs_env *env, emacs_value value, 12 bool (*extract_big_integer) (emacs_env *env, emacs_value arg, int *sign,
13 struct emacs_mpz *result) 13 ptrdiff_t *count, unsigned long *magnitude)
14 EMACS_ATTRIBUTE_NONNULL (1, 3); 14 EMACS_ATTRIBUTE_NONNULL (1);
15 15
16 emacs_value (*make_big_integer) (emacs_env *env, 16 emacs_value (*make_big_integer) (emacs_env *env, int sign, ptrdiff_t count,
17 const struct emacs_mpz *value) 17 const unsigned long *magnitude)
18 EMACS_ATTRIBUTE_NONNULL (1, 2); 18 EMACS_ATTRIBUTE_NONNULL (1);
diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c
index 2891b73c1a0..b579c8a6278 100644
--- a/test/data/emacs-module/mod-test.c
+++ b/test/data/emacs-module/mod-test.c
@@ -33,10 +33,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
33#include <gmp.h> 33#include <gmp.h>
34#else 34#else
35#include "mini-gmp.h" 35#include "mini-gmp.h"
36#define EMACS_MODULE_HAVE_MPZ_T
37#endif 36#endif
38 37
39#define EMACS_MODULE_GMP
40#include <emacs-module.h> 38#include <emacs-module.h>
41 39
42#include "timespec.h" 40#include "timespec.h"
@@ -66,6 +64,8 @@ int plugin_is_GPL_compatible;
66# error "INTPTR_MAX too large" 64# error "INTPTR_MAX too large"
67#endif 65#endif
68 66
67/* Smoke test to verify that EMACS_LIMB_MAX is defined. */
68_Static_assert (0 < EMACS_LIMB_MAX, "EMACS_LIMB_MAX missing or incorrect");
69 69
70/* Always return symbol 't'. */ 70/* Always return symbol 't'. */
71static emacs_value 71static emacs_value
@@ -372,23 +372,106 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
372 return env->make_time (env, time); 372 return env->make_time (env, time);
373} 373}
374 374
375static void
376memory_full (emacs_env *env)
377{
378 const char *message = "Memory exhausted";
379 emacs_value data = env->make_string (env, message, strlen (message));
380 env->non_local_exit_signal (env, env->intern (env, "error"),
381 env->funcall (env, env->intern (env, "list"), 1,
382 &data));
383}
384
385enum
386{
387 max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
388 / sizeof (emacs_limb_t))
389};
390
391static bool
392extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
393{
394 int sign;
395 ptrdiff_t count;
396 bool success = env->extract_big_integer (env, arg, &sign, &count, NULL);
397 if (!success)
398 return false;
399 if (sign == 0)
400 {
401 mpz_set_ui (result, 0);
402 return true;
403 }
404 enum { order = -1, size = sizeof (unsigned long), endian = 0, nails = 0 };
405 assert (0 < count && count <= max_count);
406 emacs_limb_t *magnitude = malloc (count * size);
407 if (magnitude == NULL)
408 {
409 memory_full (env);
410 return false;
411 }
412 success = env->extract_big_integer (env, arg, NULL, &count, magnitude);
413 assert (success);
414 mpz_import (result, count, order, size, endian, nails, magnitude);
415 free (magnitude);
416 if (sign < 0)
417 mpz_neg (result, result);
418 return true;
419}
420
421static emacs_value
422make_big_integer (emacs_env *env, const mpz_t value)
423{
424 if (mpz_sgn (value) == 0)
425 return env->make_integer (env, 0);
426 /* See
427 https://gmplib.org/manual/Integer-Import-and-Export.html#index-Export. */
428 enum
429 {
430 order = -1,
431 size = sizeof (emacs_limb_t),
432 endian = 0,
433 nails = 0,
434 numb = 8 * size - nails
435 };
436 size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb;
437 if (max_count < count)
438 {
439 memory_full (env);
440 return NULL;
441 }
442 emacs_limb_t *magnitude = malloc (count * size);
443 if (magnitude == NULL)
444 {
445 memory_full (env);
446 return NULL;
447 }
448 size_t written;
449 mpz_export (magnitude, &written, order, size, endian, nails, value);
450 assert (written == count);
451 assert (count <= PTRDIFF_MAX);
452 emacs_value result = env->make_big_integer (env, mpz_sgn (value),
453 (ptrdiff_t) count, magnitude);
454 free (magnitude);
455 return result;
456}
457
375static emacs_value 458static emacs_value
376Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) { 459Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) {
377 assert (nargs == 1); 460 assert (nargs == 1);
378 struct timespec time = env->extract_time (env, args[0]); 461 struct timespec time = env->extract_time (env, args[0]);
379 struct emacs_mpz nanoseconds; 462 mpz_t nanoseconds;
380 assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX); 463 assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX);
381 mpz_init_set_si (nanoseconds.value, time.tv_sec); 464 mpz_init_set_si (nanoseconds, time.tv_sec);
382#ifdef __MINGW32__ 465#ifdef __MINGW32__
383 _Static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); 466 _Static_assert (1000000000 <= ULONG_MAX, "unsupported architecture");
384#else 467#else
385 static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); 468 static_assert (1000000000 <= ULONG_MAX, "unsupported architecture");
386#endif 469#endif
387 mpz_mul_ui (nanoseconds.value, nanoseconds.value, 1000000000); 470 mpz_mul_ui (nanoseconds, nanoseconds, 1000000000);
388 assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX); 471 assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX);
389 mpz_add_ui (nanoseconds.value, nanoseconds.value, time.tv_nsec); 472 mpz_add_ui (nanoseconds, nanoseconds, time.tv_nsec);
390 emacs_value result = env->make_big_integer (env, &nanoseconds); 473 emacs_value result = make_big_integer (env, nanoseconds);
391 mpz_clear (nanoseconds.value); 474 mpz_clear (nanoseconds);
392 return result; 475 return result;
393} 476}
394 477
@@ -398,12 +481,12 @@ Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
398{ 481{
399 assert (nargs == 1); 482 assert (nargs == 1);
400 emacs_value arg = args[0]; 483 emacs_value arg = args[0];
401 struct emacs_mpz value; 484 mpz_t value;
402 mpz_init (value.value); 485 mpz_init (value);
403 env->extract_big_integer (env, arg, &value); 486 extract_big_integer (env, arg, value);
404 mpz_mul_ui (value.value, value.value, 2); 487 mpz_mul_ui (value, value, 2);
405 emacs_value result = env->make_big_integer (env, &value); 488 emacs_value result = make_big_integer (env, value);
406 mpz_clear (value.value); 489 mpz_clear (value);
407 return result; 490 return result;
408} 491}
409 492