[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] master e290a7d 2/2: Add module functions to convert from a
From: |
Philipp Stephani |
Subject: |
[Emacs-diffs] master e290a7d 2/2: Add module functions to convert from and to big integers. |
Date: |
Wed, 24 Apr 2019 06:58:38 -0400 (EDT) |
branch: master
commit e290a7d1730c99010272bbff7f497c3041cef46d
Author: Philipp Stephani <address@hidden>
Commit: Philipp Stephani <address@hidden>
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.
---
doc/lispref/internals.texi | 35 +++++++++++++++++++++++++++++++++++
etc/NEWS | 4 ++++
src/emacs-module.c | 27 +++++++++++++++++++++++++++
src/emacs-module.h.in | 10 ++++++++++
src/lisp.h | 1 +
src/module-env-27.h | 8 ++++++++
test/data/emacs-module/mod-test.c | 19 +++++++++++++++++++
test/src/emacs-module-tests.el | 7 +++++++
8 files changed, 111 insertions(+)
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 0e7a133..10f49c5 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -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,
address@hidden wraps @code{mpz_t} in the following structure:
+
address@hidden struct emacs_mpz value
+struct emacs_mpz @{ mpz_t value; @};
address@hidden deftp
+
address@hidden
+Then you can use the following additional functions:
+
address@hidden Function bool extract_big_integer (emacs_env address@hidden,
emacs_value @var{arg}, struct emacs_mpz address@hidden)
+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}. @address@hidden>value} must be an initialized
address@hidden object. @xref{Initializing Integers,,,gmp}. If
address@hidden is an integer, Emacs will store its value into
address@hidden@var{result}->value}. After you have finished using
address@hidden@var{result}->value}, you should free it using @code{mpz_clear}
+or similar.
address@hidden deftypefn
+
address@hidden Function emacs_value make_big_integer (emacs_env address@hidden,
const struct emacs_mpz address@hidden)
+This function, which is available since Emacs 27, takes an
+arbitrary-sized integer argument and returns a corresponding
address@hidden object. @var{value} must not be @code{NULL}.
address@hidden@var{value}->value} must be an initialized @code{mpz_t} object.
address@hidden Integers,,,gmp}. Emacs will return a corresponding
+integral object. After you have finished using
address@hidden@var{value}->value}, you should free it using @code{mpz_clear}
+or similar.
address@hidden 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
diff --git a/etc/NEWS b/etc/NEWS
index fc9b828..e861a37 100644
--- 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.
+
* Changes in Emacs 27.1 on Non-Free Operating Systems
diff --git a/src/emacs-module.c b/src/emacs-module.c
index e46af30..e203ce1 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -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 ());
+}
+
/* 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;
}
diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in
index bfbe226..e61aadf 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/>. */
#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@
diff --git a/src/lisp.h b/src/lisp.h
index d803f16..703fe76 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -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. */
diff --git a/src/module-env-27.h b/src/module-env-27.h
index e63843f..00de300 100644
--- a/src/module-env-27.h
+++ b/src/module-env-27.h
@@ -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);
diff --git a/test/data/emacs-module/mod-test.c
b/test/data/emacs-module/mod-test.c
index dbdbfec..85a7f28 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/>. */
#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
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el
index eea4c61..78f2381 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."
(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