]> git.eshelyaron.com Git - emacs.git/commitdiff
Add module functions to convert from and to big integers.
authorPhilipp Stephani <phst@google.com>
Thu, 18 Apr 2019 20:38:29 +0000 (22:38 +0200)
committerPhilipp Stephani <phst@google.com>
Wed, 24 Apr 2019 10:53:54 +0000 (12:53 +0200)
* 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.

doc/lispref/internals.texi
etc/NEWS
src/emacs-module.c
src/emacs-module.h.in
src/lisp.h
src/module-env-27.h
test/data/emacs-module/mod-test.c
test/src/emacs-module-tests.el

index 0e7a1339e7625681ef875b3502314ba32f28851d..10f49c569faf9a6be81206d06376f77ad6bfe46a 100644 (file)
@@ -1508,6 +1508,41 @@ function raises the @code{overflow-error} error condition if
 string.
 @end deftypefn
 
+If you define the preprocessor macro @code{EMACS_MODULE_GMP} before
+including the header @file{emacs-module.h}, you can also convert
+between Emacs integers and GMP @code{mpz_t} values.  @xref{GMP
+Basics,,,gmp}.  If @code{EMACS_MODULE_GMP} is defined,
+@file{emacs-module.h} wraps @code{mpz_t} in the following structure:
+
+@deftp struct emacs_mpz value
+struct emacs_mpz @{ mpz_t value; @};
+@end deftp
+
+@noindent
+Then you can use the following additional functions:
+
+@deftypefn Function bool extract_big_integer (emacs_env *@var{env}, emacs_value @var{arg}, struct emacs_mpz *@var{result})
+This function, which is available since Emacs 27, extracts the
+integral value of @var{arg} into @var{result}.  @var{result} must not
+be @code{NULL}.  @code{@var{result}->value} must be an initialized
+@code{mpz_t} object.  @xref{Initializing Integers,,,gmp}.  If
+@var{arg} is an integer, Emacs will store its value into
+@code{@var{result}->value}.  After you have finished using
+@code{@var{result}->value}, you should free it using @code{mpz_clear}
+or similar.
+@end deftypefn
+
+@deftypefn Function emacs_value make_big_integer (emacs_env *@var{env}, const struct emacs_mpz *@var{value})
+This function, which is available since Emacs 27, takes an
+arbitrary-sized integer argument and returns a corresponding
+@code{emacs_value} object.  @var{value} must not be @code{NULL}.
+@code{@var{value}->value} must be an initialized @code{mpz_t} object.
+@xref{Initializing Integers,,,gmp}.  Emacs will return a corresponding
+integral object.  After you have finished using
+@code{@var{value}->value}, you should free it using @code{mpz_clear}
+or similar.
+@end deftypefn
+
 The @acronym{API} does not provide functions to manipulate Lisp data
 structures, for example, create lists with @code{cons} and @code{list}
 (@pxref{Building Lists}), extract list members with @code{car} and
index fc9b828baa1866733e5fc2bdaa46ed0837d64fd3..e861a372b1744d5aed6741f6320625d96b2e4486 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1913,6 +1913,10 @@ case.
 ** New module environment functions 'make_time' and 'extract_time' to
 convert between timespec structures and Emacs Lisp time values.
 
+** New module environment functions 'make_big_integer' and
+'extract_big_integer' to create and extract arbitrary-size integer
+values.
+
 \f
 * Changes in Emacs 27.1 on Non-Free Operating Systems
 
index e46af30ce8449708c94e2e228a46d4301c14bb14..e203ce1d34812628e7c4273080cd9fb94941cde2 100644 (file)
@@ -70,6 +70,7 @@ To add a new module function, proceed as follows:
 
 #include <config.h>
 
+#define EMACS_MODULE_GMP
 #include "emacs-module.h"
 
 #include <stdarg.h>
@@ -79,7 +80,10 @@ To add a new module function, proceed as follows:
 #include <stdlib.h>
 #include <time.h>
 
+#include <gmp.h>
+
 #include "lisp.h"
+#include "bignum.h"
 #include "dynlib.h"
 #include "coding.h"
 #include "keyboard.h"
@@ -752,6 +756,27 @@ module_make_time (emacs_env *env, struct timespec time)
   return lisp_to_value (env, make_lisp_time (time));
 }
 
+static void
+module_extract_big_integer (emacs_env *env, emacs_value value,
+                            struct emacs_mpz *result)
+{
+  MODULE_FUNCTION_BEGIN ();
+  Lisp_Object o = value_to_lisp (value);
+  CHECK_INTEGER (o);
+  if (FIXNUMP (o))
+    mpz_set_intmax (result->value, XFIXNUM (o));
+  else
+    mpz_set (result->value, XBIGNUM (o)->value);
+}
+
+static emacs_value
+module_make_big_integer (emacs_env *env, const struct emacs_mpz *value)
+{
+  MODULE_FUNCTION_BEGIN (NULL);
+  mpz_set (mpz[0], value->value);
+  return lisp_to_value (env, make_integer_mpz ());
+}
+
 \f
 /* Subroutines.  */
 
@@ -1157,6 +1182,8 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv)
   env->process_input = module_process_input;
   env->extract_time = module_extract_time;
   env->make_time = module_make_time;
+  env->extract_big_integer = module_extract_big_integer;
+  env->make_big_integer = module_make_big_integer;
   Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments);
   return env;
 }
index bfbe226dd90f633c27ba16e0f549936bbaa6623b..e61aadfc3acfd6db23d9968181bdd4acaebdf555 100644 (file)
@@ -28,6 +28,10 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <stdbool.h>
 #endif
 
+#ifdef EMACS_MODULE_GMP
+#include <gmp.h>
+#endif
+
 #if defined __cplusplus && __cplusplus >= 201103L
 # define EMACS_NOEXCEPT noexcept
 #else
@@ -94,6 +98,12 @@ enum emacs_process_input_result
   emacs_process_input_quit = 1
 };
 
+#ifdef EMACS_MODULE_GMP
+struct emacs_mpz { mpz_t value; };
+#else
+struct emacs_mpz;  /* no definition */
+#endif
+
 struct emacs_env_25
 {
 @module_env_snippet_25@
index d803f1600061be2aff7f3678436f935c0815dae2..703fe76d64e0957795ff7eeac3e7d199536c700c 100644 (file)
@@ -4151,6 +4151,7 @@ extern void *unexec_realloc (void *, size_t);
 extern void unexec_free (void *);
 #endif
 
+#define EMACS_MODULE_GMP
 #include "emacs-module.h"
 
 /* Function prototype for the module Lisp functions.  */
index e63843f8d6308fe2d5ed05aca333ee3572415685..00de30090074a82f59b1f7eab56452f05bf7f929 100644 (file)
@@ -8,3 +8,11 @@
 
   emacs_value (*make_time) (emacs_env *env, struct timespec time)
     EMACS_ATTRIBUTE_NONNULL (1);
+
+  void (*extract_big_integer) (emacs_env *env, emacs_value value,
+                               struct emacs_mpz *result)
+    EMACS_ATTRIBUTE_NONNULL (1, 3);
+
+  emacs_value (*make_big_integer) (emacs_env *env,
+                                   const struct emacs_mpz *value)
+    EMACS_ATTRIBUTE_NONNULL (1, 2);
index dbdbfecfe6a2331e8ca20e0ebeb546b3e64bfecf..85a7f28e50d094489b3831046f4fc0f583beddde 100644 (file)
@@ -27,8 +27,11 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <string.h>
 #include <time.h>
 
+#define EMACS_MODULE_GMP
 #include <emacs-module.h>
 
+#include <gmp.h>
+
 #include "timespec.h"
 
 int plugin_is_GPL_compatible;
@@ -378,6 +381,21 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
   return env->make_time (env, time);
 }
 
+static emacs_value
+Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
+                  void *data)
+{
+  assert (nargs == 1);
+  emacs_value arg = args[0];
+  struct emacs_mpz value;
+  mpz_init (value.value);
+  env->extract_big_integer (env, arg, &value);
+  mpz_mul_ui (value.value, value.value, 2);
+  emacs_value result = env->make_big_integer (env, &value);
+  mpz_clear (value.value);
+  return result;
+}
+
 /* Lisp utilities for easier readability (simple wrappers).  */
 
 /* Provide FEATURE to Emacs.  */
@@ -447,6 +465,7 @@ emacs_module_init (struct emacs_runtime *ert)
          NULL, NULL);
   DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL);
   DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL);
+  DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL);
 
 #undef DEFUN
 
index eea4c611655e34801797fbf8de5767d9b45c031a..78f238140da148bbad7e52ce59cefedab7daa9e4 100644 (file)
@@ -338,4 +338,11 @@ Interactively, you can try hitting \\[keyboard-quit] to quit."
     (ert-info ((format "input: %s" input))
       (should-error (mod-test-add-nanosecond input)))))
 
+(ert-deftest mod-test-double ()
+  (dolist (input (list 0 1 2 -1 42 12345678901234567890
+                       most-positive-fixnum (1+ most-positive-fixnum)
+                       most-negative-fixnum (1- most-negative-fixnum)))
+    (ert-info ((format "input: %d" input))
+      (should (= (mod-test-double input) (* 2 input))))))
+
 ;;; emacs-module-tests.el ends here