diff options
Diffstat (limited to 'test/data')
| -rw-r--r-- | test/data/emacs-module/mod-test.c | 111 |
1 files changed, 97 insertions, 14 deletions
diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c index 2891b73c1a0..b579c8a6278 100644 --- a/test/data/emacs-module/mod-test.c +++ b/test/data/emacs-module/mod-test.c | |||
| @@ -33,10 +33,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include <gmp.h> | 33 | #include <gmp.h> |
| 34 | #else | 34 | #else |
| 35 | #include "mini-gmp.h" | 35 | #include "mini-gmp.h" |
| 36 | #define EMACS_MODULE_HAVE_MPZ_T | ||
| 37 | #endif | 36 | #endif |
| 38 | 37 | ||
| 39 | #define EMACS_MODULE_GMP | ||
| 40 | #include <emacs-module.h> | 38 | #include <emacs-module.h> |
| 41 | 39 | ||
| 42 | #include "timespec.h" | 40 | #include "timespec.h" |
| @@ -66,6 +64,8 @@ int plugin_is_GPL_compatible; | |||
| 66 | # error "INTPTR_MAX too large" | 64 | # error "INTPTR_MAX too large" |
| 67 | #endif | 65 | #endif |
| 68 | 66 | ||
| 67 | /* Smoke test to verify that EMACS_LIMB_MAX is defined. */ | ||
| 68 | _Static_assert (0 < EMACS_LIMB_MAX, "EMACS_LIMB_MAX missing or incorrect"); | ||
| 69 | 69 | ||
| 70 | /* Always return symbol 't'. */ | 70 | /* Always return symbol 't'. */ |
| 71 | static emacs_value | 71 | static emacs_value |
| @@ -372,23 +372,106 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |||
| 372 | return env->make_time (env, time); | 372 | return env->make_time (env, time); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | static void | ||
| 376 | memory_full (emacs_env *env) | ||
| 377 | { | ||
| 378 | const char *message = "Memory exhausted"; | ||
| 379 | emacs_value data = env->make_string (env, message, strlen (message)); | ||
| 380 | env->non_local_exit_signal (env, env->intern (env, "error"), | ||
| 381 | env->funcall (env, env->intern (env, "list"), 1, | ||
| 382 | &data)); | ||
| 383 | } | ||
| 384 | |||
| 385 | enum | ||
| 386 | { | ||
| 387 | max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) | ||
| 388 | / sizeof (emacs_limb_t)) | ||
| 389 | }; | ||
| 390 | |||
| 391 | static bool | ||
| 392 | extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result) | ||
| 393 | { | ||
| 394 | int sign; | ||
| 395 | ptrdiff_t count; | ||
| 396 | bool success = env->extract_big_integer (env, arg, &sign, &count, NULL); | ||
| 397 | if (!success) | ||
| 398 | return false; | ||
| 399 | if (sign == 0) | ||
| 400 | { | ||
| 401 | mpz_set_ui (result, 0); | ||
| 402 | return true; | ||
| 403 | } | ||
| 404 | enum { order = -1, size = sizeof (unsigned long), endian = 0, nails = 0 }; | ||
| 405 | assert (0 < count && count <= max_count); | ||
| 406 | emacs_limb_t *magnitude = malloc (count * size); | ||
| 407 | if (magnitude == NULL) | ||
| 408 | { | ||
| 409 | memory_full (env); | ||
| 410 | return false; | ||
| 411 | } | ||
| 412 | success = env->extract_big_integer (env, arg, NULL, &count, magnitude); | ||
| 413 | assert (success); | ||
| 414 | mpz_import (result, count, order, size, endian, nails, magnitude); | ||
| 415 | free (magnitude); | ||
| 416 | if (sign < 0) | ||
| 417 | mpz_neg (result, result); | ||
| 418 | return true; | ||
| 419 | } | ||
| 420 | |||
| 421 | static emacs_value | ||
| 422 | make_big_integer (emacs_env *env, const mpz_t value) | ||
| 423 | { | ||
| 424 | if (mpz_sgn (value) == 0) | ||
| 425 | return env->make_integer (env, 0); | ||
| 426 | /* See | ||
| 427 | https://gmplib.org/manual/Integer-Import-and-Export.html#index-Export. */ | ||
| 428 | enum | ||
| 429 | { | ||
| 430 | order = -1, | ||
| 431 | size = sizeof (emacs_limb_t), | ||
| 432 | endian = 0, | ||
| 433 | nails = 0, | ||
| 434 | numb = 8 * size - nails | ||
| 435 | }; | ||
| 436 | size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb; | ||
| 437 | if (max_count < count) | ||
| 438 | { | ||
| 439 | memory_full (env); | ||
| 440 | return NULL; | ||
| 441 | } | ||
| 442 | emacs_limb_t *magnitude = malloc (count * size); | ||
| 443 | if (magnitude == NULL) | ||
| 444 | { | ||
| 445 | memory_full (env); | ||
| 446 | return NULL; | ||
| 447 | } | ||
| 448 | size_t written; | ||
| 449 | mpz_export (magnitude, &written, order, size, endian, nails, value); | ||
| 450 | assert (written == count); | ||
| 451 | assert (count <= PTRDIFF_MAX); | ||
| 452 | emacs_value result = env->make_big_integer (env, mpz_sgn (value), | ||
| 453 | (ptrdiff_t) count, magnitude); | ||
| 454 | free (magnitude); | ||
| 455 | return result; | ||
| 456 | } | ||
| 457 | |||
| 375 | static emacs_value | 458 | static emacs_value |
| 376 | Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) { | 459 | Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) { |
| 377 | assert (nargs == 1); | 460 | assert (nargs == 1); |
| 378 | struct timespec time = env->extract_time (env, args[0]); | 461 | struct timespec time = env->extract_time (env, args[0]); |
| 379 | struct emacs_mpz nanoseconds; | 462 | mpz_t nanoseconds; |
| 380 | assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX); | 463 | assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX); |
| 381 | mpz_init_set_si (nanoseconds.value, time.tv_sec); | 464 | mpz_init_set_si (nanoseconds, time.tv_sec); |
| 382 | #ifdef __MINGW32__ | 465 | #ifdef __MINGW32__ |
| 383 | _Static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); | 466 | _Static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); |
| 384 | #else | 467 | #else |
| 385 | static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); | 468 | static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); |
| 386 | #endif | 469 | #endif |
| 387 | mpz_mul_ui (nanoseconds.value, nanoseconds.value, 1000000000); | 470 | mpz_mul_ui (nanoseconds, nanoseconds, 1000000000); |
| 388 | assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX); | 471 | assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX); |
| 389 | mpz_add_ui (nanoseconds.value, nanoseconds.value, time.tv_nsec); | 472 | mpz_add_ui (nanoseconds, nanoseconds, time.tv_nsec); |
| 390 | emacs_value result = env->make_big_integer (env, &nanoseconds); | 473 | emacs_value result = make_big_integer (env, nanoseconds); |
| 391 | mpz_clear (nanoseconds.value); | 474 | mpz_clear (nanoseconds); |
| 392 | return result; | 475 | return result; |
| 393 | } | 476 | } |
| 394 | 477 | ||
| @@ -398,12 +481,12 @@ Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args, | |||
| 398 | { | 481 | { |
| 399 | assert (nargs == 1); | 482 | assert (nargs == 1); |
| 400 | emacs_value arg = args[0]; | 483 | emacs_value arg = args[0]; |
| 401 | struct emacs_mpz value; | 484 | mpz_t value; |
| 402 | mpz_init (value.value); | 485 | mpz_init (value); |
| 403 | env->extract_big_integer (env, arg, &value); | 486 | extract_big_integer (env, arg, value); |
| 404 | mpz_mul_ui (value.value, value.value, 2); | 487 | mpz_mul_ui (value, value, 2); |
| 405 | emacs_value result = env->make_big_integer (env, &value); | 488 | emacs_value result = make_big_integer (env, value); |
| 406 | mpz_clear (value.value); | 489 | mpz_clear (value); |
| 407 | return result; | 490 | return result; |
| 408 | } | 491 | } |
| 409 | 492 | ||