Edit

kc3-lang/angle/src/common/bitset_utils.h

Branch :

  • Show log

    Commit

  • Author : Jeff Gilbert
    Date : 2017-10-31 14:44:06
    Hash : 5e5438fe
    Message : Make operator bool() explicit, and remove explicit from move ctors. Gecko bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1371190 BUG=angleproject:2211 Change-Id: I10b866728a844668de6373c3a0968ea4e8256ff7 Reviewed-on: https://chromium-review.googlesource.com/747841 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>

  • src/common/bitset_utils.h
  • //
    // Copyright 2015 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // bitset_utils:
    //   Bitset-related helper classes, such as a fast iterator to scan for set bits.
    //
    
    #ifndef COMMON_BITSETITERATOR_H_
    #define COMMON_BITSETITERATOR_H_
    
    #include <stdint.h>
    
    #include <bitset>
    
    #include "common/angleutils.h"
    #include "common/debug.h"
    #include "common/mathutil.h"
    #include "common/platform.h"
    
    namespace angle
    {
    
    template <size_t N, typename BitsT>
    class BitSetT final
    {
      public:
        class Reference final
        {
          public:
            ~Reference() {}
            Reference &operator=(bool x)
            {
                mParent->set(mBit, x);
                return *this;
            }
            explicit operator bool() const { return mParent->test(mBit); }
    
          private:
            friend class BitSetT;
    
            Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {}
    
            BitSetT *mParent;
            std::size_t mBit;
        };
    
        class Iterator final
        {
          public:
            Iterator(const BitSetT &bits);
            Iterator &operator++();
    
            bool operator==(const Iterator &other) const;
            bool operator!=(const Iterator &other) const;
            std::size_t operator*() const;
    
          private:
            std::size_t getNextBit();
    
            BitSetT mBitsCopy;
            std::size_t mCurrentBit;
        };
    
        BitSetT();
        BitSetT(BitsT value);
        ~BitSetT();
    
        BitSetT(const BitSetT &other);
        BitSetT &operator=(const BitSetT &other);
    
        bool operator==(const BitSetT &other) const;
        bool operator!=(const BitSetT &other) const;
    
        constexpr bool operator[](std::size_t pos) const;
        Reference operator[](std::size_t pos) { return Reference(this, pos); }
    
        bool test(std::size_t pos) const;
    
        bool all() const;
        bool any() const;
        bool none() const;
        std::size_t count() const;
    
        constexpr std::size_t size() const { return N; }
    
        BitSetT &operator&=(const BitSetT &other);
        BitSetT &operator|=(const BitSetT &other);
        BitSetT &operator^=(const BitSetT &other);
        BitSetT operator~() const;
    
        BitSetT operator<<(std::size_t pos) const;
        BitSetT &operator<<=(std::size_t pos);
        BitSetT operator>>(std::size_t pos) const;
        BitSetT &operator>>=(std::size_t pos);
    
        BitSetT &set();
        BitSetT &set(std::size_t pos, bool value = true);
    
        BitSetT &reset();
        BitSetT &reset(std::size_t pos);
    
        BitSetT &flip();
        BitSetT &flip(std::size_t pos);
    
        unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
        BitsT bits() const { return mBits; }
    
        Iterator begin() const { return Iterator(*this); }
        Iterator end() const { return Iterator(BitSetT()); }
    
      private:
        constexpr static BitsT Bit(std::size_t x) { return (static_cast<BitsT>(1) << x); }
        constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
    
        BitsT mBits;
    };
    
    template <size_t N>
    class IterableBitSet : public std::bitset<N>
    {
      public:
        IterableBitSet() {}
        IterableBitSet(const std::bitset<N> &implicitBitSet) : std::bitset<N>(implicitBitSet) {}
    
        class Iterator final
        {
          public:
            Iterator(const std::bitset<N> &bits);
            Iterator &operator++();
    
            bool operator==(const Iterator &other) const;
            bool operator!=(const Iterator &other) const;
            unsigned long operator*() const { return mCurrentBit; }
    
          private:
            unsigned long getNextBit();
    
            static constexpr size_t BitsPerWord = sizeof(uint32_t) * 8;
            std::bitset<N> mBits;
            unsigned long mCurrentBit;
            unsigned long mOffset;
        };
    
        Iterator begin() const { return Iterator(*this); }
        Iterator end() const { return Iterator(std::bitset<N>(0)); }
    };
    
    template <size_t N>
    IterableBitSet<N>::Iterator::Iterator(const std::bitset<N> &bitset)
        : mBits(bitset), mCurrentBit(0), mOffset(0)
    {
        if (mBits.any())
        {
            mCurrentBit = getNextBit();
        }
        else
        {
            mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
        }
    }
    
    template <size_t N>
    typename IterableBitSet<N>::Iterator &IterableBitSet<N>::Iterator::operator++()
    {
        ASSERT(mBits.any());
        mBits.set(mCurrentBit - mOffset, 0);
        mCurrentBit = getNextBit();
        return *this;
    }
    
    template <size_t N>
    bool IterableBitSet<N>::Iterator::operator==(const Iterator &other) const
    {
        return mOffset == other.mOffset && mBits == other.mBits;
    }
    
    template <size_t N>
    bool IterableBitSet<N>::Iterator::operator!=(const Iterator &other) const
    {
        return !(*this == other);
    }
    
    template <size_t N>
    unsigned long IterableBitSet<N>::Iterator::getNextBit()
    {
        // TODO(jmadill): Use 64-bit scan when possible.
        static constexpr std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
    
        while (mOffset < N)
        {
            uint32_t wordBits = static_cast<uint32_t>((mBits & wordMask).to_ulong());
            if (wordBits != 0)
            {
                return gl::ScanForward(wordBits) + mOffset;
            }
    
            mBits >>= BitsPerWord;
            mOffset += BitsPerWord;
        }
        return 0;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT>::BitSetT() : mBits(0)
    {
        static_assert(N > 0, "Bitset type cannot support zero bits.");
        static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT>::BitSetT(BitsT value) : mBits(value & Mask(N))
    {
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT>::~BitSetT()
    {
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
    {
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator=(const BitSetT &other)
    {
        mBits = other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::operator==(const BitSetT &other) const
    {
        return mBits == other.mBits;
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::operator!=(const BitSetT &other) const
    {
        return mBits != other.mBits;
    }
    
    template <size_t N, typename BitsT>
    constexpr bool BitSetT<N, BitsT>::operator[](std::size_t pos) const
    {
        return test(pos);
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::test(std::size_t pos) const
    {
        return (mBits & Bit(pos)) != 0;
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::all() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return mBits == Mask(N);
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::any() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return (mBits != 0);
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::none() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return (mBits == 0);
    }
    
    template <size_t N, typename BitsT>
    std::size_t BitSetT<N, BitsT>::count() const
    {
        return gl::BitCount(mBits);
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator&=(const BitSetT &other)
    {
        mBits &= other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator|=(const BitSetT &other)
    {
        mBits |= other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator^=(const BitSetT &other)
    {
        mBits = (mBits ^ other.mBits) & Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> BitSetT<N, BitsT>::operator~() const
    {
        return BitSetT<N, BitsT>(~mBits & Mask(N));
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> BitSetT<N, BitsT>::operator<<(std::size_t pos) const
    {
        return BitSetT<N, BitsT>((mBits << pos) & Mask(N));
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator<<=(std::size_t pos)
    {
        mBits = (mBits << pos & Mask(N));
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> BitSetT<N, BitsT>::operator>>(std::size_t pos) const
    {
        return BitSetT<N, BitsT>(mBits >> pos);
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator>>=(std::size_t pos)
    {
        mBits = ((mBits >> pos) & Mask(N));
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::set()
    {
        mBits = Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::set(std::size_t pos, bool value)
    {
        if (value)
        {
            mBits |= Bit(pos);
        }
        else
        {
            reset(pos);
        }
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset()
    {
        mBits = 0;
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset(std::size_t pos)
    {
        mBits &= ~Bit(pos);
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip()
    {
        mBits ^= Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip(std::size_t pos)
    {
        mBits ^= Bit(pos);
        return *this;
    }
    
    template <size_t N, typename BitsT>
    BitSetT<N, BitsT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
    {
        if (bits.any())
        {
            mCurrentBit = getNextBit();
        }
    }
    
    template <size_t N, typename BitsT>
    typename BitSetT<N, BitsT>::Iterator &BitSetT<N, BitsT>::Iterator::operator++()
    {
        ASSERT(mBitsCopy.any());
        mBitsCopy.reset(mCurrentBit);
        mCurrentBit = getNextBit();
        return *this;
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::Iterator::operator==(const Iterator &other) const
    {
        return mBitsCopy == other.mBitsCopy;
    }
    
    template <size_t N, typename BitsT>
    bool BitSetT<N, BitsT>::Iterator::operator!=(const Iterator &other) const
    {
        return !(*this == other);
    }
    
    template <size_t N, typename BitsT>
    std::size_t BitSetT<N, BitsT>::Iterator::operator*() const
    {
        return mCurrentBit;
    }
    
    template <size_t N, typename BitsT>
    std::size_t BitSetT<N, BitsT>::Iterator::getNextBit()
    {
        if (mBitsCopy.none())
        {
            return 0;
        }
    
        return gl::ScanForward(mBitsCopy.mBits);
    }
    
    template <size_t N>
    using BitSet32 = BitSetT<N, uint32_t>;
    
    // ScanForward for 64-bits requires a 64-bit implementation.
    #if defined(ANGLE_IS_64_BIT_CPU)
    template <size_t N>
    using BitSet64 = BitSetT<N, uint64_t>;
    #endif  // defined(ANGLE_IS_64_BIT_CPU)
    
    namespace priv
    {
    
    template <size_t N, typename T>
    using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
    
    template <size_t N, typename Enable = void>
    struct GetBitSet
    {
        using Type = IterableBitSet<N>;
    };
    
    // Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit.
    #if defined(ANGLE_IS_64_BIT_CPU)
    template <size_t N>
    struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
    {
        using Type = BitSet64<N>;
    };
    #else
    template <size_t N>
    struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
    {
        using Type = BitSet32<N>;
    };
    #endif  // defined(ANGLE_IS_64_BIT_CPU)
    
    }  // namespace priv
    
    template <size_t N>
    using BitSet = typename priv::GetBitSet<N>::Type;
    
    }  // angle
    
    template <size_t N, typename BitsT>
    inline angle::BitSetT<N, BitsT> operator&(const angle::BitSetT<N, BitsT> &lhs,
                                              const angle::BitSetT<N, BitsT> &rhs)
    {
        return angle::BitSetT<N, BitsT>(lhs.bits() & rhs.bits());
    }
    
    template <size_t N, typename BitsT>
    inline angle::BitSetT<N, BitsT> operator|(const angle::BitSetT<N, BitsT> &lhs,
                                              const angle::BitSetT<N, BitsT> &rhs)
    {
        return angle::BitSetT<N, BitsT>(lhs.bits() | rhs.bits());
    }
    
    template <size_t N, typename BitsT>
    inline angle::BitSetT<N, BitsT> operator^(const angle::BitSetT<N, BitsT> &lhs,
                                              const angle::BitSetT<N, BitsT> &rhs)
    {
        return angle::BitSetT<N, BitsT>(lhs.bits() ^ rhs.bits());
    }
    
    #endif  // COMMON_BITSETITERATOR_H_