#ifndef LIBNONSTD_INTEGRAL_H #define LIBNONSTD_INTEGRAL_H #include #include #include /* C object representation type * * Use: access and manipulate the raw bytes of a C object. * * 6.2.6.1 * * Values stored in unsigned bit-fields *and objects of type unsigned char* * shall be represented using a pure binary notation. * * Values stored in non-bit-field objects of any other object type consist of n * x CHAR_BIT bits, where n is the size of an object of that type, in bytes. * The value may be copied into an object of type unsigned char [n] (e.g., by * memcpy); the resulting set of bytes is called the object representation of * the value. * * 6.2.6.2 * * For unsigned integer types *other than unsigned char,* the bits of the * object representation shall be divided into two groups: value bits and * padding bits (there need not be any of the latter). */ typedef unsigned char byte; /* Integer bit patterns * * Usage: bitwise operations and modular arithmetic, with exact bit widths. * * 6.2.5 * * A computation involving unsigned operands can never overflow, because a * result that cannot be represented by the resulting unsigned integer type is * reduced modulo the number that is one greater than the largest value that * can be represented by the resulting type. */ typedef uint8_t b8; typedef uint16_t b16; typedef uint32_t b32; typedef uint64_t b64; /* General-purpose (signed) integers * * Usage: normal arithmetical operations and measurement, without modular * arithmetic expectations. * * Care is required with these types to avoid overflow, which is undefined * behavior. * * Each type "iN" is guaranteed to hold at least N bits, but may be wider if * that would be faster for the processor. The "_trim" variety attempts to save * space for e.g. big arrays. */ typedef int_fast8_t i8; typedef int_least8_t i8_trim; typedef int_fast16_t i16; // int typedef int_least16_t i16_trim; // short typedef int_fast32_t i32; // long typedef int_least32_t i32_trim; typedef int_fast64_t i64; // long long typedef int_least64_t i64_trim; /* The size of data objects. * * This is a numerical quantity, not a bit pattern. Thus it fits into the * signed integer category. This notion conflicts with the definition of * size_t. We provide a signed counterpart, and wrappers for sizeof() and * offsetof() that do bounds checking and conver the result. * * My conjecture is that size_t was chosen to be unsigned to wring the most out * of each available bit on e.g. segmented 16-bit memory architectures. A 64K * object size limit was bad enough, and a 32K limit would be intolerable. */ #ifdef HAVE_SSIZE_T // get ssize_t from POSIX #include #else // make our best approximation typedef ptrdiff_t ssize_t; #define SSIZE_MAX PTRDIFF_MAX #endif #define ssizeof(x) \ (sizeof(x) <= (size_t)SSIZE_MAX ? (ssize_t)sizeof(x) : -1) #define soffsetof(t, m) \ (offsetof((t), (m)) <= (size_t)SSIZE_MAX ? offsetof((t), (m)) : -1) /* Character types -- no extras provided. They are either out of scope for a * base library, or are redundant with the types above. Here are the three uses * of char: * * 1. Codepoints in a character encoding. The tasks of human language * processing are too broad for a base language library, and the rules * change as languages and locales do. Use a proper library for this, such * as ICU, and its provided data types. * * - Storage and transmission of UTF-8 can use b8. * * - Pointers to native C string literals should be char*, as the signedness * of char is implementation-defined. * * 2. Smallest units of addressible storage. We covered this case already with * the byte type. * * 3. Small integers. Already covered with b8, i8, and i8_trim. */ // Character typedefs intentionally left blank #endif