root/lib/idx.h

/* [previous][next][first][last][top][bottom][index][help]  */

INCLUDED FROM


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

/* [previous][next][first][last][top][bottom][index][help]  */