/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 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, see . */ #ifndef Bits_H #define Bits_H #include "util/Assert.h" #include "util/Gcc.h" #include "util/Linker.h" Linker_require("util/Bits.c"); #include #include /** * Find first set bit in a 64 bit integer. */ static inline int Bits_ffs64(uint64_t number) { if (!number) { return 0; } int out = 1; while (!(number & 1)) { number >>= 1; out++; } return out; } static inline int Bits_popCountx64(uint64_t number) { return __builtin_popcountll(number); } static inline int Bits_popCountx32(uint32_t number) { int out = 0; for (int i = 0; i < 32; i++) { out += ((number >> i) & 1); } return out; } static inline int Bits_log2x64(uint64_t number) { if (!number) { return 0; } return 63 - __builtin_clzll(number); } int Bits_log2x64_stupid(uint64_t number); /** Largest possible number whose log2 is bitCount. */ static inline uint64_t Bits_maxBits64(uint32_t bitCount) { Assert_ifParanoid(bitCount < 64); return (((uint64_t)1) << bitCount) - 1; } static inline int Bits_log2x32(uint32_t number) { int out = 0; while (number >>= 1) { out++; } return out; } /** * Bitwise reversal of the a number. * This is endian safe. */ static inline uint64_t Bits_bitReverse64(uint64_t toReverse) { #define Bits_rotateAndMask(mask, rotateBits) \ toReverse = ((toReverse >> rotateBits) & mask) | ((toReverse & mask) << rotateBits) Bits_rotateAndMask(0x5555555555555555ull, 1); Bits_rotateAndMask(0x3333333333333333ull, 2); Bits_rotateAndMask(0x0F0F0F0F0F0F0F0Full, 4); return __builtin_bswap64(toReverse); #undef Bits_rotateAndMask } /** * @param buffer the space of check if it's zero. * @length the nuber of bytes to check for zero'd-ness. * @return true if all bytes checked are zero. */ static inline int Bits_isZero(void* buffer, size_t length) { uint8_t* buff = (uint8_t*) buffer; for (size_t i = 0; i < length; i++) { if (buff[i]) { return 0; } } return 1; } #define Bits_memmove(a,b,c) __builtin_memmove(a,b,c) #define Bits_memset(a,b,c) __builtin_memset(a,b,c) #define Bits_memcmp(a,b,c) __builtin_memcmp(a,b,c) /** * Bits_memcpy() * Alias to POSIX memcpy(), allows for extra debugging checks. * * @param out buffer to write to. * @param in buffer to read from. * @param length number of bytes to copy. * @param file name of the file calling this, for logging. * @param line the line number of the calling file, for logging. * @param constant true if the length should be checked for being constant. * @return out */ #define Bits_memcpy(a,b,c) Bits__memcpy(a,b,c,Gcc_SHORT_FILE,Gcc_LINE) static inline void* Bits__memcpy(void* out, const void* in, size_t length, char* file, int line) { const char* inc = in; const char* outc = out; // Check that pointers don't alias. if (outc >= inc && outc < inc + length) { Assert_failure(file, line, "memcpy() pointers alias each other"); } return __builtin_memcpy(out, in, length); } void* Bits_memmem(const void* haystack, size_t haystackLen, const void* needle, size_t needleLen); static inline uint16_t Bits_get16(uint8_t* bytes) { uint16_t x = 0; Bits_memcpy(&x, bytes, 2); return x; } static inline void Bits_put16(uint8_t* bytes, uint16_t num) { Bits_memcpy(bytes, &num, 2); } #endif