/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/uds-releases/jasper/src/uds/numeric.h#2 $ */ #ifndef NUMERIC_H #define NUMERIC_H 1 #include "compiler.h" #include "numericDefs.h" #include "typeDefs.h" #if !defined(__ORDER_LITTLE_ENDIAN__) || !defined(__ORDER_BIG_ENDIAN__) \ || !defined(__BYTE_ORDER__) #error "GCC byte order macros not defined?" #endif /* * Define a type describing an integer value that is only byte-aligned * and may explicitly alias other types. GCC keeps getting better * about type-based alias analysis (both for optimization and for * warnings), so simply casting a pointer to pointer-to-uintXX_t isn't * good enough. * * C is okay with defining the structures directly in a cast, but * C++ is not, and we use this header in some C++ code internally. */ #define UNALIGNED_WRAPPER(TYPE) \ unaligned_wrap_##TYPE #define UNALIGNED_WRAPPER_DEF(TYPE) \ typedef struct __attribute__((packed, may_alias)) { TYPE value; } \ UNALIGNED_WRAPPER(TYPE) UNALIGNED_WRAPPER_DEF(int64_t); UNALIGNED_WRAPPER_DEF(uint64_t); UNALIGNED_WRAPPER_DEF(int32_t); UNALIGNED_WRAPPER_DEF(uint32_t); UNALIGNED_WRAPPER_DEF(uint16_t); #define GET_UNALIGNED(TYPE,ADDR) \ (((const UNALIGNED_WRAPPER(TYPE) *)(ADDR))->value) #define PUT_UNALIGNED(TYPE,ADDR,VALUE) \ (((UNALIGNED_WRAPPER(TYPE) *)(ADDR))->value = (VALUE)) /** * Find the minimum of two ints. * * @param a The first int * @param b The second int * * @return The lesser of a and b **/ __attribute__((warn_unused_result)) static INLINE int minInt(int a, int b) { return ((a < b) ? a : b); } /** * Find the maximum of two ints. * * @param a The first int * @param b The second int * * @return The greater of a and b **/ __attribute__((warn_unused_result)) static INLINE int maxInt(int a, int b) { return ((a > b) ? a : b); } /** * Find the maximum of two unsigned ints. * * @param a The first value * @param b The second value * * @return The greater of a and b **/ __attribute__((warn_unused_result)) static INLINE unsigned int maxUInt(unsigned int a, unsigned int b) { return ((a > b) ? a : b); } /** * Find the maximum of two signed longs. * * @param a The first int * @param b The second int * * @return The greater of a and b **/ __attribute__((warn_unused_result)) static INLINE long maxLong(long a, long b) { return ((a > b) ? a : b); } /** * Find the maximum of two unsigned longs. * * @param a The first int * @param b The second int * * @return The greater of a and b **/ __attribute__((warn_unused_result)) static INLINE unsigned long maxULong(unsigned long a, unsigned long b) { return ((a > b) ? a : b); } /** * Find the minimum of two size_ts. * * @param a The first size_t * @param b The second size_t * * @return The lesser of a and b **/ __attribute__((warn_unused_result)) static INLINE size_t minSizeT(size_t a, size_t b) { return ((a < b) ? a : b); } /** * Find the maximum of two size_ts. * * @param a The first size_t * @param b The second size_t * * @return The greater of a and b **/ __attribute__((warn_unused_result)) static INLINE size_t maxSizeT(size_t a, size_t b) { return ((a > b) ? a : b); } /** * Find the minimum of two uint64_ts. * * @param a The first uint64_t * @param b The second uint64_t * * @return The lesser of a and b **/ __attribute__((warn_unused_result)) static INLINE uint64_t minUInt64(uint64_t a, uint64_t b) { return ((a < b) ? a : b); } /** * Multiply two uint64_t and check for overflow. Does division. **/ bool multiplyWouldOverflow(uint64_t a, uint64_t b); /** * Extract a 64 bit unsigned number from a buffer stored in * big-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint64_t getUInt64BE(const byte* data) { uint64_t num = GET_UNALIGNED(uint64_t, data); #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif return num; } /** * Extract a 64 bit unsigned big-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt64BE(const byte *buffer, size_t *offset, uint64_t *decoded) { *decoded = getUInt64BE(buffer + *offset); *offset += sizeof(uint64_t); } /** * Store a 64 bit unsigned number in a buffer in * big-endian representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt64BE(byte* data, uint64_t num) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif PUT_UNALIGNED(uint64_t, data, num); } /** * Encode a 64 bit unsigned number into a buffer at a given offset * using a big-endian representation. The offset will be advanced to * first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt64BE(byte *data, size_t *offset, uint64_t toEncode) { storeUInt64BE(data + *offset, toEncode); *offset += sizeof(uint64_t); } /** * Extract a 32 bit unsigned number from a buffer stored in big-endian * representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint32_t getUInt32BE(const byte* data) { uint32_t num = GET_UNALIGNED(uint32_t, data); #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif return num; } /** * Extract a 32 bit unsigned big-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt32BE(const byte *buffer, size_t *offset, uint32_t *decoded) { *decoded = getUInt32BE(buffer + *offset); *offset += sizeof(uint32_t); } /** * Store a 32 bit number in a buffer in * big-endian representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt32BE(byte* data, uint32_t num) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif PUT_UNALIGNED(uint32_t, data, num); } /** * Encode a 32 bit number into a buffer at a given offset using a * big-endian representation. The offset will be advanced to first byte * after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt32BE(byte *data, size_t *offset, uint32_t toEncode) { storeUInt32BE(data + *offset, toEncode); *offset += sizeof(uint32_t); } /** * Extract a 16 bit number from a buffer stored in * big-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint16_t getUInt16BE(const byte* data) { uint16_t num = GET_UNALIGNED(uint16_t, data); #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = bswap_16(num); #endif return num; } /** * Extract a 16 bit, big-endian number from a buffer at a specified offset. * The offset will be advanced to the first byte after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to * extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt16BE(const byte *buffer, size_t *offset, uint16_t *decoded) { *decoded = getUInt16BE(buffer + *offset); *offset += sizeof(uint16_t); } /** * Store a 16 bit number in a buffer in * big-endian representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt16BE(byte* data, uint16_t num) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ num = bswap_16(num); #endif PUT_UNALIGNED(uint16_t, data, num); } /** * Encode a 16 bit number into a buffer at a given offset using a * big-endian representation. The offset will be advanced to first byte * after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt16BE(byte *data, size_t *offset, uint16_t toEncode) { storeUInt16BE(data + *offset, toEncode); *offset += sizeof(uint16_t); } /** * Extract a 64 bit signed number from a buffer stored in * little-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE int64_t getInt64LE(const byte* data) { int64_t num = GET_UNALIGNED(int64_t, data); #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif return num; } /** * Extract a 64 bit signed little-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeInt64LE(const byte *buffer, size_t *offset, int64_t *decoded) { *decoded = getInt64LE(buffer + *offset); *offset += sizeof(int64_t); } /** * Store a signed 64 bit number in a buffer in little-endian * representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeInt64LE(byte* data, int64_t num) { #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif PUT_UNALIGNED(int64_t, data, num); } /** * Encode a 64 bit signed number into a buffer at a given offset using * a little-endian representation. The offset will be advanced to * first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeInt64LE(byte *data, size_t *offset, int64_t toEncode) { storeInt64LE(data + *offset, toEncode); *offset += sizeof(int64_t); } /** * Extract a 64 bit number from a buffer stored in * little-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint64_t getUInt64LE(const byte* data) { uint64_t num = GET_UNALIGNED(uint64_t, data); #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif return num; } /** * Extract a 64 bit unsigned little-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt64LE(const byte *buffer, size_t *offset, uint64_t *decoded) { *decoded = getUInt64LE(buffer + *offset); *offset += sizeof(uint64_t); } /** * Store a 64 bit unsigned number in a buffer in little-endian * representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt64LE(byte* data, uint64_t num) { #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap64(num); #endif PUT_UNALIGNED(uint64_t, data, num); } /** * Encode a 64 bit unsigned number into a buffer at a given offset * using a little-endian representation. The offset will be advanced * to first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt64LE(byte *data, size_t *offset, uint64_t toEncode) { storeUInt64LE(data + *offset, toEncode); *offset += sizeof(uint64_t); } /** * Extract a 32 bit signed number from a buffer stored in * little-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE int32_t getInt32LE(const byte* data) { int32_t num = GET_UNALIGNED(int32_t, data); #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif return num; } /** * Extract a 32 bit signed little-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeInt32LE(const byte *buffer, size_t *offset, int32_t *decoded) { *decoded = getInt32LE(buffer + *offset); *offset += sizeof(int32_t); } /** * Store a signed 32 bit number in a buffer in little-endian * representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeInt32LE(byte* data, int32_t num) { #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif PUT_UNALIGNED(int32_t, data, num); } /** * Encode a 32 bit signed number into a buffer at a given offset using * a little-endian representation. The offset will be advanced to * first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeInt32LE(byte *data, size_t *offset, int32_t toEncode) { storeInt32LE(data + *offset, toEncode); *offset += sizeof(int32_t); } /** * Extract a 32 bit unsigned number from a buffer stored in * little-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint32_t getUInt32LE(const byte* data) { uint32_t num = GET_UNALIGNED(uint32_t, data); #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif return num; } /** * Extract a 32 bit unsigned little-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt32LE(const byte *buffer, size_t *offset, uint32_t *decoded) { *decoded = getUInt32LE(buffer + *offset); *offset += sizeof(uint32_t); } /** * Store a 32 bit unsigned number in a buffer in little-endian * representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt32LE(byte* data, uint32_t num) { #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = __builtin_bswap32(num); #endif PUT_UNALIGNED(uint32_t, data, num); } /** * Encode a 32 bit unsigned number into a buffer at a given offset * using a little-endian representation. The offset will be advanced * to first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt32LE(byte *data, size_t *offset, uint32_t toEncode) { storeUInt32LE(data + *offset, toEncode); *offset += sizeof(uint32_t); } /** * Extract a 16 bit number from a buffer stored in * little-endian representation. * * @param data The buffer from which to extract the number * * @return The extracted quantity **/ __attribute__((warn_unused_result)) static INLINE uint16_t getUInt16LE(const byte* data) { uint16_t num = GET_UNALIGNED(uint16_t, data); #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = bswap_16(num); #endif return num; } /** * Extract a 16 bit unsigned little-endian number from a buffer at a * specified offset. The offset will be advanced to the first byte * after the number. * * @param buffer The buffer from which to extract the number * @param offset A pointer to the offset into the buffer at which to * extract * @param decoded A pointer to hold the extracted number **/ static INLINE void decodeUInt16LE(const byte *buffer, size_t *offset, uint16_t *decoded) { *decoded = getUInt16LE(buffer + *offset); *offset += sizeof(uint16_t); } /** * Store a 16 bit number in a buffer in little-endian representation. * * @param data The buffer in which to store the number * @param num The number to store **/ static INLINE void storeUInt16LE(byte* data, uint16_t num) { #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ num = bswap_16(num); #endif PUT_UNALIGNED(uint16_t, data, num); } /** * Encode a 16 bit unsigned number into a buffer at a given offset * using a little-endian representation. The offset will be advanced * to first byte after the encoded number. * * @param data The buffer to encode into * @param offset A pointer to the offset at which to start encoding * @param toEncode The number to encode **/ static INLINE void encodeUInt16LE(byte *data, size_t *offset, uint16_t toEncode) { storeUInt16LE(data + *offset, toEncode); *offset += sizeof(uint16_t); } /** * Special function wrapper required for compile-time assertions. This * function will fail to compile if any of the uint*_t types are not of the * size we expect. This function should never be called. **/ void numericCompileTimeAssertions(void); #endif /* NUMERIC_H */