diff options
| author | Philipp Stephani | 2019-04-18 22:38:29 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2019-04-24 12:53:54 +0200 |
| commit | e290a7d1730c99010272bbff7f497c3041cef46d (patch) | |
| tree | d17ccf1313e8b408c6e8cbef64e71a4f1311da4e | |
| parent | bffceab6339fb4042588b893ef754c6264379e75 (diff) | |
| download | emacs-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.texi | 35 | ||||
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | src/emacs-module.c | 27 | ||||
| -rw-r--r-- | src/emacs-module.h.in | 10 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/module-env-27.h | 8 | ||||
| -rw-r--r-- | test/data/emacs-module/mod-test.c | 19 | ||||
| -rw-r--r-- | test/src/emacs-module-tests.el | 7 |
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 | |||
| 1508 | string. | 1508 | string. |
| 1509 | @end deftypefn | 1509 | @end deftypefn |
| 1510 | 1510 | ||
| 1511 | If you define the preprocessor macro @code{EMACS_MODULE_GMP} before | ||
| 1512 | including the header @file{emacs-module.h}, you can also convert | ||
| 1513 | between Emacs integers and GMP @code{mpz_t} values. @xref{GMP | ||
| 1514 | Basics,,,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 | ||
| 1518 | struct emacs_mpz @{ mpz_t value; @}; | ||
| 1519 | @end deftp | ||
| 1520 | |||
| 1521 | @noindent | ||
| 1522 | Then 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}) | ||
| 1525 | This function, which is available since Emacs 27, extracts the | ||
| 1526 | integral value of @var{arg} into @var{result}. @var{result} must not | ||
| 1527 | be @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} | ||
| 1532 | or similar. | ||
| 1533 | @end deftypefn | ||
| 1534 | |||
| 1535 | @deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, const struct emacs_mpz *@var{value}) | ||
| 1536 | This function, which is available since Emacs 27, takes an | ||
| 1537 | arbitrary-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 | ||
| 1541 | integral object. After you have finished using | ||
| 1542 | @code{@var{value}->value}, you should free it using @code{mpz_clear} | ||
| 1543 | or similar. | ||
| 1544 | @end deftypefn | ||
| 1545 | |||
| 1511 | The @acronym{API} does not provide functions to manipulate Lisp data | 1546 | The @acronym{API} does not provide functions to manipulate Lisp data |
| 1512 | structures, for example, create lists with @code{cons} and @code{list} | 1547 | structures, 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 |
| @@ -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 |
| 1914 | convert between timespec structures and Emacs Lisp time values. | 1914 | convert 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 | ||
| 1918 | values. | ||
| 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 | ||
| 759 | static void | ||
| 760 | module_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 | |||
| 772 | static emacs_value | ||
| 773 | module_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 | ||
| 102 | struct emacs_mpz { mpz_t value; }; | ||
| 103 | #else | ||
| 104 | struct emacs_mpz; /* no definition */ | ||
| 105 | #endif | ||
| 106 | |||
| 97 | struct emacs_env_25 | 107 | struct 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); | |||
| 4151 | extern void unexec_free (void *); | 4151 | extern 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 | ||
| 34 | int plugin_is_GPL_compatible; | 37 | int 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 | ||
| 384 | static emacs_value | ||
| 385 | Fmod_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 |