aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Stephani2019-04-18 22:38:29 +0200
committerPhilipp Stephani2019-04-24 12:53:54 +0200
commite290a7d1730c99010272bbff7f497c3041cef46d (patch)
treed17ccf1313e8b408c6e8cbef64e71a4f1311da4e
parentbffceab6339fb4042588b893ef754c6264379e75 (diff)
downloademacs-e290a7d1730c99010272bbff7f497c3041cef46d.tar.gz
emacs-e290a7d1730c99010272bbff7f497c3041cef46d.zip
Add module functions to convert from and to big integers.
* src/module-env-27.h: Add new module functions to convert big integers. * src/emacs-module.h.in (emacs_mpz): Define if GMP is available. * src/emacs-module.c (module_extract_big_integer) (module_make_big_integer): New functions. (initialize_environment): Use them. * test/data/emacs-module/mod-test.c (Fmod_test_double): New test function. (emacs_module_init): Define it. * test/src/emacs-module-tests.el (mod-test-double): New unit test. * doc/lispref/internals.texi (Module Values): Document new functions.
-rw-r--r--doc/lispref/internals.texi35
-rw-r--r--etc/NEWS4
-rw-r--r--src/emacs-module.c27
-rw-r--r--src/emacs-module.h.in10
-rw-r--r--src/lisp.h1
-rw-r--r--src/module-env-27.h8
-rw-r--r--test/data/emacs-module/mod-test.c19
-rw-r--r--test/src/emacs-module-tests.el7
8 files changed, 111 insertions, 0 deletions
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 0e7a1339e76..10f49c569fa 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -1508,6 +1508,41 @@ function raises the @code{overflow-error} error condition if
1508string. 1508string.
1509@end deftypefn 1509@end deftypefn
1510 1510
1511If you define the preprocessor macro @code{EMACS_MODULE_GMP} before
1512including the header @file{emacs-module.h}, you can also convert
1513between Emacs integers and GMP @code{mpz_t} values. @xref{GMP
1514Basics,,,gmp}. If @code{EMACS_MODULE_GMP} is defined,
1515@file{emacs-module.h} wraps @code{mpz_t} in the following structure:
1516
1517@deftp struct emacs_mpz value
1518struct emacs_mpz @{ mpz_t value; @};
1519@end deftp
1520
1521@noindent
1522Then you can use the following additional functions:
1523
1524@deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, struct emacs_mpz *@var{result})
1525This function, which is available since Emacs 27, extracts the
1526integral value of @var{arg} into @var{result}. @var{result} must not
1527be @code{NULL}. @code{@var{result}->value} must be an initialized
1528@code{mpz_t} object. @xref{Initializing Integers,,,gmp}. If
1529@var{arg} is an integer, Emacs will store its value into
1530@code{@var{result}->value}. After you have finished using
1531@code{@var{result}->value}, you should free it using @code{mpz_clear}
1532or similar.
1533@end deftypefn
1534
1535@deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, const struct emacs_mpz *@var{value})
1536This function, which is available since Emacs 27, takes an
1537arbitrary-sized integer argument and returns a corresponding
1538@code{emacs_value} object. @var{value} must not be @code{NULL}.
1539@code{@var{value}->value} must be an initialized @code{mpz_t} object.
1540@xref{Initializing Integers,,,gmp}. Emacs will return a corresponding
1541integral object. After you have finished using
1542@code{@var{value}->value}, you should free it using @code{mpz_clear}
1543or similar.
1544@end deftypefn
1545
1511The @acronym{API} does not provide functions to manipulate Lisp data 1546The @acronym{API} does not provide functions to manipulate Lisp data
1512structures, for example, create lists with @code{cons} and @code{list} 1547structures, for example, create lists with @code{cons} and @code{list}
1513(@pxref{Building Lists}), extract list members with @code{car} and 1548(@pxref{Building Lists}), extract list members with @code{car} and
diff --git a/etc/NEWS b/etc/NEWS
index fc9b828baa1..e861a372b17 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1913,6 +1913,10 @@ case.
1913** New module environment functions 'make_time' and 'extract_time' to 1913** New module environment functions 'make_time' and 'extract_time' to
1914convert between timespec structures and Emacs Lisp time values. 1914convert between timespec structures and Emacs Lisp time values.
1915 1915
1916** New module environment functions 'make_big_integer' and
1917'extract_big_integer' to create and extract arbitrary-size integer
1918values.
1919
1916 1920
1917* Changes in Emacs 27.1 on Non-Free Operating Systems 1921* Changes in Emacs 27.1 on Non-Free Operating Systems
1918 1922
diff --git a/src/emacs-module.c b/src/emacs-module.c
index e46af30ce84..e203ce1d348 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -70,6 +70,7 @@ To add a new module function, proceed as follows:
70 70
71#include <config.h> 71#include <config.h>
72 72
73#define EMACS_MODULE_GMP
73#include "emacs-module.h" 74#include "emacs-module.h"
74 75
75#include <stdarg.h> 76#include <stdarg.h>
@@ -79,7 +80,10 @@ To add a new module function, proceed as follows:
79#include <stdlib.h> 80#include <stdlib.h>
80#include <time.h> 81#include <time.h>
81 82
83#include <gmp.h>
84
82#include "lisp.h" 85#include "lisp.h"
86#include "bignum.h"
83#include "dynlib.h" 87#include "dynlib.h"
84#include "coding.h" 88#include "coding.h"
85#include "keyboard.h" 89#include "keyboard.h"
@@ -752,6 +756,27 @@ module_make_time (emacs_env *env, struct timespec time)
752 return lisp_to_value (env, make_lisp_time (time)); 756 return lisp_to_value (env, make_lisp_time (time));
753} 757}
754 758
759static void
760module_extract_big_integer (emacs_env *env, emacs_value value,
761 struct emacs_mpz *result)
762{
763 MODULE_FUNCTION_BEGIN ();
764 Lisp_Object o = value_to_lisp (value);
765 CHECK_INTEGER (o);
766 if (FIXNUMP (o))
767 mpz_set_intmax (result->value, XFIXNUM (o));
768 else
769 mpz_set (result->value, XBIGNUM (o)->value);
770}
771
772static emacs_value
773module_make_big_integer (emacs_env *env, const struct emacs_mpz *value)
774{
775 MODULE_FUNCTION_BEGIN (NULL);
776 mpz_set (mpz[0], value->value);
777 return lisp_to_value (env, make_integer_mpz ());
778}
779
755 780
756/* Subroutines. */ 781/* Subroutines. */
757 782
@@ -1157,6 +1182,8 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv)
1157 env->process_input = module_process_input; 1182 env->process_input = module_process_input;
1158 env->extract_time = module_extract_time; 1183 env->extract_time = module_extract_time;
1159 env->make_time = module_make_time; 1184 env->make_time = module_make_time;
1185 env->extract_big_integer = module_extract_big_integer;
1186 env->make_big_integer = module_make_big_integer;
1160 Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments); 1187 Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments);
1161 return env; 1188 return env;
1162} 1189}
diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in
index bfbe226dd90..e61aadfc3ac 100644
--- a/src/emacs-module.h.in
+++ b/src/emacs-module.h.in
@@ -28,6 +28,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
28#include <stdbool.h> 28#include <stdbool.h>
29#endif 29#endif
30 30
31#ifdef EMACS_MODULE_GMP
32#include <gmp.h>
33#endif
34
31#if defined __cplusplus && __cplusplus >= 201103L 35#if defined __cplusplus && __cplusplus >= 201103L
32# define EMACS_NOEXCEPT noexcept 36# define EMACS_NOEXCEPT noexcept
33#else 37#else
@@ -94,6 +98,12 @@ enum emacs_process_input_result
94 emacs_process_input_quit = 1 98 emacs_process_input_quit = 1
95}; 99};
96 100
101#ifdef EMACS_MODULE_GMP
102struct emacs_mpz { mpz_t value; };
103#else
104struct emacs_mpz; /* no definition */
105#endif
106
97struct emacs_env_25 107struct emacs_env_25
98{ 108{
99@module_env_snippet_25@ 109@module_env_snippet_25@
diff --git a/src/lisp.h b/src/lisp.h
index d803f160006..703fe76d64e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4151,6 +4151,7 @@ extern void *unexec_realloc (void *, size_t);
4151extern void unexec_free (void *); 4151extern void unexec_free (void *);
4152#endif 4152#endif
4153 4153
4154#define EMACS_MODULE_GMP
4154#include "emacs-module.h" 4155#include "emacs-module.h"
4155 4156
4156/* Function prototype for the module Lisp functions. */ 4157/* Function prototype for the module Lisp functions. */
diff --git a/src/module-env-27.h b/src/module-env-27.h
index e63843f8d63..00de3009007 100644
--- a/src/module-env-27.h
+++ b/src/module-env-27.h
@@ -8,3 +8,11 @@
8 8
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
12 void (*extract_big_integer) (emacs_env *env, emacs_value value,
13 struct emacs_mpz *result)
14 EMACS_ATTRIBUTE_NONNULL (1, 3);
15
16 emacs_value (*make_big_integer) (emacs_env *env,
17 const struct emacs_mpz *value)
18 EMACS_ATTRIBUTE_NONNULL (1, 2);
diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c
index dbdbfecfe6a..85a7f28e50d 100644
--- a/test/data/emacs-module/mod-test.c
+++ b/test/data/emacs-module/mod-test.c
@@ -27,8 +27,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
27#include <string.h> 27#include <string.h>
28#include <time.h> 28#include <time.h>
29 29
30#define EMACS_MODULE_GMP
30#include <emacs-module.h> 31#include <emacs-module.h>
31 32
33#include <gmp.h>
34
32#include "timespec.h" 35#include "timespec.h"
33 36
34int plugin_is_GPL_compatible; 37int plugin_is_GPL_compatible;
@@ -378,6 +381,21 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
378 return env->make_time (env, time); 381 return env->make_time (env, time);
379} 382}
380 383
384static emacs_value
385Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
386 void *data)
387{
388 assert (nargs == 1);
389 emacs_value arg = args[0];
390 struct emacs_mpz value;
391 mpz_init (value.value);
392 env->extract_big_integer (env, arg, &value);
393 mpz_mul_ui (value.value, value.value, 2);
394 emacs_value result = env->make_big_integer (env, &value);
395 mpz_clear (value.value);
396 return result;
397}
398
381/* Lisp utilities for easier readability (simple wrappers). */ 399/* Lisp utilities for easier readability (simple wrappers). */
382 400
383/* Provide FEATURE to Emacs. */ 401/* Provide FEATURE to Emacs. */
@@ -447,6 +465,7 @@ emacs_module_init (struct emacs_runtime *ert)
447 NULL, NULL); 465 NULL, NULL);
448 DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL); 466 DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL);
449 DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL); 467 DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL);
468 DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL);
450 469
451#undef DEFUN 470#undef DEFUN
452 471
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el
index eea4c611655..78f238140da 100644
--- a/test/src/emacs-module-tests.el
+++ b/test/src/emacs-module-tests.el
@@ -338,4 +338,11 @@ Interactively, you can try hitting \\[keyboard-quit] to quit."
338 (ert-info ((format "input: %s" input)) 338 (ert-info ((format "input: %s" input))
339 (should-error (mod-test-add-nanosecond input))))) 339 (should-error (mod-test-add-nanosecond input)))))
340 340
341(ert-deftest mod-test-double ()
342 (dolist (input (list 0 1 2 -1 42 12345678901234567890
343 most-positive-fixnum (1+ most-positive-fixnum)
344 most-negative-fixnum (1- most-negative-fixnum)))
345 (ert-info ((format "input: %d" input))
346 (should (= (mod-test-double input) (* 2 input))))))
347
341;;; emacs-module-tests.el ends here 348;;; emacs-module-tests.el ends here