// bslstl_bitset.h                                                    -*-C++-*-
#ifndef INCLUDED_BSLSTL_BITSET
#define INCLUDED_BSLSTL_BITSET

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an STL-compliant bitset class.
//
//@CLASSES:
//  bsl::bitset: STL-compatible bitset template
//
//@CANONICAL_HEADER: bsl_bitset.h
//
//@SEE_ALSO: package bos+stdhdrs in the bos package group
//
//@DESCRIPTION: This component is for internal use only.  Please include
// '<bsl_bitset.h>' instead and use 'bsl::bitset' directly.  This component
// implements a static bitset class that is suitable for use as an
// implementation of the 'std::bitset' class template.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Determining if a Number is Prime (Sieve of Eratosthenes)
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to write a function to determine whether or not a given
// number is prime.  One way to implement this function is by using what's
// called the Sieve of Eratosthenes.  The basic idea of this algorithm is to
// repeatedly walk the sequence of integer values and mark any numbers up to
// and including the particular value of interest that are integer multiples of
// first 2, then 3, then 5, etc. (skipping 4 because it was previously marked
// when we walked the sequence by 2's).  Once we have walked the sequence with
// all primes up to and including the square root of the number of interest, we
// check to see if that number has been marked: If it has, it's composite;
// otherwise it's prime.
//
// When implementing this classic algorithm, we need an efficient way of
// representing a flag for each potential prime number.  The following
// illustrates how we can use 'bsl::bitset' to accomplish this result, provided
// we know an upper bound on supplied candidate values at compile time.
//
// First, we begin to define a function template that will determine whether or
// not a given candidate value is prime:
//..
//  template <unsigned int MAX_VALUE>
//  bool isPrime(int candidate)
//      // Return 'true' if the specified 'candidate' value is a prime number,
//      // and 'false' otherwise.  The behavior is undefined unless
//      // '2 <= candidate <= MAX_VALUE'
//  {
//      BSLMF_ASSERT(2 <= MAX_VALUE);
//      BSLS_ASSERT(2 <= candidate); BSLS_ASSERT(candidate <= MAX_VALUE);
//..
// Then, we declare a 'bsl::bitset', 'compositeFlags', that will contain flags
// indicating whether a value corresponding to a given index is known to be
// composite ('true') or is still potentially prime ('false') up to and
// including the compile-time constant template parameter, 'MAX_VALUE'.
//..
//      // Candidate primes in the '[2 .. MAX_VALUE]' range.
//
//      bsl::bitset<MAX_VALUE + 1> compositeFlags;
//..
// Next, we observe that a default-constructed 'bsl::bitset' has no flags set,
// We can check this by asserting that the 'none' method returns true, by
// asserting that the 'any' method returns false, or by asserting that the
// 'count' of set bits is 0:
//..
//      assert(true  == compositeFlags.none());
//      assert(false == compositeFlags.any());
//      assert(0     == compositeFlags.count());
//..
// Then, we note that a 'bsl::bitset' has a fixed 'size' (the set can't be
// grown or shrunk) and verify that 'size' is the same as the template argument
// used to create the 'bsl::bitset':
//..
//      assert(MAX_VALUE + 1 == compositeFlags.size());
//..
// Next, we compute 'sqrt(candidate)', which is as far as we need to look:
//..
//      // We need to cast the 'sqrt' argument to avoid an overload ambiguity.
//      const int sqrtOfCandidate = std::sqrt(static_cast<double>(candidate))
//                                + 0.01;  // fudge factor
//..
// Now, we loop from 2 to 'sqrtOfCandidate', and use the sieve algorithm to
// eliminate non-primes:
//..
//      // Note that we treat 'false' values as potential primes,
//      // since that is how 'bsl::bitset' is default-initialized.
//
//      for (std::size_t i = 2; i <= sqrtOfCandidate; ++i) {
//          if (compositeFlags[i]) {
//              continue; // Skip this value: it's flagged as composite, so all
//                        // of its multiples are already flagged as composite
//                        // as well.
//          }
//
//          for (std::size_t flagValue = i;
//               flagValue <= candidate;
//               flagValue += i) {
//              compositeFlags[flagValue] = true;
//          }
//
//          if (true == compositeFlags[candidate]) {
//              return false;                                         // RETURN
//          }
//      }
//
//      BSLS_ASSERT(false == compositeFlags[candidate]);
//
//      return true;
//  }
//..
// Notice that if we don't return 'false' from the loop, none of the lower
// numbers evenly divided the candidate value; hence, it is a prime number.
//
// Finally, we can exercise our 'isPrime' function with an upper bound of
// 10,000:
//..
//  enum { UPPER_BOUND = 10000 };
//
//  assert(1 == isPrime<UPPER_BOUND>(2));
//  assert(1 == isPrime<UPPER_BOUND>(3));
//  assert(0 == isPrime<UPPER_BOUND>(4));
//  assert(1 == isPrime<UPPER_BOUND>(5));
//  assert(0 == isPrime<UPPER_BOUND>(6));
//  assert(1 == isPrime<UPPER_BOUND>(7));
//  assert(0 == isPrime<UPPER_BOUND>(8));
//  assert(0 == isPrime<UPPER_BOUND>(9));
//  assert(0 == isPrime<UPPER_BOUND>(10));
//  // ...
//  assert(1 == isPrime<UPPER_BOUND>(9973));
//  assert(0 == isPrime<UPPER_BOUND>(9975));
//  assert(0 == isPrime<UPPER_BOUND>(10000));
//..

#include <bslscm_version.h>

#include <bslstl_stdexceptutil.h>
#include <bslstl_string.h>

#include <bslma_stdallocator.h>

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_performancehint.h>
#include <bsls_platform.h>

#include <algorithm>    // 'min'

#include <cstddef>

#include <iosfwd>

#include <string>
#include <limits.h>
#include <string.h>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#if defined(BSLS_PLATFORM_CMP_MSVC) ||                                        \
   (defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION < 40400)
    // Last tested against MSVC 2013.  The Microsoft compiler cannot parse the
    // nested typenames for function parameters with default arguments, where
    // the function parameter type is a dependent type within a template, such
    // as 'typename std::basic_string<C,T,A>::size_type'.  The error message
    // complains about invalid identiefiers on the right of the '::', and this
    // feature macro is named accordingly.  Older version of g++ also have this
    // problem.
# define BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS
#endif

namespace bsl {

template <std::size_t N>
class bitset;

                          // ====================
                          // class Bitset_ImpUtil
                          // ====================
struct Bitset_ImpUtil {
    enum {
        k_BYTES_PER_INT = sizeof(int),
        k_BITS_PER_INT  = CHAR_BIT * sizeof(int),
        k_INTS_IN_LONG  = sizeof(long) / sizeof(int)
    };

    static void defaultInit(unsigned int  *data,
                            size_t         size,
                            unsigned long  val = 0);
        // Initialize the memory at the address specified by 'data' so that the
        // the first 'M' bit positions correspond to the bit values in the
        // specified 'val' where 'M' is the smaller of 'size * k_BITS_PER_INT'
        // and 'CHAR_BIT * sizeof(unsigned long)'.  The remaining bits are
        // initialized to zero '0'.
};

                          // ====================
                          // class Bitset_ImpBase
                          // ====================

template <std::size_t BITSETSIZE,
          std::size_t NUM_INIT =  (BITSETSIZE < sizeof(long) / sizeof(int))
                                 ? BITSETSIZE : sizeof(long) / sizeof(int)>
class Bitset_ImpBase;
    // This component private 'class' template describes the basic data and
    // initialization semantics needed in order to implement a C++11 'bitset'
    // class.  The 'BITSETSIZE' template parameter specifies the size of the
    // underlying data array, 'd_data'.  The 'NUM_INIT' template parameter
    // specifies the number of elements in 'd_data' needed to use when storing
    // a value of type 'unsigned long'.  Partial class template specializations
    // of 'Bitset_ImpBase' are provided for 'NUM_INIT == 1' and
    // 'NUM_INIT == 2'.  No other values of 'NUM_INIT' are supported.

#if __cplusplus >= 201103L
template <std::size_t BITSETSIZE, std::size_t NUM_INIT>
class Bitset_ImpBase {
  private:
    static_assert(NUM_INIT != NUM_INIT,
                  "bsl::bitset is not supported on this target because "
                  "sizeof(long) / sizeof(int) is neither 1 nor 2.");
};
#endif


template <std::size_t BITSETSIZE>
class Bitset_ImpBase<BITSETSIZE, 1> {
  public:
    // PUBLIC DATA
    unsigned int d_data[BITSETSIZE];

    // CREATORS
    BSLS_KEYWORD_CONSTEXPR Bitset_ImpBase();
        // Create a 'Bitset_ImpBase' with each bit in 'd_data' initialized to
        // zero.  In C++11 this constructor can be used in a constant
        // expression.

    BSLS_KEYWORD_CONSTEXPR Bitset_ImpBase(unsigned long val);
        // Create a 'Bitset_ImpBase' with the first 'N' bit positions of
        // 'd_data' corresponding to the first 'N' bit positions of the
        // specified 'val' after conversion to 'unsigned int' and the remaining
        // bits in 'd_data' initialized to zero, where 'N' is
        // 'CHAR_BIT * sizeof(int)'.  The behavior is undefined unless
        // 'BITSETSIZE == 1' or 'sizeof(long) / sizeof(int) == 1'.  In C++11
        // this constructor can be used in a constant expression.
};

template <std::size_t BITSETSIZE>
class Bitset_ImpBase<BITSETSIZE, 2> {
  public:
    // PUBLIC DATA
    unsigned int d_data[BITSETSIZE];

    // CREATORS
    BSLS_KEYWORD_CONSTEXPR Bitset_ImpBase();
        // Create a Bitset_ImpBase with each bit in 'd_data' initialized to
        // zero.  In C++11 this constructor can be used in a constant
        // expression.

    BSLS_KEYWORD_CONSTEXPR Bitset_ImpBase(unsigned long);
        // Create a 'Bitset_ImpBase' with the first 'N' bit positions of
        // 'd_data' corresponding to the first 'N' bit positions of the
        // specified 'val' after conversion to 'unsigned int' and the remaining
        // bits in 'd_data' initialized to zero, where 'N' is
        // 'CHAR_BIT * sizeof(int) * 2'.  The behavior is undefined unless
        // 'sizeof(long) / sizeof(int) == 2'.  In C++11 this constructor can be
        // used in a constant expression.
};

                        // =================
                        // class bsl::bitset
                        // =================

template <std::size_t N>
class bitset :
       private Bitset_ImpBase<N ? (N - 1) / (CHAR_BIT * sizeof(int)) + 1 : 1> {
    // This class template provides an STL-compliant 'bitset'.  For the
    // requirements of a 'bitset' class, consult the second revision of the
    // ISO/IEC 14882 Programming Language c++ (2011).
    //
    // In addition to the methods defined in the standard, this class also
    // provides an extra constructor that takes a 'bsl::basic_string'.  This
    // extra constructor provides the capability to construct a 'bitset' from a
    // 'bsl::basic_string', in addition to a 'std::basic_string'.

    // PRIVATE TYPES
    enum {
        k_BYTES_PER_INT = sizeof(int),
        k_BITS_PER_INT  = CHAR_BIT * k_BYTES_PER_INT,
        k_BITSETSIZE    = N ? (N - 1) / k_BITS_PER_INT + 1 : 1
    };

    // 'static_cast' is needed here to avoid warning with '-Wextra' and 'gcc'.
    typedef Bitset_ImpBase<static_cast<std::size_t>(k_BITSETSIZE)> Base;

    using Base::d_data;

    // FRIENDS
    friend class reference;

  public:
    // PUBLIC TYPES
    class reference {
        // This class represents a reference to a modifiable bit inside a
        // 'bsl::bitset'.

        // FRIENDS
        friend class bitset;

        // DATA
        unsigned int *d_int_p;   // pointer to the 'int' inside the 'bitset'.
        unsigned int  d_offset;  // bit offset to 'd_int'.

        // PRIVATE CREATORS
        reference(unsigned int *i, unsigned int offset);
            // Create a 'reference' object that refers to the bit at the
            // specified 'offset' of the 'int' pointed to by the specified 'i'.
            // The behavior is undefined unless 'i' points to an 'int' inside a
            // 'bsl::bitset'.

      public:
#ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS
        // CREATORS
        reference(const reference& original) BSLS_KEYWORD_NOEXCEPT = default;
            // Create a 'reference' object having the same value as the
            // specified 'original' object.  Note that this copy constructor is
            // generated by the compiler.
#endif

        // MANIPULATORS
        reference& operator=(bool x) BSLS_KEYWORD_NOEXCEPT;
            // Assign to the bit referenced by this object the specified value
            // 'x' and return a reference offering modifiable access to this
            // object.

        reference& operator=(const reference& x) BSLS_KEYWORD_NOEXCEPT;
            // Assign this object to refer to the same bit as the specified 'x'
            // and return a reference offering modifiable access to this
            // object.

        reference& flip() BSLS_KEYWORD_NOEXCEPT;
            // Invert the value of the bit referenced by this object and return
            // a reference offering modifiable access to this object.

        // ACCESSORS
        operator bool() const BSLS_KEYWORD_NOEXCEPT;
            //  Return the value of the bit referenced by this object.

        bool operator~() const BSLS_KEYWORD_NOEXCEPT;
            // Return the inverted value of the bit referenced by this object.
            // Note that the value of the referenced bit remains unchanged.
    };

  private:
    // PRIVATE MANIPULATORS
    void clearUnusedBits();
        // Clear the bits unused by the bitset in 'd_data', namely, bits
        // 'k_BITSETSIZE * k_BITS_PER_INT - 1' to 'N' (where the bit count
        // starts at 0).

    void clearUnusedBits(bsl::false_type);
    void clearUnusedBits(bsl::true_type);
        // Implementations of 'clearUnusedBits', overloaded by whether there
        // are any unused bits.

    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    void copyString(const    std::basic_string<CHAR_TYPE,
                                               TRAITS,
                                               ALLOCATOR>&           str,
                    typename std::basic_string<CHAR_TYPE,
                                               TRAITS,
                                               ALLOCATOR>::size_type pos,
                    typename std::basic_string<CHAR_TYPE,
                                               TRAITS,
                                               ALLOCATOR>::size_type n,
                    CHAR_TYPE zeroChar,
                    CHAR_TYPE oneChar);
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    void copyString(
      const     bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&           str,
      typename  bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos,
      typename  bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n,
      CHAR_TYPE zeroChar,
      CHAR_TYPE oneChar);
        // Assign to the first 'M' bit of this object a value corresponding to
        // the characters in the specified 'pos' of the specified 'str'.  'M'
        // is the smaller of the specified 'N' and 'str.length()'.  If 'M < N'
        // the remaining bit positions are left unchanged.  Characters with the
        // value 'zeroChar' correspond to an unset bit and characters with the
        // value 'oneChar' correspond to a set bit.  The behavior is undefined
        // if any characters in 'str' is neither the specified 'zeroChar' nor
        // the specified 'oneChar'.

    // PRIVATE ACCESSORS
    std::size_t numOneSet(unsigned int src) const;
        // Return the number of 1 bits in the specified 'src'.

  public:
    // CREATORS
    BSLS_KEYWORD_CONSTEXPR bitset() BSLS_KEYWORD_NOEXCEPT;
        // Create a 'bitset' with all bits initialized to '0'.

    BSLS_KEYWORD_CONSTEXPR
    bitset(unsigned long val) BSLS_KEYWORD_NOEXCEPT;                // IMPLICIT
        // Create a bitset with its first 'M' bit positions correspond to bit
        // values in the specified 'val'.  'M' is the smaller of the
        // parameterized 'N' and '8 * sizeof(unsigned long)'.  If 'M < N', the
        // remaining bit positions are initialized to 0.

#if !defined(BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS)
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    explicit bitset(
     const std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&     str,
     typename
     std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos = 0,
     typename
     std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n   =
                  std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::npos,
     CHAR_TYPE zeroChar = CHAR_TYPE('0'),
     CHAR_TYPE oneChar  = CHAR_TYPE('1'));
#else
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    explicit
    bitset(const std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>& str,
           bsl::string::size_type pos      = 0,
           bsl::string::size_type n        = bsl::string::npos,
           CHAR_TYPE              zeroChar = CHAR_TYPE('0'),
           CHAR_TYPE              oneChar  = CHAR_TYPE('1'));
#endif
        // Create a bitset with its first 'M' bit positions corresponding to
        // the characters in the specified 'pos' of the specified 'str'.  'M'
        // is the smaller of the parameterized 'N' and 'str.length()'.  If
        // 'M < N', the remaining bit positions are initialized to 0.
        // Characters with the value 'zeroChar' correspond to an unset bit and
        // characters with the value 'oneChar' correspond to a set bit.  The
        // behavior is undefined if any characters in 'str' is neither the
        // specified 'zeroChar' nor the specified 'oneChar'.

#if !defined(BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS)
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    explicit bitset(
      const bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&              str,
      typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos =
                                                                             0,
      typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n   =
                         bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::npos,
      CHAR_TYPE zeroChar = CHAR_TYPE('0'),
      CHAR_TYPE oneChar  = CHAR_TYPE('1'));
#else
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
    explicit bitset(const bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>& str,
                    bsl::string::size_type pos      = 0,
                    bsl::string::size_type n        = bsl::string::npos,
                    CHAR_TYPE              zeroChar = CHAR_TYPE('0'),
                    CHAR_TYPE              oneChar  = CHAR_TYPE('1'));
#endif
        // Create a bitset with its first 'M' bit positions corresponding to 0
        // the characters in the specified 'pos' of the specified 'str'.  'M'
        // is the smaller of the parameterized 'N' and 'str.length()'.  If
        // 'M < N', the remaining bit positions are initialized to 0.
        // Characters with the value 'zeroChar' correspond to an unset bit and
        // characters with the value 'oneChar' correspond to a set bit.  The
        // behavior is undefined if the characters in the specified 'str' is
        // not the specified 'zeroChar' and not the specified 'oneChar'

    // MANIPULATORS
    bitset& operator&=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT;
        // Clear each bit of this bitset for each corresponding bit that is 0
        // in the specified 'rhs', and leaves all other bits unchanged.  Return
        // a reference to this modifiable bitset.  Note that this is equivalent
        // to a bitwise OR.

    bitset& operator|=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT;
        // Set each bit of this bitset for each corresponding bit that is 1 in
        // the specified 'rhs', and leaves all other bits unchanged.  Return a
        // reference to this modifiable bitset.  Note that this is equivalent
        // to a bitwise AND.

    bitset& operator^=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT;
        // Toggle each bit of this bitset for each corresponding bit that is 1
        // in the specified 'rhs', and leaves all other bits unchanged.  Return
        // a reference to this modifiable bitset.  Note that this is equivalent
        // to a bitwise XOR.

    bitset& operator<<=(std::size_t pos) BSLS_KEYWORD_NOEXCEPT;
        // Shift the bits of this bitset left (towards the most significant
        // bit) by the specified 'pos' and return a reference to this
        // modifiable bitset.  For all bits with position I where 'I <= pos',
        // the new value is 0.  The behavior is undefined unless 'pos <= N'.

    bitset& operator>>=(std::size_t pos) BSLS_KEYWORD_NOEXCEPT;
        // Shift the bits of this bitset right (towards the least significant
        // bit) by the specified 'pos' and return a reference to this
        // modifiable bitset.  For all bits with position I where
        // 'I > N - pos', the new value is 0.  The behavior is undefined unless
        // 'pos <= N'.

    bitset& flip() BSLS_KEYWORD_NOEXCEPT;
        // Toggle all bits of this bitset and return a reference to this
        // modifiable bitset.

    bitset& flip(std::size_t pos);
        // Toggle the bit at the specified 'pos' of this bitset and return a
        // reference to this modifiable bitset.

    bitset& reset() BSLS_KEYWORD_NOEXCEPT;
        // Set all bits of this bitset to 0 and return a reference to this
        // modifiable bitset.

    bitset& reset(std::size_t pos);
        // Set the bit at the specified 'pos' of this bitset to 0 and return a
        // reference to this modifiable bitset.

    bitset& set() BSLS_KEYWORD_NOEXCEPT;
        // Set all bits of this bitset to 1 and return a reference to this
        // modifiable bitset.

    bitset& set(std::size_t pos, int val = true);
        // Set the bit at the specified 'pos' of this bitset to 1 and return a
        // reference to this modifiable bitset.  Optionally specify 'val' as
        // the value to set the bit.  If 'val' is non-zero, the bit is set to
        // 1, otherwise the bit is set to 0.

    reference operator[](std::size_t pos);
        // Return a 'reference' to the modifiable bit position at the specified
        // 'pos'.

    // ACCESSORS
    bitset operator<<(std::size_t pos) const BSLS_KEYWORD_NOEXCEPT;
        // Return a bitset constructed from shifting this bitset left by the
        // specified 'pos'.

    bitset operator>>(std::size_t pos) const BSLS_KEYWORD_NOEXCEPT;
        // Return a bitset constructed from shifting this bitset right by the
        // specified 'pos'.

    bitset operator~() const BSLS_KEYWORD_NOEXCEPT;
        // Toggle all bits of this bitset and return a reference to this
        // modifiable bitset.

    BSLS_KEYWORD_CONSTEXPR bool operator[](std::size_t pos) const;
        // Return the value of the bit position at the specified 'pos'.

    bool operator==(const bitset& rhs) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if the specified 'rhs' has the same value as this
        // bitset and 'false' otherwise.  Two bitsets have the same value when
        // the sequence and value of bits they hold are the same.

    bool operator!=(const bitset& rhs) const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if the specified 'rhs' do not have the same value as
        // this bitset and 'false' otherwise.  Two bitset do not have the same
        // value when either the sequence or the value of bits they hold are
        // not the same.

    bool all() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if all of the bits in this bitset have the value of 1
        // and 'false' otherwise.  Note that 'all()' and 'none()' are both true
        // for bitsets of size 0.

    bool any() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if one or more of the bits in this bitset has the
        // value of 1 and 'false' otherwise.

    bool none() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if all the bits in this bitset has the value of 0 and
        // 'false' otherwise.  Note that 'all()' and 'none()' are both true
        // for bitsets of size 0.

    std::size_t count() const BSLS_KEYWORD_NOEXCEPT;
        // Return the number of bits in this bitset that have the value of 1.

    BSLS_KEYWORD_CONSTEXPR std::size_t size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the number of bits this bitset holds.

    bool test(size_t pos) const;
        // Return 'true' if the bit at the specified 'pos' has the value of 1
        // and 'false' otherwise.

#if __cplusplus >= 201103L
    template <class CHAR_TYPE = char,
              class TRAITS = char_traits<CHAR_TYPE>,
              class ALLOCATOR = allocator<CHAR_TYPE> >
#else
    template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
#endif
    basic_string<CHAR_TYPE, TRAITS, ALLOCATOR> to_string(
                                        CHAR_TYPE zero = CHAR_TYPE('0'),
                                        CHAR_TYPE one  = CHAR_TYPE('1')) const;
        // Return a 'basic_string' representation of this bitset, where the
        // zero-bits are represented by the specified 'zero' character and the
        // one-bits are represented by the specified 'one' character.  The
        // most-significant bit is placed at the beginning of the string, and
        // the least-significant bit is placed at the end of the string.

    unsigned long to_ulong() const;
        // Return an 'unsigned' 'long' value that has the same bit value as the
        // bitset.  Note that the behavior is undefined if the bitset cannot be
        // represented as an 'unsigned' 'long'.
};

// FREE OPERATORS
template <std::size_t N>
bitset<N> operator&(const bitset<N>& lhs, const bitset<N>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
    // Return a 'bitset' that results from a bitwise AND of the specified 'lhs'
    // and 'rhs'.

template <std::size_t N>
bitset<N> operator|(const bitset<N>& lhs, const bitset<N>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
    // Return a 'bitset' that results from a bitwise OR of the specified 'lhs'
    // and 'rhs'.

template <std::size_t N>
bitset<N> operator^(const bitset<N>& lhs, const bitset<N>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;
    // Return a 'bitset' that results from a bitwise XOR of the specified 'lhs'
    // and 'rhs'.

template <class CHAR_TYPE, class TRAITS, std::size_t N>
std::basic_istream<CHAR_TYPE, TRAITS>&
operator>>(std::basic_istream<CHAR_TYPE, TRAITS>& is, bitset<N>& x);

template <class CHAR_TYPE, class TRAITS, std::size_t N>
std::basic_ostream<CHAR_TYPE, TRAITS>&
operator<<(std::basic_ostream<CHAR_TYPE, TRAITS>& os, const bitset<N>& x);

// ============================================================================
//                   INLINE AND TEMPLATE FUNCTION DEFINITIONS
// ============================================================================


                        // --------------------------
                        // class Bitset_ImpBase<N, 1>
                        // --------------------------

template <std::size_t BITSETSIZE>
inline BSLS_KEYWORD_CONSTEXPR
Bitset_ImpBase<BITSETSIZE, 1>::Bitset_ImpBase()
: d_data()
{
}

template <std::size_t BITSETSIZE>
inline BSLS_KEYWORD_CONSTEXPR
Bitset_ImpBase<BITSETSIZE, 1>::Bitset_ImpBase(unsigned long val)
#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) \
 &&!(defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1900)
  : d_data{static_cast<unsigned int>(val)}
{
}
#else
{
    Bitset_ImpUtil::defaultInit(d_data, BITSETSIZE, val);
}
#endif

                        // --------------------------
                        // class Bitset_ImpBase<N, 2>
                        // --------------------------

template <std::size_t BITSETSIZE>
inline BSLS_KEYWORD_CONSTEXPR
Bitset_ImpBase<BITSETSIZE, 2>::Bitset_ImpBase()
: d_data()
{
}

  template <std::size_t BITSETSIZE>
inline BSLS_KEYWORD_CONSTEXPR
Bitset_ImpBase<BITSETSIZE, 2>::Bitset_ImpBase(unsigned long val)
#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) \
 &&!(defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VER < 1900)
  : d_data{static_cast<unsigned int>(val),
           static_cast<unsigned int>(val >> (sizeof(int) * CHAR_BIT))}
{
}
#else
{
    Bitset_ImpUtil::defaultInit(d_data, BITSETSIZE, val);
}
#endif

                        // -----------------------
                        // class bitset::reference
                        // -----------------------

// PRIVATE CREATORS
template <std::size_t N>
inline
bitset<N>::reference::reference(unsigned int *i, unsigned int offset)
: d_int_p(i)
, d_offset(offset)
{
    BSLS_ASSERT_SAFE(d_int_p);
}

// MANIPULATORS
template <std::size_t N>
inline
typename bitset<N>::reference&
bitset<N>::reference::operator=(bool x) BSLS_KEYWORD_NOEXCEPT
{
    if (x) {
        *d_int_p |= (1 << d_offset);
    }
    else {
        *d_int_p &= ~(1 << d_offset);
    }
    return *this;
}

template <std::size_t N>
inline
typename bitset<N>::reference&
bitset<N>::reference::operator=(const reference& x) BSLS_KEYWORD_NOEXCEPT
{
    if (x) {
        *d_int_p |= (1 << d_offset);
    }
    else {
        *d_int_p &= ~(1 << d_offset);
    }
    return *this;
}

template <std::size_t N>
inline
typename bitset<N>::reference&
bitset<N>::reference::flip() BSLS_KEYWORD_NOEXCEPT
{
    *d_int_p ^= (1 << d_offset);
    return *this;
}

// ACCESSORS
template <std::size_t N>
inline
bitset<N>::reference::operator bool() const BSLS_KEYWORD_NOEXCEPT
{
    return ((*d_int_p & (1 << d_offset)) != 0);
}

template <std::size_t N>
inline
bool bitset<N>::reference::operator~() const BSLS_KEYWORD_NOEXCEPT
{
    return ((*d_int_p & (1 << d_offset)) == 0);
}

                        // ------------
                        // class bitset
                        // ------------

// PRIVATE MANIPULATORS
template <std::size_t N>
inline
void bitset<N>::clearUnusedBits()
{
    enum { k_VALUE = N % k_BITS_PER_INT ? 1 : 0 };

    clearUnusedBits(bsl::integral_constant<bool, k_VALUE>());
}

template <std::size_t N>
inline
void bitset<N>::clearUnusedBits(bsl::false_type)
{
}

template <std::size_t N>
inline
void bitset<N>::clearUnusedBits(bsl::true_type)
{
    const unsigned int offset = N % k_BITS_PER_INT;  // never 0

    d_data[k_BITSETSIZE - 1] &= ~(~((unsigned int)0) << offset);
}

template <std::size_t N>
std::size_t bitset<N>::numOneSet(unsigned int src) const
{
    // The following code was taken from 'bdes_bitutil'.
    unsigned input = src;

    // First we use a tricky way of getting every 2-bit half-nibble to
    // represent the number of bits that were set in those two bits.

    input -= (input >> 1) & 0x55555555;

    // Henceforth, we just accumulate the sum down into lower and lower bits.

    {
        const int mask = 0x33333333;
        input = ((input >> 2) & mask) + (input & mask);
    }

    // Any 4-bit nibble is now guaranteed to be less than or equal to 8, so we
    // do not have to mask both sides of the addition.  We must mask after the
    // addition, so 8-bit bytes are the sum of bits in those 8 bits.

    input = ((input >> 4) + input) & 0x0f0f0f0f;

    // It is no longer necessary to mask the additions, because it is
    // impossible for any bit groups to add up to more than 256 and carry, thus
    // interfering with adjacent groups.  Each 8-bit byte is independent from
    // now on.

    input = (input >>  8) + input;
    input = (input >> 16) + input;

    return input & 0x000000ff;
}

template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
void bitset<N>::copyString(
const    std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&           str,
typename std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos,
typename std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n,
CHAR_TYPE zeroChar,
CHAR_TYPE oneChar)
{
    typedef typename std::basic_string<CHAR_TYPE,
                                       TRAITS,
                                       ALLOCATOR>::size_type size_type;
    n = std::min(N, std::min(n, str.size() - pos));
    for (size_type i = 0; i < n; ++i) {
        typename TRAITS::int_type bit = TRAITS::to_int_type(
                                                        str[pos + n  - i - 1]);

        if (bit == oneChar) {
            set(i);
        }
        else if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(bit != zeroChar)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            BloombergLP::bslstl::StdExceptUtil::throwInvalidArgument(
                                             "string for bitset constructor "
                                             "must be '0' or '1'");
        }
    }
}

template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
void bitset<N>::copyString(
       const    bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&           str,
       typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos,
       typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n,
       CHAR_TYPE zeroChar,
       CHAR_TYPE oneChar)
{
    typedef typename bsl::basic_string<CHAR_TYPE,
                                          TRAITS,
                                          ALLOCATOR>::size_type size_type;
    n = std::min(N, std::min(n, str.size() - pos));
    for (size_type i = 0; i < n; ++i) {
        typename TRAITS::int_type bit = TRAITS::to_int_type(
                                                        str[pos + n  - i - 1]);

        if (bit == oneChar) {
            set(i);
        }
        else if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(bit != zeroChar)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            BloombergLP::bslstl::StdExceptUtil::throwInvalidArgument(
                                             "string for bitset constructor "
                                             "must be '0' or '1'");
        }
    }
}

// CREATORS
template <std::size_t N>
inline BSLS_KEYWORD_CONSTEXPR
bitset<N>::bitset() BSLS_KEYWORD_NOEXCEPT : Base()
{
}

template <std::size_t N>
BSLS_KEYWORD_CONSTEXPR
bitset<N>::bitset(unsigned long val) BSLS_KEYWORD_NOEXCEPT : Base(val)
{
}

#if !defined(BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS)
template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
inline
bitset<N>::
bitset(const    std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&           str,
       typename std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos,
       typename std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n,
       CHAR_TYPE zeroChar,
       CHAR_TYPE oneChar)
#else
template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
inline
bitset<N>::
bitset(const std::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>& str,
       bsl::string::size_type pos,
       bsl::string::size_type n,
       CHAR_TYPE              zeroChar,
       CHAR_TYPE              oneChar)
#endif
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(pos > str.size())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                                  "'pos > str.size()' for bitset constructor");
    }
    memset(d_data, 0, k_BITSETSIZE * k_BYTES_PER_INT);
    copyString(str, pos, n, zeroChar, oneChar);
}


#if !defined(BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS)
template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
inline
bitset<N>::
bitset(const    bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>&           str,
       typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type pos,
       typename bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>::size_type n,
       CHAR_TYPE zeroChar,
       CHAR_TYPE oneChar)
#else
template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
inline
bitset<N>::
bitset(const bsl::basic_string<CHAR_TYPE, TRAITS, ALLOCATOR>& str,
       bsl::string::size_type pos,
       bsl::string::size_type n,
       CHAR_TYPE              zeroChar,
       CHAR_TYPE              oneChar)
#endif
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(pos > str.size())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                                  "'pos > str.size()' for bitset constructor");
    }
    memset(d_data, 0, k_BITSETSIZE * k_BYTES_PER_INT);
    copyString(str, pos, n, zeroChar, oneChar);
}

// MANIPULATORS
template <std::size_t N>
bitset<N>& bitset<N>::operator&=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        d_data[i] &= rhs.d_data[i];
    }
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::operator|=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        d_data[i] |= rhs.d_data[i];
    }
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::operator^=(const bitset& rhs) BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        d_data[i] ^= rhs.d_data[i];
    }
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::operator<<=(std::size_t pos) BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT_SAFE(pos <= N);

    if (pos) {
        const std::size_t shift  = pos / k_BITS_PER_INT;
        const std::size_t offset = pos % k_BITS_PER_INT;

        if (shift) {
            memmove(d_data + shift,
                    d_data,
                    (k_BITSETSIZE - shift) * k_BYTES_PER_INT);
            memset(d_data, 0, shift * k_BYTES_PER_INT);
        }

        if (offset) {
            for (std::size_t i = k_BITSETSIZE - 1; i > shift; --i) {
                d_data[i] = (d_data[i] << offset)
                          | (d_data[i-1] >> (k_BITS_PER_INT - offset));
            }
            d_data[shift] <<= offset;
        }

        clearUnusedBits();
    }
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::operator>>=(std::size_t pos) BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT_SAFE(pos <= N);

    if (pos) {
        const std::size_t shift  = pos / k_BITS_PER_INT;
        const std::size_t offset = pos % k_BITS_PER_INT;

        if (shift) {
            memmove(d_data,
                    d_data + shift,
                    (k_BITSETSIZE - shift) * k_BYTES_PER_INT);
            memset(d_data + k_BITSETSIZE - shift, 0, shift * k_BYTES_PER_INT);
        }

        if (offset) {
            for (std::size_t i = 0; i < k_BITSETSIZE - shift - 1; ++i) {
                d_data[i] = (d_data[i] >> offset)
                          | (d_data[i+1] << (k_BITS_PER_INT - offset));
            }
            d_data[k_BITSETSIZE - shift - 1] >>= offset;
        }

        clearUnusedBits();
    }
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::flip() BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        d_data[i] = ~d_data[i];
    }
    clearUnusedBits();
    return *this;
}

template <std::size_t N>
inline
bitset<N>& bitset<N>::flip(std::size_t pos)
{
    BSLS_ASSERT_SAFE(pos < N);

    const std::size_t shift  = pos / k_BITS_PER_INT;
    const std::size_t offset = pos % k_BITS_PER_INT;
    d_data[shift] ^= (1 << offset);
    return *this;
}

template <std::size_t N>
inline
bitset<N>& bitset<N>::reset() BSLS_KEYWORD_NOEXCEPT
{
    memset(d_data, 0, k_BITSETSIZE * k_BYTES_PER_INT);
    return *this;
}

template <std::size_t N>
inline
bitset<N>& bitset<N>::reset(std::size_t pos)
{
    BSLS_ASSERT_SAFE(pos < N);

    const std::size_t shift  = pos / k_BITS_PER_INT;
    const std::size_t offset = pos % k_BITS_PER_INT;
    d_data[shift] &= ~(1 << offset);
    return *this;
}

template <std::size_t N>
inline
bitset<N>& bitset<N>::set() BSLS_KEYWORD_NOEXCEPT
{
    memset(d_data, 0xFF, k_BITSETSIZE * k_BYTES_PER_INT);
    clearUnusedBits();
    return *this;
}

template <std::size_t N>
bitset<N>& bitset<N>::set(std::size_t pos, int val)
{
    BSLS_ASSERT_SAFE(pos < N);

    const std::size_t shift  = pos / k_BITS_PER_INT;
    const std::size_t offset = pos % k_BITS_PER_INT;
    if (val) {
        d_data[shift] |= (1 << offset);
    }
    else {
        d_data[shift] &= ~(1 << offset);
    }
    return *this;
}

template <std::size_t N>
inline
typename bitset<N>::reference bitset<N>::operator[](std::size_t pos)
{
    BSLS_ASSERT_SAFE(pos < N);

    const std::size_t shift  = pos / k_BITS_PER_INT;
    const std::size_t offset = pos % k_BITS_PER_INT;
    return typename bitset<N>::reference(&d_data[shift],
                                         static_cast<unsigned int>(offset));
}

// ACCESSORS
template <std::size_t N>
inline
bitset<N> bitset<N>::operator<<(std::size_t pos) const BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT_SAFE(pos <= N);

    bitset<N> tmp(*this);
    return tmp <<= pos;
}

template <std::size_t N>
inline
bitset<N> bitset<N>::operator>>(std::size_t pos) const BSLS_KEYWORD_NOEXCEPT
{
    BSLS_ASSERT_SAFE(pos <= N);

    bitset<N> tmp(*this);
    return tmp >>= pos;
}

template <std::size_t N>
inline
bitset<N> bitset<N>::operator~() const BSLS_KEYWORD_NOEXCEPT
{
    bitset<N> tmp(*this);
    return tmp.flip();
}

template <std::size_t N>
inline BSLS_KEYWORD_CONSTEXPR
bool bitset<N>::operator[](std::size_t pos) const
{
#if defined(BSLSTL_BITSET_ALLOW_ASSERT_IN_CONSTEXPR)
    BSLS_ASSERT_SAFE(pos < N);
#endif

    return 0 != (d_data[pos / k_BITS_PER_INT] & (1 << (pos % k_BITS_PER_INT)));
}

template <std::size_t N>
inline
bool bitset<N>::operator==(const bitset& rhs) const BSLS_KEYWORD_NOEXCEPT
{
    return memcmp(d_data, rhs.d_data, k_BITSETSIZE * k_BYTES_PER_INT) == 0;
}

template <std::size_t N>
inline
bool bitset<N>::operator!=(const bitset& rhs) const BSLS_KEYWORD_NOEXCEPT
{
    return !operator==(rhs);
}

template <std::size_t N>
bool bitset<N>::all() const BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < N / k_BITS_PER_INT; ++i) {
        if (d_data[i] != ~0u) {
            return false;
        }
    }

    const std::size_t modulo = N % k_BITS_PER_INT;

    if (modulo) {
        const std::size_t mask = ((1u << modulo) - 1);
        return d_data[k_BITSETSIZE - 1] == mask;
    }

    return true;
}

template <std::size_t N>
bool bitset<N>::any() const BSLS_KEYWORD_NOEXCEPT
{
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        if (d_data[i] != 0) {
            return true;                                              // RETURN
        }
    }
    return false;
}

template <std::size_t N>
std::size_t bitset<N>::count() const BSLS_KEYWORD_NOEXCEPT
{
    std::size_t sum = 0;
    for (std::size_t i = 0; i < k_BITSETSIZE; ++i) {
        sum += numOneSet(d_data[i]);
    }
    return sum;
}

template <std::size_t N>
inline
bool bitset<N>::none() const BSLS_KEYWORD_NOEXCEPT
{
    return !any();
}

template <std::size_t N>
inline
BSLS_KEYWORD_CONSTEXPR std::size_t bitset<N>::size() const BSLS_KEYWORD_NOEXCEPT
{
    return N;
}

template <std::size_t N>
inline
bool bitset<N>::test(size_t pos) const
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(pos >= N)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        BloombergLP::bslstl::StdExceptUtil::throwOutOfRange(
                                        "out_of_range in bsl::bitset<>::test");
    }
    return operator[](pos);
}

template <std::size_t N>
template <class CHAR_TYPE, class TRAITS, class ALLOCATOR>
basic_string<CHAR_TYPE, TRAITS, ALLOCATOR> bitset<N>::to_string(
                                                           CHAR_TYPE zero,
                                                           CHAR_TYPE one) const
{
    basic_string<CHAR_TYPE, TRAITS, ALLOCATOR> str(N, zero);
    for (std::size_t i = 0; i < N; ++i) {
        if (this->operator[](i)) {
            str[N - i - 1] = one;
        }
    }
    return str;
}

template <std::size_t N>
unsigned long bitset<N>::to_ulong() const
{
    enum {
        k_INTS_IN_LONG = sizeof(unsigned long) / sizeof(int)
    };

    for (std::size_t i = k_INTS_IN_LONG; i < k_BITSETSIZE; ++i) {
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(d_data[i])) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            BloombergLP::bslstl::StdExceptUtil::throwOverflowError(
                                        "overflow in bsl::bitset<>::to_ulong");
        }
    }

    unsigned long      value   = 0;
    const unsigned int numInts = (unsigned int) k_INTS_IN_LONG
                                                  < (unsigned int) k_BITSETSIZE
                               ? (unsigned int) k_INTS_IN_LONG
                               : (unsigned int) k_BITSETSIZE;

    for (unsigned int i = 0; i < numInts; ++i) {
        value |= (unsigned long) d_data[i] << (k_BITS_PER_INT * i);
    }
    return value;
}

// FREE OPERATORS
template <std::size_t N>
bitset<N> operator&(const bitset<N>& lhs, const bitset<N>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    bitset<N> tmp(lhs);
    return tmp &= rhs;
}

template <std::size_t N>
bitset<N> operator|(const bitset<N>& lhs, const bitset<N>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    bitset<N> tmp(lhs);
    return tmp |= rhs;
}

template <std::size_t N>
bitset<N> operator^(const bitset<N>& lhs, const bitset<N>& rhs)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    bitset<N> tmp(lhs);
    return tmp ^= rhs;
}

template <class CHAR_TYPE, class TRAITS, std::size_t N>
std::basic_istream<CHAR_TYPE, TRAITS>&
operator>>(std::basic_istream<CHAR_TYPE, TRAITS>& is, bitset<N>& x)
{
    typedef typename TRAITS::int_type int_type;

    basic_string<CHAR_TYPE, TRAITS, allocator<CHAR_TYPE> > tmp;
    tmp.reserve(N);

    typename std::basic_istream<CHAR_TYPE, TRAITS>::sentry sen(is);
    if (sen) {
        std::basic_streambuf<CHAR_TYPE, TRAITS> *buffer = is.rdbuf();
        for (std::size_t i = 0; i < N; ++i) {
            static int_type eof = TRAITS::eof();
            int_type cint = buffer->sbumpc();
            if (TRAITS::eq_int_type(cint, eof)) {
                is.setstate(std::ios_base::eofbit);
                break;
            }
            else {
                CHAR_TYPE cchar = TRAITS::to_char_type(cint);
                char      c     = is.narrow(cchar, '*');

                if (c == '0' || c == '1') {
                    tmp.push_back(c);
                }
                else if (TRAITS::eq_int_type(buffer->sputbackc(cchar), eof)) {
                    is.setstate(std::ios_base::failbit);
                    break;
                }
            }
        }

        if (tmp.empty()) {
            is.setstate(std::ios_base::failbit);
        }
        else {
            x = bitset<N>(tmp);
        }
    }
    return is;
}

template <class CHAR_TYPE, class TRAITS, std::size_t N>
inline
std::basic_ostream<CHAR_TYPE, TRAITS>&
operator<<(std::basic_ostream<CHAR_TYPE, TRAITS>& os, const bitset<N>& x)
{
    basic_string<CHAR_TYPE, TRAITS, allocator<CHAR_TYPE> > tmp (
             x.template to_string<CHAR_TYPE, TRAITS, allocator<CHAR_TYPE> >());
    return os << tmp;
}

}  // close namespace bsl

#if defined(BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS)
# undef BSLSTL_BITSET_MSVC_CANNOT_PARSE_DEFAULTS_WITH_COLONS
#endif

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------