1 /*===========================================================================
2  *  Filename : scmint.h
3  *  About    : Integer types for Scheme implementation
4  *
5  *  Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
6  *  Copyright (c) 2007-2008 SigScheme Project <uim-en AT googlegroups.com>
7  *
8  *  All rights reserved.
9  *
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions
12  *  are met:
13  *
14  *  1. Redistributions of source code must retain the above copyright
15  *     notice, this list of conditions and the following disclaimer.
16  *  2. Redistributions in binary form must reproduce the above copyright
17  *     notice, this list of conditions and the following disclaimer in the
18  *     documentation and/or other materials provided with the distribution.
19  *  3. Neither the name of authors nor the names of its contributors
20  *     may be used to endorse or promote products derived from this software
21  *     without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
24  *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
27  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30  *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33  *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 ===========================================================================*/
35 
36 /*
37  * This file is independent of SigScheme and can be used to implement Scheme
38  * implementation-neutral generic subordinate parts, such as ports and
39  * character encoding handlers. In our short-term development, this separation
40  * aims that making the underlying port implementations and encoding handlers
41  * directly usable from libuim without SigScheme. It is needed to make libuim
42  * Scheme-implementation independent without problems caused by differences of
43  * implementation-specific character encoding handling behaviors.
44  *
45  * The copyright will be succeeded to the uim Project once the subordinate
46  * parts are completely separated from SigScheme.
47  *
48  *   -- YamaKen 2006-03-30
49  */
50 
51 #ifndef __SCM_SCMINT_H
52 #define __SCM_SCMINT_H
53 
54 #include <sigscheme/config.h>
55 
56 #if HAVE_STDINT_H
57 #include <stdint.h>
58 #endif
59 #if HAVE_INTTYPES_H
60 #include <inttypes.h>
61 #endif
62 #if HAVE_SYS_INTTYPES_H
63 #include <sys/inttypes.h>
64 #endif
65 #if HAVE_SYS_TYPES_H
66 #include <sys/types.h>
67 #endif
68 #include <limits.h>
69 
70 #ifdef __cplusplus
71 extern "C" {
72 #endif
73 
74 /*=======================================
75   Macro Definitions
76 =======================================*/
77 #ifndef SCM_EMPTY_EXPR
78 #define SCM_EMPTY_EXPR ((void)0)
79 #endif
80 
81 /*=======================================
82   Type Definitions: stdint.h subtitutes
83 =======================================*/
84 #define SCM_STDINT_MIN(t) ((t)(~(u##t)0))
85 #define SCM_STDINT_MAX(t) ((t)((~(u##t)0) >> 1))
86 
87 /* Note: Since these macros are not pure constant such as (-1LL), testing in
88  * preprocessor directives (such as #if INT32_MAX < LONG_MAX) does not work. */
89 #ifndef INT8_MIN
90 #define INT8_MIN    SCM_STDINT_MIN(int8_t)
91 #endif
92 #ifndef INT16_MIN
93 #define INT16_MIN   SCM_STDINT_MIN(int16_t)
94 #endif
95 #ifndef INT32_MIN
96 #define INT32_MIN   SCM_STDINT_MIN(int32_t)
97 #endif
98 #ifndef INT64_MIN
99 #define INT64_MIN   SCM_STDINT_MIN(int64_t)
100 #endif
101 #ifndef INTMAX_MIN
102 #define INTMAX_MIN  SCM_STDINT_MIN(intmax_t)
103 #endif
104 #ifndef INTPTR_MIN
105 #define INTPTR_MIN  SCM_STDINT_MIN(intptr_t)
106 #endif
107 
108 #ifndef INT8_MAX
109 #define INT8_MAX    SCM_STDINT_MAX(int8_t)
110 #endif
111 #ifndef INT16_MAX
112 #define INT16_MAX   SCM_STDINT_MAX(int16_t)
113 #endif
114 #ifndef INT32_MAX
115 #define INT32_MAX   SCM_STDINT_MAX(int32_t)
116 #endif
117 #ifndef INT64_MAX
118 #define INT64_MAX   SCM_STDINT_MAX(int64_t)
119 #endif
120 #ifndef INTMAX_MAX
121 #define INTMAX_MAX  SCM_STDINT_MAX(intmax_t)
122 #endif
123 #ifndef INTPTR_MAX
124 #define INTPTR_MAX  SCM_STDINT_MAX(intptr_t)
125 #endif
126 
127 #ifndef UINT8_MAX
128 #define UINT8_MAX   (~(uint8_t)0)
129 #endif
130 #ifndef UINT16_MAX
131 #define UINT16_MAX  (~(uint16_t)0)
132 #endif
133 #ifndef UINT32_MAX
134 #define UINT32_MAX  (~(uint32_t)0)
135 #endif
136 #ifndef UINT64_MAX
137 #define UINT64_MAX  (~(uint64_t)0)
138 #endif
139 #ifndef UINTMAX_MAX
140 #define UINTMAX_MAX (~(uintmax_t)0)
141 #endif
142 #ifndef UINTPTR_MAX
143 #define UINTPTR_MAX (~(uintptr_t)0)
144 #endif
145 
146 /*=======================================
147   Type Definitions
148 =======================================*/
149 /*
150  * Our own Boolean type
151  *
152  * libsscm does not use C99 stdbool, its autoconf equivalent or popular
153  * combination of {int, TRUE, FALSE}, to avoid system-dependent ABI
154  * incompatibility (such as size difference) and client-dependent problems
155  * (such as an unexpected assumption about TRUE value).
156  *
157  * The definition use plain typedef and macro definition to avoid
158  * misrecognition about the usage of the type, such as enum-related ones.
159  *
160  *                           *** IMPORTANT ***
161  *
162  * Do not test a value with (val == scm_true). The scm_true is only A TYPICAL
163  * VALUE FOR TRUE. Use (val) or (val != scm_false) instead.
164  *
165  */
166 typedef int scm_bool;
167 #define scm_false 0
168 #define scm_true  1
169 
170 /*
171  * Fixed bit width numbers
172  *
173  * This types define internal representation corresponding to each number
174  * objects of Scheme.
175  *
176  * The configuration alters both ABI and storage implementation of
177  * libsscm. Although it specifies the bit width, actual width varies for each
178  * underlying storage implementation. Refer SCM_INT_BITS, SCM_INT_MAX and so
179  * on to know such values.
180  *
181  * The integer type defaults to 64-bit on LP64 platforms.
182  */
183 #if SCM_USE_64BIT_FIXNUM
184 typedef int64_t            scm_int_t;
185 typedef uint64_t           scm_uint_t;
186 #define ALIGNOF_SCM_INT_T  ALIGNOF_INT64_T
187 #define ALIGNOF_SCM_UINT_T ALIGNOF_INT64_T
188 #define SIZEOF_SCM_INT_T   SIZEOF_INT64_T
189 #define SIZEOF_SCM_UINT_T  SIZEOF_INT64_T
190 #define SCM_INT_T_MAX      INT64_MAX
191 #define SCM_INT_T_MIN      INT64_MIN
192 #define SCM_UINT_T_MAX     UINT64_MAX
193 #elif SCM_USE_32BIT_FIXNUM
194 typedef int32_t            scm_int_t;
195 typedef uint32_t           scm_uint_t;
196 #define ALIGNOF_SCM_INT_T  ALIGNOF_INT32_T
197 #define ALIGNOF_SCM_UINT_T ALIGNOF_INT32_T
198 #define SIZEOF_SCM_INT_T   SIZEOF_INT32_T
199 #define SIZEOF_SCM_UINT_T  SIZEOF_INT32_T
200 #define SCM_INT_T_MAX      INT32_MAX
201 #define SCM_INT_T_MIN      INT32_MIN
202 #define SCM_UINT_T_MAX     UINT32_MAX
203 #elif SCM_USE_INT_FIXNUM
204 typedef int                scm_int_t;
205 typedef unsigned int       scm_uint_t;
206 #define ALIGNOF_SCM_INT_T  ALIGNOF_INT
207 #define ALIGNOF_SCM_UINT_T ALIGNOF_INT
208 #define SIZEOF_SCM_INT_T   SIZEOF_INT
209 #define SIZEOF_SCM_UINT_T  SIZEOF_INT
210 #define SCM_INT_T_MAX      INT_MAX
211 #define SCM_INT_T_MIN      INT_MIN
212 #define SCM_UINT_T_MAX     UINT_MAX
213 #else
214 #undef  SCM_USE_LONG_FIXNUM
215 #define SCM_USE_LONG_FIXNUM 1
216 typedef long               scm_int_t;
217 typedef unsigned long      scm_uint_t;
218 #define ALIGNOF_SCM_INT_T  ALIGNOF_LONG
219 #define ALIGNOF_SCM_UINT_T ALIGNOF_LONG
220 #define SIZEOF_SCM_INT_T   SIZEOF_LONG
221 #define SIZEOF_SCM_UINT_T  SIZEOF_LONG
222 #define SCM_INT_T_MAX      LONG_MAX
223 #define SCM_INT_T_MIN      LONG_MIN
224 #define SCM_UINT_T_MAX     ULONG_MAX
225 #endif
226 
227 /*
228  * Integer representation of abstract reference to ScmObj
229  *
230  * This types define sufficient width integer which is capable of holding any
231  * ScmRef that is used in currently selected storage implementation.
232  *
233  * A ScmRef is abstract reference to a ScmObj. It is usually a pointer, but do
234  * not assume it since another representation may be used. For instance, a pair
235  * of heap index and object index in the heap can be a ScmRef. In such case,
236  * scm_uintref_t can address any object in a heap scattered in full 64-bit
237  * address space even if the bit width of the reference is smaller than a
238  * 64-bit pointer. So any size assumption between pointer and the reference
239  * must not be coded.
240  *
241  * The integer representation is intended for low-level bitwise processing. Use
242  * ScmRef instead for higher-level code.
243  *
244  * Since actual representation is entirely controlled in each storage
245  * implementation, this configuration only specifies the ABI about maximum size
246  * of reference objects. Deal with particular storage implementation if fine
247  * tuning is required. Otherwise simply keep untouched.
248  *
249  * The type defaults to direct pointer represenation, so *LP64 gets 64-bit.
250  */
251 #if SCM_USE_64BIT_SCMREF
252 typedef int64_t               scm_intref_t;
253 typedef uint64_t              scm_uintref_t;
254 #define ALIGNOF_SCM_INTREF_T  ALIGNOF_INT64_T
255 #define ALIGNOF_SCM_UINTREF_T ALIGNOF_INT64_T
256 #define SIZEOF_SCM_INTREF_T   SIZEOF_INT64_T
257 #define SIZEOF_SCM_UINTREF_T  SIZEOF_INT64_T
258 #elif SCM_USE_32BIT_SCMREF
259 typedef int32_t               scm_intref_t;
260 typedef uint32_t              scm_uintref_t;
261 #define ALIGNOF_SCM_INTREF_T  ALIGNOF_INT32_T
262 #define ALIGNOF_SCM_UINTREF_T ALIGNOF_INT32_T
263 #define SIZEOF_SCM_INTREF_T   SIZEOF_INT32_T
264 #define SIZEOF_SCM_UINTREF_T  SIZEOF_INT32_T
265 #else
266 #undef  SCM_USE_INTPTR_SCMREF
267 #define SCM_USE_INTPTR_SCMREF 1
268 typedef intptr_t              scm_intref_t;
269 typedef uintptr_t             scm_uintref_t;
270 #define ALIGNOF_SCM_INTREF_T  ALIGNOF_INTPTR_T
271 #define ALIGNOF_SCM_UINTREF_T ALIGNOF_INTPTR_T
272 #define SIZEOF_SCM_INTREF_T   SIZEOF_INTPTR_T
273 #define SIZEOF_SCM_UINTREF_T  SIZEOF_INTPTR_T
274 #endif
275 
276 /*
277  * Integer representation of ScmObj
278  *
279  * This types define sufficient width integer which is capable of holding the
280  * ScmObj that is used in currently selected storage implementation.
281  *
282  * A ScmObj is abstract Scheme object. Its represenation and size vary for each
283  * storage implementations. But the size is surely defined as larger one of
284  * scm_uint_t and scm_uintref_t. It can be assumed on coding.
285  *
286  * The integer representation is intended for low-level bitwise processing. Use
287  * ScmObj instead for higher-level code.
288  *
289  * This configuration is passively chosen in accordance with the fixnum size
290  * and reference size. And of course alters the ABI.
291  */
292 #if (SIZEOF_SCM_INT_T < SIZEOF_SCM_INTREF_T)
293 typedef scm_intref_t          scm_intobj_t;
294 typedef scm_uintref_t         scm_uintobj_t;
295 #define ALIGNOF_SCM_INTOBJ_T  ALIGNOF_SCM_INTREF_T
296 #define ALIGNOF_SCM_UINTOBJ_T ALIGNOF_SCM_UINTREF_T
297 #define SIZEOF_SCM_INTOBJ_T   SIZEOF_SCM_INTREF_T
298 #define SIZEOF_SCM_UINTOBJ_T  SIZEOF_SCM_UINTREF_T
299 #else
300 typedef scm_int_t             scm_intobj_t;
301 typedef scm_uint_t            scm_uintobj_t;
302 #define ALIGNOF_SCM_INTOBJ_T  ALIGNOF_SCM_INT_T
303 #define ALIGNOF_SCM_UINTOBJ_T ALIGNOF_SCM_UINT_T
304 #define SIZEOF_SCM_INTOBJ_T   SIZEOF_SCM_INT_T
305 #define SIZEOF_SCM_UINTOBJ_T  SIZEOF_SCM_UINT_T
306 #endif
307 
308 /*
309  * Internal integer representation of Scheme character object
310  *
311  * The type is used to pass a Scheme-level character object in C codes.
312  *
313  * It is distinguished from the element of fixed-width character string
314  * (scm_wchar_t). This integer type is defined as wide as capable of any
315  * multibyte char, and not configurable, to keep ABI stable regardless of
316  * configuration about scm_wchar_t.
317  *
318  * Actual bit width varies for each storage implementation. Refer
319  * SCM_CHAR_BITS, SCM_CHAR_MAX and SCM_CHAR_MIN if needed.
320  */
321 typedef int32_t             scm_ichar_t;
322 #define ALIGNOF_SCM_ICHAR_T ALIGNOF_INT32_T
323 #define SIZEOF_SCM_ICHAR_T  SIZEOF_INT32_T
324 #define SCM_ICHAR_T_MAX     INT32_MAX
325 #define SCM_ICHAR_T_MIN     INT32_MIN
326 #define SCM_ICHAR_EOF       (-1)
327 
328 /*
329  * Definitive byte type
330  *
331  * To avoid the sign-extension problem, platform-dependent signedness variation
332  * (for example, ARM compilers treat 'char' as 'unsigned char'), use this type
333  * for raw strings and so on.
334  */
335 typedef unsigned char       scm_byte_t;
336 #define ALIGNOF_SCM_BYTE_T  ALIGNOF_CHAR
337 #define SIZEOF_SCM_BYTE_T   SIZEOF_CHAR
338 #define SCM_BYTE_T_MAX      UCHAR_MAX
339 #define SCM_BYTE_T_MIN      0
340 
341 /*
342  * Constant-width character for strings (not used yet)
343  */
344 #if SCM_HAS_4OCT_WCHAR
345 typedef uint32_t            scm_wchar_t;
346 #define ALIGNOF_SCM_WCHAR_T ALIGNOF_INT32_T
347 #define SIZEOF_SCM_WCHAR_T  SIZEOF_INT32_T
348 #elif SCM_HAS_2OCT_WCHAR
349 typedef uint16_t            scm_wchar_t;
350 #define ALIGNOF_SCM_WCHAR_T ALIGNOF_INT16_T
351 #define SIZEOF_SCM_WCHAR_T  SIZEOF_INT16_T
352 #else
353 typedef scm_byte_t          scm_wchar_t;
354 #define ALIGNOF_SCM_WCHAR_T ALIGNOF_SCM_BYTE_T
355 #define SIZEOF_SCM_WCHAR_T  SIZEOF_SCM_BYTE_T
356 #endif
357 
358 /* size constraints */
359 #if !(   SIZEOF_SCM_INT_T    == SIZEOF_SCM_UINT_T                            \
360       && SIZEOF_SCM_INTREF_T == SIZEOF_SCM_UINTREF_T                         \
361       && SIZEOF_SCM_INTOBJ_T == SIZEOF_SCM_UINTOBJ_T                         \
362       && SIZEOF_SCM_INTREF_T <= SIZEOF_SCM_INTOBJ_T                          \
363       && SIZEOF_SCM_INT_T    <= SIZEOF_SCM_INTOBJ_T                          \
364       && ((SIZEOF_SCM_UINTREF_T <= SIZEOF_SCM_UINT_T                         \
365            && SIZEOF_SCM_UINTOBJ_T == SIZEOF_SCM_UINT_T)                     \
366           || (SIZEOF_SCM_UINTREF_T > SIZEOF_SCM_UINT_T                       \
367               && SIZEOF_SCM_UINTOBJ_T == SIZEOF_SCM_UINTREF_T))              \
368       && SIZEOF_SCM_WCHAR_T  <= SIZEOF_SCM_ICHAR_T                           \
369       && SIZEOF_SCM_ICHAR_T  <= SIZEOF_SCM_INT_T)
370 #error "size constraints of primitive types are broken"
371 #endif
372 
373 #define SCM_MAX(a, b) (((a) < (b)) ? (b) : (a))
374 #define SCM_MIN(a, b) (((a) > (b)) ? (b) : (a))
375 
376 /*=======================================
377   Variable Declarations
378 =======================================*/
379 
380 /*=======================================
381   Function Declarations
382 =======================================*/
383 
384 #ifdef __cplusplus
385 }
386 #endif
387 
388 #endif /* __SCM_SCMINT_H */
389