summaryrefslogtreecommitdiff
path: root/libguile/chars.h
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/chars.h')
-rw-r--r--libguile/chars.h21
1 files changed, 12 insertions, 9 deletions
diff --git a/libguile/chars.h b/libguile/chars.h
index 488dd255f..505a7f9c8 100644
--- a/libguile/chars.h
+++ b/libguile/chars.h
@@ -3,7 +3,8 @@
#ifndef SCM_CHARS_H
#define SCM_CHARS_H
-/* Copyright (C) 1995,1996,2000,2001,2004, 2006, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996, 2000, 2001, 2004, 2006, 2008, 2009, 2019
+ * Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -36,16 +37,18 @@ typedef scm_t_int32 scm_t_wchar;
#define SCM_CHARP(x) (SCM_ITAG8(x) == scm_tc8_char)
#define SCM_CHAR(x) ((scm_t_wchar)SCM_ITAG8_DATA(x))
-/* SCM_MAKE_CHAR maps signed chars (-128 to 127) and unsigned chars (0
- to 255) to Latin-1 codepoints (0 to 255) while allowing higher
+/* SCM_MAKE_CHAR maps signed chars (-128 to 127) and unsigned chars
+ (0 to 255) to Latin-1 codepoints (0 to 255) while allowing higher
codepoints (256 to 1114111) to pass through unchanged.
- This macro evaluates x twice, which may lead to side effects if not
- used properly. */
-#define SCM_MAKE_CHAR(x) \
- ((x) <= 1 \
- ? SCM_MAKE_ITAG8 ((scm_t_bits) (unsigned char) (x), scm_tc8_char) \
- : SCM_MAKE_ITAG8 ((scm_t_bits) (x), scm_tc8_char))
+ To avoid evaluating X more than once, we use an arithmetic trick: we
+ compute (X mod 2^N) mod (2^N - 256), which is equal to the required
+ mapping in the range -256 .. (2^N - 257). Here, N is the number of
+ bits in scm_t_bits. Note that (scm_t_bits) (x) implicitly computes
+ (X mod 2^N), and (scm_t_bits) -256 equals (2^N - 256). GCC is able
+ to optimize away these operations in practice. */
+#define SCM_MAKE_CHAR(x) \
+ (SCM_MAKE_ITAG8 ((scm_t_bits) (x) % (scm_t_bits) -256, scm_tc8_char))
#define SCM_CODEPOINT_DOTTED_CIRCLE (0x25cc)
#define SCM_CODEPOINT_SURROGATE_START (0xd800)