Asa's CP Library

a01sa01to's competitive programming library. Requires C++20 or higher with GCC. This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub a01sa01to/cp-library

:heavy_check_mark: Dynamic Bitset
(library/data-structure/dynamic-bitset.hpp)

Bitset の動的版。

使い方

基本的には (static な) bitset と同じように扱える ([] アクセスと to_ull() 以外)

演算子系

メンバ関数

Verified with

Code

#pragma once

#include <algorithm>
#include <bit>
#include <concepts>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
using namespace std;

namespace asalib::ds {
  class DynamicBitset {
    private:
    using ull = uint64_t;
    size_t siz = 0;
    // TODO: valarray が constexpr に対応したら変える
    vector<ull> bits;

    public:
    constexpr explicit DynamicBitset() = default;
    constexpr DynamicBitset(const DynamicBitset&) = default;
    constexpr ~DynamicBitset() = default;
    constexpr DynamicBitset& operator=(const DynamicBitset&) = default;
    constexpr explicit DynamicBitset(const size_t size) {
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
    }
    template<integral T>
    constexpr explicit DynamicBitset(const size_t size, const T value) {
      // TODO: ほかの型も考慮する
      static_assert(sizeof(T) <= sizeof(ull), "DynamicBitset: value type too large");
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
      bits[0] = static_cast<ull>(value);
    }

    constexpr DynamicBitset& operator&=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] &= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator|=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] |= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator^=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] ^= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator<<=(const size_t shift) {
      const size_t full = shift >> 6;
      const size_t rem = shift & 63;
      vector<ull> new_bits(bits.size(), 0);
      for (size_t i = 0; i < bits.size(); ++i) {
        if (i + full < new_bits.size()) {
          new_bits[i + full] |= bits[i] << rem;
          if (i + full + 1 < new_bits.size()) new_bits[i + full + 1] |= bits[i] >> (64 - rem);
        }
      }
      bits = std::move(new_bits);
      return *this;
    }
    constexpr DynamicBitset& operator>>=(const size_t shift) {
      const size_t full = shift >> 6;
      const size_t rem = shift & 63;
      vector<ull> new_bits(bits.size(), 0);
      for (size_t i = full; i < bits.size(); ++i) {
        new_bits[i - full] |= bits[i] >> rem;
        if (i - full - 1 < new_bits.size()) new_bits[i - full - 1] |= bits[i] << (64 - rem);
      }
      bits = std::move(new_bits);
      return *this;
    }
    constexpr DynamicBitset& set() {
      for (size_t i = 0; i < bits.size(); ++i) bits[i] = ~0ULL;
      return *this;
    }
    constexpr DynamicBitset& set(const size_t pos, const bool val = true) {
      if (pos >= siz) throw out_of_range("DynamicBitset::set: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      if (val)
        bits[idx] |= (1ULL << bit);
      else
        bits[idx] &= ~(1ULL << bit);
      return *this;
    }
    constexpr DynamicBitset& reset() {
      ranges::fill(bits, 0);
      return *this;
    }
    constexpr DynamicBitset& reset(size_t pos) { return set(pos, false); }
    constexpr DynamicBitset operator~() const {
      DynamicBitset res = *this;
      res.flip();
      return res;
    }
    constexpr DynamicBitset& flip() {
      for (size_t i = 0; i < bits.size(); ++i) bits[i] = ~bits[i];
      return *this;
    }
    constexpr DynamicBitset& flip(const size_t pos) {
      if (pos >= siz) throw out_of_range("DynamicBitset::flip: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      bits[idx] ^= (1ULL << bit);
      return *this;
    }

    constexpr size_t count() const {
      size_t cnt = 0;
      for (const ull& b : bits) cnt += popcount(b);
      return cnt;
    }
    constexpr size_t size() const { return siz; }
    constexpr bool test(const size_t pos) const {
      if (pos >= siz) throw out_of_range("DynamicBitset::test: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      return (bits[idx] >> bit) & 1;
    }
    constexpr bool all() const {
      for (const ull& b : bits)
        if (b != ~0ULL) return false;
      return true;
    }
    constexpr bool any() const {
      for (const ull& b : bits)
        if (b != 0) return true;
      return false;
    }
    constexpr bool none() const {
      for (const ull& b : bits)
        if (b != 0) return false;
      return true;
    }
    constexpr ull to_ull() const {
      if (bits.size() > 1) throw logic_error("DynamicBitset::to_ull: overflow");
      if (bits.empty()) return 0;
      return bits[0];
    }
    constexpr string to_string() const {
      string res;
      res.reserve(siz);
      for (size_t i = 0; i < siz; ++i) res += (test(i) ? '1' : '0');
      ranges::reverse(res);
      return res;
    }

    constexpr bool operator==(const DynamicBitset& other) const {
      if (siz != other.siz) return false;
      for (size_t i = 0; i < bits.size(); ++i)
        if (bits[i] != other.bits[i]) return false;
      return true;
    }
    constexpr bool operator!=(const DynamicBitset& other) const {
      return !(*this == other);
    }
    constexpr DynamicBitset operator<<(const size_t shift) const {
      DynamicBitset res = *this;
      res <<= shift;
      return res;
    }
    constexpr DynamicBitset operator>>(const size_t shift) const {
      DynamicBitset res = *this;
      res >>= shift;
      return res;
    }
    constexpr DynamicBitset operator&(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res &= other;
      return res;
    }
    constexpr DynamicBitset operator|(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res |= other;
      return res;
    }
    constexpr DynamicBitset operator^(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res ^= other;
      return res;
    }
  };
}  // namespace asalib::ds
#line 2 "library/data-structure/dynamic-bitset.hpp"

#include <algorithm>
#include <bit>
#include <concepts>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
using namespace std;

namespace asalib::ds {
  class DynamicBitset {
    private:
    using ull = uint64_t;
    size_t siz = 0;
    // TODO: valarray が constexpr に対応したら変える
    vector<ull> bits;

    public:
    constexpr explicit DynamicBitset() = default;
    constexpr DynamicBitset(const DynamicBitset&) = default;
    constexpr ~DynamicBitset() = default;
    constexpr DynamicBitset& operator=(const DynamicBitset&) = default;
    constexpr explicit DynamicBitset(const size_t size) {
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
    }
    template<integral T>
    constexpr explicit DynamicBitset(const size_t size, const T value) {
      // TODO: ほかの型も考慮する
      static_assert(sizeof(T) <= sizeof(ull), "DynamicBitset: value type too large");
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
      bits[0] = static_cast<ull>(value);
    }

    constexpr DynamicBitset& operator&=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] &= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator|=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] |= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator^=(const DynamicBitset& other) {
      const size_t s = min(bits.size(), other.bits.size());
      for (size_t i = 0; i < s; ++i) bits[i] ^= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator<<=(const size_t shift) {
      const size_t full = shift >> 6;
      const size_t rem = shift & 63;
      vector<ull> new_bits(bits.size(), 0);
      for (size_t i = 0; i < bits.size(); ++i) {
        if (i + full < new_bits.size()) {
          new_bits[i + full] |= bits[i] << rem;
          if (i + full + 1 < new_bits.size()) new_bits[i + full + 1] |= bits[i] >> (64 - rem);
        }
      }
      bits = std::move(new_bits);
      return *this;
    }
    constexpr DynamicBitset& operator>>=(const size_t shift) {
      const size_t full = shift >> 6;
      const size_t rem = shift & 63;
      vector<ull> new_bits(bits.size(), 0);
      for (size_t i = full; i < bits.size(); ++i) {
        new_bits[i - full] |= bits[i] >> rem;
        if (i - full - 1 < new_bits.size()) new_bits[i - full - 1] |= bits[i] << (64 - rem);
      }
      bits = std::move(new_bits);
      return *this;
    }
    constexpr DynamicBitset& set() {
      for (size_t i = 0; i < bits.size(); ++i) bits[i] = ~0ULL;
      return *this;
    }
    constexpr DynamicBitset& set(const size_t pos, const bool val = true) {
      if (pos >= siz) throw out_of_range("DynamicBitset::set: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      if (val)
        bits[idx] |= (1ULL << bit);
      else
        bits[idx] &= ~(1ULL << bit);
      return *this;
    }
    constexpr DynamicBitset& reset() {
      ranges::fill(bits, 0);
      return *this;
    }
    constexpr DynamicBitset& reset(size_t pos) { return set(pos, false); }
    constexpr DynamicBitset operator~() const {
      DynamicBitset res = *this;
      res.flip();
      return res;
    }
    constexpr DynamicBitset& flip() {
      for (size_t i = 0; i < bits.size(); ++i) bits[i] = ~bits[i];
      return *this;
    }
    constexpr DynamicBitset& flip(const size_t pos) {
      if (pos >= siz) throw out_of_range("DynamicBitset::flip: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      bits[idx] ^= (1ULL << bit);
      return *this;
    }

    constexpr size_t count() const {
      size_t cnt = 0;
      for (const ull& b : bits) cnt += popcount(b);
      return cnt;
    }
    constexpr size_t size() const { return siz; }
    constexpr bool test(const size_t pos) const {
      if (pos >= siz) throw out_of_range("DynamicBitset::test: position out of range");
      const size_t idx = pos >> 6;
      const size_t bit = pos & 63;
      return (bits[idx] >> bit) & 1;
    }
    constexpr bool all() const {
      for (const ull& b : bits)
        if (b != ~0ULL) return false;
      return true;
    }
    constexpr bool any() const {
      for (const ull& b : bits)
        if (b != 0) return true;
      return false;
    }
    constexpr bool none() const {
      for (const ull& b : bits)
        if (b != 0) return false;
      return true;
    }
    constexpr ull to_ull() const {
      if (bits.size() > 1) throw logic_error("DynamicBitset::to_ull: overflow");
      if (bits.empty()) return 0;
      return bits[0];
    }
    constexpr string to_string() const {
      string res;
      res.reserve(siz);
      for (size_t i = 0; i < siz; ++i) res += (test(i) ? '1' : '0');
      ranges::reverse(res);
      return res;
    }

    constexpr bool operator==(const DynamicBitset& other) const {
      if (siz != other.siz) return false;
      for (size_t i = 0; i < bits.size(); ++i)
        if (bits[i] != other.bits[i]) return false;
      return true;
    }
    constexpr bool operator!=(const DynamicBitset& other) const {
      return !(*this == other);
    }
    constexpr DynamicBitset operator<<(const size_t shift) const {
      DynamicBitset res = *this;
      res <<= shift;
      return res;
    }
    constexpr DynamicBitset operator>>(const size_t shift) const {
      DynamicBitset res = *this;
      res >>= shift;
      return res;
    }
    constexpr DynamicBitset operator&(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res &= other;
      return res;
    }
    constexpr DynamicBitset operator|(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res |= other;
      return res;
    }
    constexpr DynamicBitset operator^(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res ^= other;
      return res;
    }
  };
}  // namespace asalib::ds
Back to top page