xref: /Universal-ctags/gnulib/idx.h (revision a939078a69878851c19820eb92e6cb95ba429546)
1*a939078aSHiroo HAYASHI /* A type for indices and sizes.
2*a939078aSHiroo HAYASHI    Copyright (C) 2020-2021 Free Software Foundation, Inc.
3*a939078aSHiroo HAYASHI    This file is part of the GNU C Library.
4*a939078aSHiroo HAYASHI 
5*a939078aSHiroo HAYASHI    The GNU C Library is free software; you can redistribute it and/or
6*a939078aSHiroo HAYASHI    modify it under the terms of the GNU Lesser General Public
7*a939078aSHiroo HAYASHI    License as published by the Free Software Foundation; either
8*a939078aSHiroo HAYASHI    version 2.1 of the License, or (at your option) any later version.
9*a939078aSHiroo HAYASHI 
10*a939078aSHiroo HAYASHI    The GNU C Library is distributed in the hope that it will be useful,
11*a939078aSHiroo HAYASHI    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*a939078aSHiroo HAYASHI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13*a939078aSHiroo HAYASHI    Lesser General Public License for more details.
14*a939078aSHiroo HAYASHI 
15*a939078aSHiroo HAYASHI    You should have received a copy of the GNU Lesser General Public
16*a939078aSHiroo HAYASHI    License along with the GNU C Library; if not, see
17*a939078aSHiroo HAYASHI    <https://www.gnu.org/licenses/>.  */
18*a939078aSHiroo HAYASHI 
19*a939078aSHiroo HAYASHI #ifndef _IDX_H
20*a939078aSHiroo HAYASHI #define _IDX_H
21*a939078aSHiroo HAYASHI 
22*a939078aSHiroo HAYASHI /* Get ptrdiff_t.  */
23*a939078aSHiroo HAYASHI #include <stddef.h>
24*a939078aSHiroo HAYASHI 
25*a939078aSHiroo HAYASHI /* Get PTRDIFF_MAX.  */
26*a939078aSHiroo HAYASHI #include <stdint.h>
27*a939078aSHiroo HAYASHI 
28*a939078aSHiroo HAYASHI /* The type 'idx_t' holds an (array) index or an (object) size.
29*a939078aSHiroo HAYASHI    Its implementation promotes to a signed integer type,
30*a939078aSHiroo HAYASHI    which can hold the values
31*a939078aSHiroo HAYASHI      0..2^63-1 (on 64-bit platforms) or
32*a939078aSHiroo HAYASHI      0..2^31-1 (on 32-bit platforms).
33*a939078aSHiroo HAYASHI 
34*a939078aSHiroo HAYASHI    Why a signed integer type?
35*a939078aSHiroo HAYASHI 
36*a939078aSHiroo HAYASHI      * Security: Signed types can be checked for overflow via
37*a939078aSHiroo HAYASHI        '-fsanitize=undefined', but unsigned types cannot.
38*a939078aSHiroo HAYASHI 
39*a939078aSHiroo HAYASHI      * Comparisons without surprises: ISO C99 § 6.3.1.8 specifies a few
40*a939078aSHiroo HAYASHI        surprising results for comparisons, such as
41*a939078aSHiroo HAYASHI 
42*a939078aSHiroo HAYASHI            (int) -3 < (unsigned long) 7  =>  false
43*a939078aSHiroo HAYASHI            (int) -3 < (unsigned int) 7   =>  false
44*a939078aSHiroo HAYASHI        and on 32-bit machines:
45*a939078aSHiroo HAYASHI            (long) -3 < (unsigned int) 7  =>  false
46*a939078aSHiroo HAYASHI 
47*a939078aSHiroo HAYASHI        This is surprising because the natural comparison order is by
48*a939078aSHiroo HAYASHI        value in the realm of infinite-precision signed integers (ℤ).
49*a939078aSHiroo HAYASHI 
50*a939078aSHiroo HAYASHI        The best way to get rid of such surprises is to use signed types
51*a939078aSHiroo HAYASHI        for numerical integer values, and use unsigned types only for
52*a939078aSHiroo HAYASHI        bit masks and enums.
53*a939078aSHiroo HAYASHI 
54*a939078aSHiroo HAYASHI    Why not use 'size_t' directly?
55*a939078aSHiroo HAYASHI 
56*a939078aSHiroo HAYASHI      * Because 'size_t' is an unsigned type, and a signed type is better.
57*a939078aSHiroo HAYASHI        See above.
58*a939078aSHiroo HAYASHI 
59*a939078aSHiroo HAYASHI    Why not use 'ptrdiff_t' directly?
60*a939078aSHiroo HAYASHI 
61*a939078aSHiroo HAYASHI      * Maintainability: When reading and modifying code, it helps to know that
62*a939078aSHiroo HAYASHI        a certain variable cannot have negative values.  For example, when you
63*a939078aSHiroo HAYASHI        have a loop
64*a939078aSHiroo HAYASHI 
65*a939078aSHiroo HAYASHI          int n = ...;
66*a939078aSHiroo HAYASHI          for (int i = 0; i < n; i++) ...
67*a939078aSHiroo HAYASHI 
68*a939078aSHiroo HAYASHI        or
69*a939078aSHiroo HAYASHI 
70*a939078aSHiroo HAYASHI          ptrdiff_t n = ...;
71*a939078aSHiroo HAYASHI          for (ptrdiff_t i = 0; i < n; i++) ...
72*a939078aSHiroo HAYASHI 
73*a939078aSHiroo HAYASHI        you have to ask yourself "what if n < 0?".  Whereas in
74*a939078aSHiroo HAYASHI 
75*a939078aSHiroo HAYASHI          idx_t n = ...;
76*a939078aSHiroo HAYASHI          for (idx_t i = 0; i < n; i++) ...
77*a939078aSHiroo HAYASHI 
78*a939078aSHiroo HAYASHI        you know that this case cannot happen.
79*a939078aSHiroo HAYASHI 
80*a939078aSHiroo HAYASHI        Similarly, when a programmer writes
81*a939078aSHiroo HAYASHI 
82*a939078aSHiroo HAYASHI          idx_t = ptr2 - ptr1;
83*a939078aSHiroo HAYASHI 
84*a939078aSHiroo HAYASHI        there is an implied assertion that ptr1 and ptr2 point into the same
85*a939078aSHiroo HAYASHI        object and that ptr1 <= ptr2.
86*a939078aSHiroo HAYASHI 
87*a939078aSHiroo HAYASHI      * Being future-proof: In the future, range types (integers which are
88*a939078aSHiroo HAYASHI        constrained to a certain range of values) may be added to C compilers
89*a939078aSHiroo HAYASHI        or to the C standard.  Several programming languages (Ada, Haskell,
90*a939078aSHiroo HAYASHI        Common Lisp, Pascal) already have range types.  Such range types may
91*a939078aSHiroo HAYASHI        help producing good code and good warnings.  The type 'idx_t' could
92*a939078aSHiroo HAYASHI        then be typedef'ed to a range type that is signed after promotion.  */
93*a939078aSHiroo HAYASHI 
94*a939078aSHiroo HAYASHI /* In the future, idx_t could be typedef'ed to a signed range type.
95*a939078aSHiroo HAYASHI    The clang "extended integer types", supported in Clang 11 or newer
96*a939078aSHiroo HAYASHI    <https://clang.llvm.org/docs/LanguageExtensions.html#extended-integer-types>,
97*a939078aSHiroo HAYASHI    are a special case of range types.  However, these types don't support binary
98*a939078aSHiroo HAYASHI    operators with plain integer types (e.g. expressions such as x > 1).
99*a939078aSHiroo HAYASHI    Therefore, they don't behave like signed types (and not like unsigned types
100*a939078aSHiroo HAYASHI    either).  So, we cannot use them here.  */
101*a939078aSHiroo HAYASHI 
102*a939078aSHiroo HAYASHI /* Use the signed type 'ptrdiff_t'.  */
103*a939078aSHiroo HAYASHI /* Note: ISO C does not mandate that 'size_t' and 'ptrdiff_t' have the same
104*a939078aSHiroo HAYASHI    size, but it is so on all platforms we have seen since 1990.  */
105*a939078aSHiroo HAYASHI typedef ptrdiff_t idx_t;
106*a939078aSHiroo HAYASHI 
107*a939078aSHiroo HAYASHI /* IDX_MAX is the maximum value of an idx_t.  */
108*a939078aSHiroo HAYASHI #define IDX_MAX PTRDIFF_MAX
109*a939078aSHiroo HAYASHI 
110*a939078aSHiroo HAYASHI /* So far no need has been found for an IDX_WIDTH macro.
111*a939078aSHiroo HAYASHI    Perhaps there should be another macro IDX_VALUE_BITS that does not
112*a939078aSHiroo HAYASHI    count the sign bit and is therefore one less than PTRDIFF_WIDTH.  */
113*a939078aSHiroo HAYASHI 
114*a939078aSHiroo HAYASHI #endif /* _IDX_H */
115