X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Fexperimental%2FBits.h;h=0601513fd3ee596e4f2d23ad677d2b509179416a;hb=7ffe7766f032914384aa6e0b9598bab7d9a90602;hp=df23d8594103fc723e33afc21f3ae5e338418d9c;hpb=5c77fedbef46995a71ffa268c9fcaf49efddd01b;p=folly.git diff --git a/folly/experimental/Bits.h b/folly/experimental/Bits.h index df23d859..0601513f 100644 --- a/folly/experimental/Bits.h +++ b/folly/experimental/Bits.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,15 @@ #include #include -#include "folly/Bits.h" -#include "folly/Range.h" +#include +#include +#include namespace folly { +template +struct UnalignedNoASan : public Unaligned { }; + // As a general rule, bit operations work on unsigned values only; // right-shift is arithmetic for signed values, and that can lead to // unpleasant bugs. @@ -37,7 +41,8 @@ namespace detail { * (T, where T is an unsigned integral type) or unaligned values * (Unaligned, where T is an unsigned integral type) */ -template struct BitsTraits; +template +struct BitsTraits; // Partial specialization for Unaligned, where T is unsigned integral // loadRMW is the same as load, but it indicates that it loads for a @@ -45,13 +50,39 @@ template struct BitsTraits; // silence the GCC warning in that case. template struct BitsTraits, typename std::enable_if< - (std::is_integral::value && std::is_unsigned::value)>::type> { + (std::is_integral::value)>::type> { typedef T UnderlyingType; static T load(const Unaligned& x) { return x.value; } static void store(Unaligned& x, T v) { x.value = v; } static T loadRMW(const Unaligned& x) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" +// make sure we compile without warning on gcc 4.6 with -Wpragmas +#if __GNUC_PREREQ(4, 7) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + return x.value; +#pragma GCC diagnostic pop + } +}; + +// Special version that allows to disable address sanitizer on demand. +template +struct BitsTraits, typename std::enable_if< + (std::is_integral::value)>::type> { + typedef T UnderlyingType; + static T FOLLY_DISABLE_ADDRESS_SANITIZER + load(const UnalignedNoASan& x) { return x.value; } + static void FOLLY_DISABLE_ADDRESS_SANITIZER + store(UnalignedNoASan& x, T v) { x.value = v; } + static T FOLLY_DISABLE_ADDRESS_SANITIZER + loadRMW(const UnalignedNoASan& x) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +// make sure we compile without warning on gcc 4.6 with -Wpragmas +#if __GNUC_PREREQ(4, 7) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif return x.value; #pragma GCC diagnostic pop } @@ -60,17 +91,21 @@ struct BitsTraits, typename std::enable_if< // Partial specialization for T, where T is unsigned integral template struct BitsTraits::value && std::is_unsigned::value)>::type> { + (std::is_integral::value)>::type> { typedef T UnderlyingType; static T load(const T& x) { return x; } static void store(T& x, T v) { x = v; } static T loadRMW(const T& x) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" +#if __GNUC_PREREQ(4, 7) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif return x; #pragma GCC diagnostic pop } }; + } // namespace detail /** @@ -88,8 +123,8 @@ struct Bits { /** * Number of bits in a block. */ - static constexpr size_t bitsPerBlock = - std::numeric_limits::digits; + static constexpr size_t bitsPerBlock = std::numeric_limits< + typename std::make_unsigned::type>::digits; /** * Byte index of the given bit. @@ -132,6 +167,7 @@ struct Bits { * from the least significant count bits of value; little endian. * (value & 1 becomes the bit at bitStart, etc) * Precondition: count <= sizeof(T) * 8 + * Precondition: value can fit in 'count' bits */ static void set(T* p, size_t bitStart, size_t count, UnderlyingType value); @@ -164,6 +200,15 @@ struct Bits { } }; +// gcc 4.8 needs more -Wmaybe-uninitialized tickling, as it propagates the +// taint upstream from loadRMW + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#if __GNUC_PREREQ(4, 7) +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + template inline void Bits::set(T* p, size_t bit) { T& block = p[blockIndex(bit)]; @@ -176,58 +221,77 @@ inline void Bits::clear(T* p, size_t bit) { Traits::store(block, Traits::loadRMW(block) & ~(one << bitOffset(bit))); } -template -inline bool Bits::test(const T* p, size_t bit) { - return Traits::load(p[blockIndex(bit)]) & (one << bitOffset(bit)); -} - template inline void Bits::set(T* p, size_t bitStart, size_t count, UnderlyingType value) { assert(count <= sizeof(UnderlyingType) * 8); + size_t cut = bitsPerBlock - count; + assert(value == (value << cut >> cut)); size_t idx = blockIndex(bitStart); size_t offset = bitOffset(bitStart); + if (std::is_signed::value) { + value &= ones(count); + } if (offset + count <= bitsPerBlock) { innerSet(p + idx, offset, count, value); } else { size_t countInThisBlock = bitsPerBlock - offset; size_t countInNextBlock = count - countInThisBlock; - innerSet(p + idx, offset, countInThisBlock, - value & ((one << countInThisBlock) - 1)); - innerSet(p + idx + 1, 0, countInNextBlock, value >> countInThisBlock); + + UnderlyingType thisBlock = value & ((one << countInThisBlock) - 1); + UnderlyingType nextBlock = value >> countInThisBlock; + if (std::is_signed::value) { + nextBlock &= ones(countInNextBlock); + } + innerSet(p + idx, offset, countInThisBlock, thisBlock); + innerSet(p + idx + 1, 0, countInNextBlock, nextBlock); } } +template +inline void Bits::innerSet(T* p, size_t offset, size_t count, + UnderlyingType value) { + // Mask out bits and set new value + UnderlyingType v = Traits::loadRMW(*p); + v &= ~(ones(count) << offset); + v |= (value << offset); + Traits::store(*p, v); +} + +#pragma GCC diagnostic pop + +template +inline bool Bits::test(const T* p, size_t bit) { + return Traits::load(p[blockIndex(bit)]) & (one << bitOffset(bit)); +} + template inline auto Bits::get(const T* p, size_t bitStart, size_t count) -> UnderlyingType { assert(count <= sizeof(UnderlyingType) * 8); size_t idx = blockIndex(bitStart); size_t offset = bitOffset(bitStart); + UnderlyingType ret; if (offset + count <= bitsPerBlock) { - return innerGet(p + idx, offset, count); + ret = innerGet(p + idx, offset, count); } else { size_t countInThisBlock = bitsPerBlock - offset; size_t countInNextBlock = count - countInThisBlock; UnderlyingType thisBlockValue = innerGet(p + idx, offset, countInThisBlock); UnderlyingType nextBlockValue = innerGet(p + idx + 1, 0, countInNextBlock); - return (nextBlockValue << countInThisBlock) | thisBlockValue; + ret = (nextBlockValue << countInThisBlock) | thisBlockValue; } -} - -template -inline void Bits::innerSet(T* p, size_t offset, size_t count, - UnderlyingType value) { - // Mask out bits and set new value - UnderlyingType v = Traits::loadRMW(*p); - v &= ~(ones(count) << offset); - v |= (value << offset); - Traits::store(*p, v); + if (std::is_signed::value) { + size_t emptyBits = bitsPerBlock - count; + ret <<= emptyBits; + ret >>= emptyBits; + } + return ret; } template inline auto Bits::innerGet(const T* p, size_t offset, size_t count) - -> UnderlyingType { + -> UnderlyingType { return (Traits::load(*p) >> offset) & ones(count); } @@ -243,4 +307,3 @@ inline size_t Bits::count(const T* begin, const T* end) { } // namespace folly #endif /* FOLLY_EXPERIMENTAL_BITS_H_ */ -