// TR2 <dynamic_bitset> -*- C++ -*-

// Copyright (C) 2009-2025 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library 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 3, or (at your option)
// any later version.

// This library 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.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file tr2/dynamic_bitset
 *  This is a TR2 C++ Library header.
 */

#ifndef _GLIBCXX_TR2_DYNAMIC_BITSET
#define _GLIBCXX_TR2_DYNAMIC_BITSET 1

#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif

#include <limits>
#include <vector>
#include <string>
#include <istream>
#include <bits/functexcept.h>
#include <bits/stl_algo.h>	// For fill
#include <bits/cxxabi_forced.h>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

namespace tr2
{
  /**
   *  @defgroup dynamic_bitset Dynamic Bitset.
   *  @ingroup extensions
   *
   *  @{
   */

  /**
   *  Base class, general case.
   *
   *  See documentation for dynamic_bitset.
   */
  template<typename _WordT = unsigned long long,
	   typename _Alloc = std::allocator<_WordT>>
    struct __dynamic_bitset_base
    {
      static_assert(std::is_unsigned<_WordT>::value, "template argument "
		    "_WordT not an unsigned integral type");

      typedef _WordT block_type;
      typedef _Alloc allocator_type;
      typedef size_t size_type;

      static const size_type _S_bits_per_block = __CHAR_BIT__ * sizeof(block_type);
      static const size_type npos = static_cast<size_type>(-1);

      /// 0 is the least significant word.
      std::vector<block_type, allocator_type> _M_w;

      explicit
      __dynamic_bitset_base(const allocator_type& __alloc)
      : _M_w(__alloc)
      { }

      __dynamic_bitset_base() = default;
      __dynamic_bitset_base(const __dynamic_bitset_base&) = default;
      __dynamic_bitset_base(__dynamic_bitset_base&& __b) = default;
      __dynamic_bitset_base& operator=(const __dynamic_bitset_base&) = default;
      __dynamic_bitset_base& operator=(__dynamic_bitset_base&&) = default;
      ~__dynamic_bitset_base() = default;

      explicit
      __dynamic_bitset_base(size_type __nbits, unsigned long long __val = 0ULL,
			   const allocator_type& __alloc = allocator_type())
      : _M_w(__nbits / _S_bits_per_block + (__nbits % _S_bits_per_block > 0),
	     block_type(0), __alloc)
      {
	if (__nbits < std::numeric_limits<decltype(__val)>::digits)
	  __val &= ~(-1ULL << __nbits);
	if (__val == 0)
	  return;

	if _GLIBCXX17_CONSTEXPR (sizeof(__val) == sizeof(block_type))
	  _M_w[0] = __val;
	else
	  {
	    const size_t __n
	      = std::min(_M_w.size(), sizeof(__val) / sizeof(block_type));
	    for (size_t __i = 0; __val && __i < __n; ++__i)
	      {
		_M_w[__i] = static_cast<block_type>(__val);
		__val >>= _S_bits_per_block;
	      }
	  }
      }

      void
      _M_swap(__dynamic_bitset_base& __b) noexcept
      { this->_M_w.swap(__b._M_w); }

      void
      _M_clear() noexcept
      { this->_M_w.clear(); }

      void
      _M_resize(size_t __nbits, bool __value)
      {
	size_t __sz = __nbits / _S_bits_per_block;
	if (__nbits % _S_bits_per_block > 0)
	  ++__sz;
	if (__sz != this->_M_w.size())
	  {
	    block_type __val = 0;
	    if (__value)
	      __val = std::numeric_limits<block_type>::max();
	    this->_M_w.resize(__sz, __val);
	  }
      }

      allocator_type
      _M_get_allocator() const noexcept
      { return this->_M_w.get_allocator(); }

      static size_type
      _S_whichword(size_type __pos) noexcept
      { return __pos / _S_bits_per_block; }

      static size_type
      _S_whichbyte(size_type __pos) noexcept
      { return (__pos % _S_bits_per_block) / __CHAR_BIT__; }

      static size_type
      _S_whichbit(size_type __pos) noexcept
      { return __pos % _S_bits_per_block; }

      static block_type
      _S_maskbit(size_type __pos) noexcept
      { return (static_cast<block_type>(1)) << _S_whichbit(__pos); }

      block_type&
      _M_getword(size_type __pos) noexcept
      { return this->_M_w[_S_whichword(__pos)]; }

      block_type
      _M_getword(size_type __pos) const noexcept
      { return this->_M_w[_S_whichword(__pos)]; }

      block_type&
      _M_hiword() noexcept
      { return this->_M_w[_M_w.size() - 1]; }

      block_type
      _M_hiword() const noexcept
      { return this->_M_w[_M_w.size() - 1]; }

      void
      _M_do_and(const __dynamic_bitset_base& __x) noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	    this->_M_w[__i] &= __x._M_w[__i];
	else
	  return;
      }

      void
      _M_do_or(const __dynamic_bitset_base& __x) noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	    this->_M_w[__i] |= __x._M_w[__i];
	else
	  return;
      }

      void
      _M_do_xor(const __dynamic_bitset_base& __x) noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	    this->_M_w[__i] ^= __x._M_w[__i];
	else
	  return;
      }

      void
      _M_do_dif(const __dynamic_bitset_base& __x) noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	    this->_M_w[__i] &= ~__x._M_w[__i];
	else
	  return;
      }

      void
      _M_do_left_shift(size_t __shift);

      void
      _M_do_right_shift(size_t __shift);

      void
      _M_do_flip() noexcept
      {
	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	  this->_M_w[__i] = ~this->_M_w[__i];
      }

      void
      _M_do_set() noexcept
      {
	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	  this->_M_w[__i] = static_cast<block_type>(-1);
      }

      void
      _M_do_reset() noexcept
      {
	std::fill(_M_w.begin(), _M_w.end(), static_cast<block_type>(0));
      }

      bool
      _M_is_equal(const __dynamic_bitset_base& __x) const noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  {
	    for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	      if (this->_M_w[__i] != __x._M_w[__i])
		return false;
	    return true;
	  }
	else
	  return false;
      }

      bool
      _M_is_less(const __dynamic_bitset_base& __x) const noexcept
      {
	if (__x._M_w.size() == this->_M_w.size())
	  {
	    for (size_t __i = this->_M_w.size(); __i > 0; --__i)
	      {
		if (this->_M_w[__i-1] < __x._M_w[__i-1])
		  return true;
		else if (this->_M_w[__i-1] > __x._M_w[__i-1])
		  return false;
	      }
	    return false;
	  }
	else
	  return false;
      }

      size_t
      _M_are_all_aux() const noexcept
      {
	for (size_t __i = 0; __i < this->_M_w.size() - 1; ++__i)
	  if (_M_w[__i] != static_cast<block_type>(-1))
	    return 0;
	return ((this->_M_w.size() - 1) * _S_bits_per_block
		+ __builtin_popcountll(this->_M_hiword()));
      }

      bool
      _M_is_any() const noexcept
      {
	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	  if (this->_M_w[__i] != static_cast<block_type>(0))
	    return true;
	return false;
      }

      bool
      _M_is_subset_of(const __dynamic_bitset_base& __b) noexcept
      {
	if (__b._M_w.size() == this->_M_w.size())
	  {
	    for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	      if (this->_M_w[__i] != (this->_M_w[__i] | __b._M_w[__i]))
		return false;
	    return true;
	  }
	else
	  return false;
      }

      bool
      _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const noexcept
      {
	if (this->_M_is_subset_of(__b))
	  {
	    if (*this == __b)
	      return false;
	    else
	      return true;
	  }
	else
	  return false;
      }

      size_t
      _M_do_count() const noexcept
      {
	size_t __result = 0;
	for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
	  __result += __builtin_popcountll(this->_M_w[__i]);
	return __result;
      }

      size_type
      _M_size() const noexcept
      { return this->_M_w.size(); }

      unsigned long
      _M_do_to_ulong() const;

      unsigned long long
      _M_do_to_ullong() const;

      // find first "on" bit
      size_type
      _M_do_find_first(size_t __not_found) const;

      // find the next "on"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       