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.
This commit is contained in:
parent
bffceab633
commit
e290a7d173
8 changed files with 111 additions and 0 deletions
|
@ -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
|
||||
|
|
4
etc/NEWS
4
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue