// bdlb_bitstringutil.h                                               -*-C++-*-
#ifndef INCLUDED_BDLB_BITSTRINGUTIL
#define INCLUDED_BDLB_BITSTRINGUTIL

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

//@PURPOSE: Provide efficient operations on a multi-word sequence of bits.
//
//@CLASSES:
// bdlb::BitStringUtil: namespace for common bit-manipulation procedures
//
//@SEE_ALSO: bdlb_bitutil, bdlb_bitmaskutil, bdlb_bitstringimputil,
//           bdlc_bitarray
//
//@DESCRIPTION: This component provides a utility 'struct',
// 'bdlb::BitStringUtil', that serves as a namespace for a collection of
// efficient, bit-level procedures on "bit strings", sequences of bits stored
// in arrays of 64-bit 'uint64_t' values.  A number of operations of various
// types are provided: bitwise-logical, copy, assignment, read, insert/remove,
// compare, find, count, and print operations are offered, among others.
//
///The "Bit String" Pseudo-Type
///----------------------------
// A contiguous sequence of bits that occupy a positive integral number of
// sequential 'uint64_t' values can be viewed as a string of bits.  This
// component supports operations on such sequences.  The notion of "bit
// string", a pseudo-type, is used to document those operations.
// Correspondingly, 'BitStringUtil' operations are categorized as either
// "manipulators", operations that modify bit strings; or "accessors",
// operations that return information and guarantee that no change to bit
// strings occurs.
//
// A bit string has two "structural" attributes:
//..
//  Capacity - The capacity, in bits, of a bit string is the number of
//             'uint64_t' values in the array multiplied by
//             'BitStringUtil::k_BITS_PER_UINT64'.  Note that the capacity of a
//             bit string is analogous to the capacity of a 'bsl::vector'.
//
//  Length   - The number of significant bits stored in the bit string.  The
//             length can never exceed the capacity, and the length is
//             analogous to the length of a 'bsl::vector'.
//..
// Since the bit string is a pseudo-type, there is no language support for
// managing these values; the user must do so explicitly.
//
// Many operations on a bit string refer to a "position" within a bit string,
// or a range of positions within a bit string:
//..
//  Position - The offset (in bits) of a bit value from the beginning of a
//             bit string (also called the "index" of a bit).
//..
// The notion of "position" used in this component is a generalization of the
// notion of a bit's position in a single integer value.
//
// Bits within a 64-bit 'uint64_t' (irrespective of the endian-ness of a
// platform) are here numbered, starting at 0, from the least-significant bit
// to the most-significant bit.  In illustrations, we typically show the
// high-order bits on the left:
//..
//   63 62  . . . . .   5  4  3  2  1  0
//  +-----------------------------------+
//  | 1| 0| . . . . . | 1| 1| 0| 0| 1| 0|
//  +-----------------------------------+
//..
// Thus, left-shifting (e.g., caused by 'insert'ing low-order bits) causes bits
// to move up in bit-position (to positions of higher significance) and
// right-shifting (e.g., caused by 'remove'ing low-order bits) causes bits to
// move into positions of less significance.
//
// This component extends this representation to an arbitrary sequence of bits
// represented using an array of 64-bit 'uint64_t' values.  For example, the
// bit string shown below is built on an array of three 'uint64_t' values.
// Thus, it has a capacity of 192 (i.e.,
// '3 * BitStringUtil::k_BITS_PER_UINT64').  Note that words are ordered
// right-to-left, so the lowest-order bits are to the right.  This is also how
// the 'bdlb::BitStringUtil::print' function orders the words it outputs:
//..
//  |<------ word 2 ------>|<------ word 1 ------>|<------ word 0 ------>|
//  | 191 190 . .  129 128 | 127 126 . . .  65 64 | 63 62 . . . . .  1 0 |
//  +----------------------+----------------------+----------------------+
//..
//
///Manipulator Functions
///---------------------
// Manipulator functions return 'void', and take the address of an integer as
// the first argument in order to modify it in place.
//..
//
//
//                                 Assignment
// +--------------------------------------------------------------------------+
// | assign     | Overloaded; assign 0 or more contiguous bits to a specified |
// |            | 'bool' value.                                               |
// +--------------------------------------------------------------------------+
// | assign0    | Overloaded; assign 0 or more contiguous bits to 'false'.    |
// +--------------------------------------------------------------------------+
// | assign1    | Overloaded; assign 0 or more contiguous bits to 'true'.     |
// +--------------------------------------------------------------------------+
// | assignBits | Assign up to one word of contiguous bits, taken from a      |
// |            | 'uint64_t' argument.                                        |
// +--------------------------------------------------------------------------+
//
//
//                                Bitwise-Logical
// +--------------------------------------------------------------------------+
// | andEqual   | Bitwise-AND ranges of equal length from two bit strings, a  |
// |            | 'dstBitString' and a 'srcBitString', writing the result     |
// |            | over the range from 'dstBitString'.                         |
// +--------------------------------------------------------------------------+
// | minusEqual | Bitwise-MINUS ranges of equal length from two bit strings,  |
// |            | a 'srcBitString' from a 'dstBitString', writing the result  |
// |            | over the range from 'dstBitString'.                         |
// +--------------------------------------------------------------------------+
// | orEqual    | Bitwise-OR ranges of equal length from two bit strings, a   |
// |            | 'dstBitString' and a 'srcBitString', writing the result     |
// |            | over the range from 'dstBitString'.                         |
// +--------------------------------------------------------------------------+
// | xorEqual   | Bitwise-XOR ranges of equal length from two bit strings, a  |
// |            | 'dstBitString' and a 'srcBitString', writing the result     |
// |            | over the range from 'dstBitString'.                         |
// +--------------------------------------------------------------------------+
//
//
//                                      Copy
// +--------------------------------------------------------------------------+
// | copyRaw | Copy a range from one bit string to another range, with some   |
// |         | restrictions on overlap between the two ranges.                |
// +--------------------------------------------------------------------------+
// | copy    | Copy a range from one bit string to another range, with no     |
// |         | restrictions on overlap between the two ranges.                |
// +--------------------------------------------------------------------------+
//
//
//                                 Insert / Remove
// +--------------------------------------------------------------------------+
// | insert    | Overloaded; insert 0 or more bits of a specified 'bool'      |
// |           | value.                                                       |
// +--------------------------------------------------------------------------+
// | insert0   | Overloaded; insert 0 or more 'false' bits.                   |
// +--------------------------------------------------------------------------+
// | insert1   | Overloaded; insert 0 or more 'true' bits.                    |
// +--------------------------------------------------------------------------+
// | insertRaw | Make room for additional bits in a bit string by moving all  |
// |           | bits above a given index up, leaving the values of the       |
// |           | newly-inserted bits undefined.                               |
// +--------------------------------------------------------------------------+
// | remove         | Remove 0 or more bits from a bit string.                |
// +--------------------------------------------------------------------------+
// | removeAndFill0 | Remove 0 or more bits from a bit string and assign      |
// |                | 'false' to vacated higher-order bits.                   |
// +--------------------------------------------------------------------------+
// | removeAndFill1 | Remove 0 or more bits from a bit string and assign      |
// |                | 'true' to vacated higher-order bits.                    |
// +--------------------------------------------------------------------------+
//
//
//                                Other Manipulators
// +--------------------------------------------------------------------------+
// | swapRaw | Swap two ranges of bit strings, which must not overlap.        |
// +--------------------------------------------------------------------------+
// | toggle  | Negate all the bits in a range of a bit string.                |
// +--------------------------------------------------------------------------+
//
//..
//
///Accessor Functions
///------------------
// Accessor function return a value but do not modify a bit string.
//..
//
//                                    Compare
// +--------------------------------------------------------------------------+
// | areEqual | Compare two ranges of bits for equality.                      |
// +--------------------------------------------------------------------------+
//
//
//                                     Read
// +--------------------------------------------------------------------------+
// | bit  | Return the boolean value of a single bit from a bit string.       |
// +--------------------------------------------------------------------------+
// | bits | Return a 'uint64_t' containing at most 'k_BITS_PER_UINT64'        |
// |      | adjacent bits from a bit string.                                  |
// +--------------------------------------------------------------------------+
//
//
//                                     Find
// +--------------------------------------------------------------------------+
// | find0AtMaxIndex | Locate the highest-order 0 bit in a range.             |
// +--------------------------------------------------------------------------+
// | find0AtMinIndex | Locate the lowest-order 0 bit in a range.              |
// +--------------------------------------------------------------------------+
// | find1AtMaxIndex | Locate the highest-order 1 bit in a range.             |
// +--------------------------------------------------------------------------+
// | find1AtMinIndex | Locate the lowest-order 1 bit in a range.              |
// +--------------------------------------------------------------------------+
//
//
//                                     Count
// +--------------------------------------------------------------------------+
// | isAny0 | Return 'true' if any bit in a range is 0, and 'false'           |
// |        | otherwise.                                                      |
// +--------------------------------------------------------------------------+
// | isAny1 | Return 'true' if any bit in a range is 1, and 'false'           |
// |        | otherwise.                                                      |
// +--------------------------------------------------------------------------+
// | num0   | Return the number of 0 bits in a range.                         |
// +--------------------------------------------------------------------------+
// | num1   | Return the number of 1 bits in a range.                         |
// +--------------------------------------------------------------------------+
//
//
//                                    Output
// +--------------------------------------------------------------------------+
// | print | Output a bit string in hex.                                      |
// +--------------------------------------------------------------------------+
//
//..
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Maintaining a Calendar of Business Days
/// - - - - - - - - - - - - - - - - - - - - - - - - -
// Bit strings can be used to represent business calendars and facilitate
// efficient operations on such calendars.  We will use bit strings to mark
// properties of days of the year 2013.
//
// First, create an enumeration showing the number of days in the year 2013
// before the beginning of each month, so that:
//..
// <constant for month> + <day of month> == <day of year>
//
//  enum {
//      JAN =        0,    // Note: First DOY is 'JAN + 1'.
//      FEB = JAN + 31,
//      MAR = FEB + 28,    // 2013 was not a leap year.
//      APR = MAR + 31,
//      MAY = APR + 30,
//      JUN = MAY + 31,
//      JUL = JUN + 30,
//      AUG = JUL + 31,
//      SEP = AUG + 31,
//      OCT = SEP + 30,
//      NOV = OCT + 31,
//      DEC = NOV + 30
//  };
//..
// Then, create a bit string with sufficient capacity to represent every day
// of a year (note that 64 * 6 = 384) and set a 1-bit in the indices
// corresponding to the day-of-year (DOY) for each weekend day.  For
// convenience in date calculations, the 0 index is not used; the 365 days of
// the year are at indices '[1 .. 365]'.  Further note that the values set
// below correspond to the year 2013:
//..
//  uint64_t weekends[6] = { 0 };
//
//  // We are marking only weekend days, so start with the first weekend day
//  // of the year: Saturday, January 5, 2013.
//
//  for (int i = 5; i < 366; i += 7) {
//      bdlb::BitStringUtil::assign(weekends, i,   1);
//      if (i + 1 < 366) {
//          bdlb::BitStringUtil::assign(weekends, i + 1, 1);
//      }
//  }
//..
// Next, we can easily use 'bdlb::BitStringUtil' methods to find days of
// interest.  For example, we can find the first and last weekend days of the
// year:
//..
//  const int firstWeekendDay = bdlb::BitStringUtil::find1AtMinIndex(weekends,
//                                                                   365 + 1);
//  const int lastWeekendDay  = bdlb::BitStringUtil::find1AtMaxIndex(weekends,
//                                                                   365 + 1);
//
//  assert(JAN +  5 == firstWeekendDay);
//  assert(DEC + 29 ==  lastWeekendDay);
//..
// Then, we define the following enumeration that allows us to easily represent
// the US holidays of the year:
//..
//  uint64_t holidays[6] = { 0 };
//
//  enum USHolidays2013 {
//      NEW_YEARS_DAY             = JAN +  1,
//      MARTIN_LUTHER_KING_JR_DAY = JAN + 21,
//      PRESIDENTS_DAY            = FEB + 18,
//      GOOD_FRIDAY               = MAR + 29,
//      MEMORIAL_DAY              = MAY + 27,
//      INDEPENDENCE_DAY          = JUL +  4,
//      LABOR_DAY                 = SEP +  2,
//      THANKSGIVING              = NOV + 28,
//      CHRISTMAS                 = DEC + 25
//  };
//
//  bdlb::BitStringUtil::assign(holidays, NEW_YEARS_DAY,             true);
//  bdlb::BitStringUtil::assign(holidays, MARTIN_LUTHER_KING_JR_DAY, true);
//  bdlb::BitStringUtil::assign(holidays, PRESIDENTS_DAY,            true);
//  bdlb::BitStringUtil::assign(holidays, GOOD_FRIDAY,               true);
//  bdlb::BitStringUtil::assign(holidays, MEMORIAL_DAY,              true);
//  bdlb::BitStringUtil::assign(holidays, INDEPENDENCE_DAY,          true);
//  bdlb::BitStringUtil::assign(holidays, LABOR_DAY,                 true);
//  bdlb::BitStringUtil::assign(holidays, THANKSGIVING,              true);
//  bdlb::BitStringUtil::assign(holidays, CHRISTMAS,                 true);
//..
// Next, the following enumeration indicates the beginning of fiscal quarters:
//..
//  enum {
//      Q1 = JAN + 1,
//      Q2 = APR + 1,
//      Q3 = JUN + 1,
//      Q4 = OCT + 1
//  };
//..
// Now, we can query our calendar for the first holiday in the third quarter,
// if any:
//..
//  const bsl::size_t firstHolidayOfQ3 = bdlb::BitStringUtil::find1AtMinIndex(
//                                                                    holidays,
//                                                                    Q3,
//                                                                    Q4);
//  assert(INDEPENDENCE_DAY == firstHolidayOfQ3);
//..
// Finally, our weekend and holiday calendars are readily combined to represent
// days off for either reason (i.e., holiday or weekend):
//..
//  uint64_t allDaysOff[6] = { 0 };
//  bdlb::BitStringUtil::orEqual(allDaysOff, 1, weekends, 1, 365);
//  bdlb::BitStringUtil::orEqual(allDaysOff, 1, holidays, 1, 365);
//
//  bool isOffMay24 = bdlb::BitStringUtil::bit(allDaysOff, MAY + 24);
//  bool isOffMay25 = bdlb::BitStringUtil::bit(allDaysOff, MAY + 25);
//  bool isOffMay26 = bdlb::BitStringUtil::bit(allDaysOff, MAY + 26);
//  bool isOffMay27 = bdlb::BitStringUtil::bit(allDaysOff, MAY + 27);
//  bool isOffMay28 = bdlb::BitStringUtil::bit(allDaysOff, MAY + 28);
//
//  assert(false == isOffMay24);
//  assert(true  == isOffMay25);    // Saturday
//  assert(true  == isOffMay26);    // Sunday
//  assert(true  == isOffMay27);    // Note May 27, 2013 is Memorial Day.
//  assert(false == isOffMay28);
//..

#include <bdlscm_version.h>

#include <bdlb_bitutil.h>

#include <bsls_assert.h>
#include <bsls_review.h>

#include <bsl_cstddef.h>
#include <bsl_cstdint.h>
#include <bsl_iosfwd.h>

namespace BloombergLP {
namespace bdlb {

                            // ====================
                            // struct BitStringUtil
                            // ====================

struct BitStringUtil {
    // This 'struct' provides a namespace for a suite of static functions to
    // manipulate and access sequences of bits stored in an array of 'uint64_t'
    // (also known as a "bit string"; see {The "Bit String" Pseudo-Type}).

    // PUBLIC TYPES
    enum { k_BITS_PER_UINT64 = 64 };  // number of bits in a 'uint64_t'

    // PUBLIC CLASS CONSTANTS
    static const bsl::size_t k_INVALID_INDEX = ~static_cast<bsl::size_t>(0);

    // CLASS METHODS

                                // Assign

    static void assign(bsl::uint64_t *bitString,
                       bsl::size_t    index,
                       bool           value);
        // Set the bit at the specified 'index' in the specified 'bitString' to
        // the specified 'value'.  The behavior is undefined unless 'index' is
        // less than the capacity of 'bitString'.

    static void assign(bsl::uint64_t *bitString,
                       bsl::size_t    index,
                       bool           value,
                       bsl::size_t    numBits);
        // Set the specified 'numBits' beginning at the specified 'index' in
        // the specified 'bitString' to the specified 'value'.  The behavior is
        // undefined unless 'bitString' has a capacity of at least
        // 'index + numBits'.

    static void assign0(bsl::uint64_t *bitString, bsl::size_t index);
        // Set the bit at the specified 'index' in the specified 'bitString' to
        // 'false'.  The behavior is undefined unless 'index' is less than the
        // capacity of 'bitString'.

    static void assign0(bsl::uint64_t *bitString,
                        bsl::size_t    index,
                        bsl::size_t    numBits);
        // Set the specified 'numBits' beginning at the specified 'index' in
        // the specified 'bitString' to 'false'.  The behavior is undefined
        // unless 'bitString' has a capacity of at least 'index + numBits'.

    static void assign1(bsl::uint64_t *bitString, bsl::size_t index);
        // Set the bit at the specified 'index' in the specified 'bitString' to
        // 'true'.  The behavior is undefined unless 'index' is less than the
        // capacity of 'bitString'.

    static void assign1(bsl::uint64_t *bitString,
                        bsl::size_t    index,
                        bsl::size_t    numBits);
        // Set the specified 'numBits' beginning at the specified 'index' in
        // the specified 'bitString' to 'true'.  The behavior is undefined
        // unless 'bitString' has a capacity of at least 'index + numBits'.

    static void assignBits(bsl::uint64_t *bitString,
                           bsl::size_t    index,
                           bsl::uint64_t  srcValue,
                           bsl::size_t    numBits);
        // Assign the low-order specified 'numBits' from the specified
        // 'srcValue' to the 'numBits' starting at the specified 'index' in the
        // specified 'bitString'.  The behavior is undefined unless
        // 'numBits <= k_BITS_PER_UINT64' and 'bitString' has a capacity of at
        // least 'index + numBits'.

                                // Bitwise-Logical

    static void andEqual(bsl::uint64_t       *dstBitString,
                         bsl::size_t          dstIndex,
                         const bsl::uint64_t *srcBitString,
                         bsl::size_t          srcIndex,
                         bsl::size_t          numBits);
        // Bitwise AND the specified 'numBits' of the specified 'dstBitString'
        // starting at the specified 'dstIndex' with the 'numBits' of the
        // specified 'srcBitString' starting at the specified 'srcIndex', and
        // write the result over the bits that were read from 'dstBitString'.
        // The behavior is undefined unless 'dstBitString' has a length of at
        // least 'dstIndex + numBits' and 'srcBitString' has a length of at
        // least 'srcIndex + numBits'.

    static void minusEqual(bsl::uint64_t       *dstBitString,
                           bsl::size_t          dstIndex,
                           const bsl::uint64_t *srcBitString,
                           bsl::size_t          srcIndex,
                           bsl::size_t          numBits);
        // Bitwise MINUS the specified 'numBits' of the specified
        // 'srcBitString' starting at the specified 'srcIndex' from the
        // 'numBits' of the specified 'dstBitString' starting at the specified
        // 'dstIndex', and write the result over the bits that were read from
        // 'dstBitString'.  The behavior is undefined unless 'dstBitString' has
        // a length of at least 'dstIndex + numBits' and 'srcBitString' has a
        // length of at least 'srcIndex + numBits'.  Note that the logical
        // difference 'A - B' is defined to be 'A & !B'.

    static void orEqual(bsl::uint64_t       *dstBitString,
                        bsl::size_t          dstIndex,
                        const bsl::uint64_t *srcBitString,
                        bsl::size_t          srcIndex,
                        bsl::size_t          numBits);
        // Bitwise OR the specified 'numBits' of the specified 'dstBitString'
        // starting at the specified 'dstIndex' with the 'numBits' of the
        // specified 'srcBitString' starting at the specified 'srcIndex', and
        // write the result over the bits that were read from 'dstBitString'.
        // The behavior is undefined unless 'dstBitString' has a length of at
        // least 'dstIndex + numBits' and 'srcBitString' has a length of at
        // least 'srcIndex + numBits'.

    static void xorEqual(bsl::uint64_t       *dstBitString,
                         bsl::size_t          dstIndex,
                         const bsl::uint64_t *srcBitString,
                         bsl::size_t          srcIndex,
                         bsl::size_t          numBits);
        // Bitwise XOR the specified 'numBits' of the specified 'dstBitString'
        // starting at the specified 'dstIndex' with the 'numBits' of the
        // specified 'srcBitString' starting at the specified 'srcIndex', and
        // write the result over the bits that were read from 'dstBitString'.
        // The behavior is undefined unless 'dstBitString' has a length of at
        // least 'dstIndex + numBits' and 'srcBitString' has a length of at
        // least 'srcIndex + numBits'.

                                // Copy

    static void copy(bsl::uint64_t       *dstBitString,
                     bsl::size_t          dstIndex,
                     const bsl::uint64_t *srcBitString,
                     bsl::size_t          srcIndex,
                     bsl::size_t          numBits);
        // Copy to the specified 'dstBitString', beginning at the specified
        // 'dstIndex', the specified 'numBits' beginning at the specified
        // 'srcIndex' in the specified 'srcBitString'.  This function works
        // correctly regardless of whether the source and destination ranges
        // overlap.  The behavior is undefined unless 'dstBitString' has a
        // capacity of at least 'dstIndex + numBits' and 'srcBitString' has a
        // length of at least 'srcIndex + numBits'.

    static void copyRaw(bsl::uint64_t       *dstBitString,
                        bsl::size_t          dstIndex,
                        const bsl::uint64_t *srcBitString,
                        bsl::size_t          srcIndex,
                        bsl::size_t          numBits);
        // Copy to the specified 'dstBitString', beginning at the specified
        // 'dstIndex', the specified 'numBits' beginning at the specified
        // 'srcIndex' in the specified 'srcBitString'.  The behavior is
        // undefined unless 'dstBitString' has a capacity of at least
        // 'dstIndex + numBits', 'srcBitString' has a length of at least
        // 'srcIndex + numBits', and the source and destination ranges either
        // do not overlap, or the destination range is equal to the source
        // range, or the start of the destination range is below the start of
        // the source range.

                                // Insert / Remove

    static void insert(bsl::uint64_t *bitString,
                       bsl::size_t    initialLength,
                       bsl::size_t    dstIndex,
                       bool           value,
                       bsl::size_t    numBits);
        // Insert the specified 'numBits', each having the specified 'value',
        // into the specified 'bitString' having the specified 'initialLength',
        // beginning at the specified 'dstIndex'.  Bits at or above 'dstIndex'
        // are shifted up by 'numBits' index positions and the length of
        // 'bitString' is increased by 'numBits'.  The behavior is undefined
        // unless 'dstIndex <= initialLength' and 'bitString' has a capacity of
        // at least 'initialLength + numBits'.

    static void insert0(bsl::uint64_t *bitString,
                        bsl::size_t    initialLength,
                        bsl::size_t    dstIndex,
                        bsl::size_t    numBits);
        // Insert the specified 'numBits' 0 bits into the specified 'bitString'
        // having the specified 'initialLength' beginning at the specified
        // 'dstIndex'.  Bits at or above 'dstIndex' are shifted up by 'numBits'
        // index positions and the length of 'bitString' is increased by
        // 'numBits'.  The behavior is undefined unless
        // 'dstIndex <= initialLength' and 'bitString' has a capacity of at
        // least 'initialLength + numBits'.

    static void insert1(bsl::uint64_t *bitString,
                        bsl::size_t    initialLength,
                        bsl::size_t    dstIndex,
                        bsl::size_t    numBits);
        // Insert the specified 'numBits' 1 bits into the specified 'bitString'
        // having the specified 'initialLength' beginning at the specified
        // 'dstIndex'.  Bits at or above 'dstIndex' are shifted up by 'numBits'
        // index positions and the length of 'bitString' is increased by
        // 'numBits'.  The behavior is undefined unless
        // 'dstIndex <= initialLength' and 'bitString' has a capacity of at
        // least 'initialLength + numBits'.

    static void insertRaw(bsl::uint64_t *bitString,
                          bsl::size_t    initialLength,
                          bsl::size_t    dstIndex,
                          bsl::size_t    numBits);
        // Insert the specified 'numBits' into the specified 'bitString' having
        // the specified 'initialLength' beginning at the specified 'dstIndex'.
        // Bits at or above 'dstIndex' are shifted up by 'numBits' index
        // positions and the length of 'bitString' is increased by 'numBits'.
        // The values of the inserted bits are undefined.  The behavior is
        // undefined unless 'dstIndex <= initialLength' and 'bitString' has a
        // capacity of at least 'initialLength + numBits'.  Note that the
        // inserted bits are not assigned any value.

    static void remove(bsl::uint64_t *bitString,
                       bsl::size_t    length,
                       bsl::size_t    index,
                       bsl::size_t    numBits);
        // Remove the specified 'numBits' from the specified 'bitString' of the
        // specified 'length' beginning at the specified 'index'.  Bits above
        // 'index + numBits' are shifted down by 'numBits' index positions and
        // the length of 'bitString' is reduced by 'numBits'.  The values of
        // the vacated high-order bits are not modified.  The behavior is
        // undefined unless 'index + numBits <= length'.

    static void removeAndFill0(bsl::uint64_t *bitString,
                               bsl::size_t    length,
                               bsl::size_t    index,
                               bsl::size_t    numBits);
        // Remove the specified 'numBits' from the specified 'bitString' having
        // the specified 'length' beginning at the specified 'index'.  Bits
        // above 'index + numBits' are shifted down by 'numBits' index
        // positions and the last 'numBits' of 'bitString' are set to 0.  The
        // length of 'bitString' is not changed.  The behavior is undefined
        // unless 'index + numBits <= length'.

    static void removeAndFill1(bsl::uint64_t *bitString,
                               bsl::size_t    length,
                               bsl::size_t    index,
                               bsl::size_t    numBits);
        // Remove the specified 'numBits' from the specified 'bitString' having
        // the specified 'length' beginning at the specified 'index'.  Bits
        // above 'index + numBits' are shifted down by 'numBits' index
        // positions and the last 'numBits' of 'bitString' are set to 1.  The
        // length of 'bitString' is not changed.  The behavior is undefined
        // unless 'index + numBits <= length'.

                                // Other Manipulators

    static void swapRaw(bsl::uint64_t *bitString1,
                        bsl::size_t    index1,
                        bsl::uint64_t *bitString2,
                        bsl::size_t    index2,
                        bsl::size_t    numBits);
        // Exchange the specified 'numBits' beginning at the specified 'index1'
        // in the specified 'bitString1' with the 'numBits' beginning at the
        // specified 'index2' in the specified 'bitString2'.  The behavior is
        // undefined unless 'bitString1' has a length of at least
        // 'index1 + numBits', 'bitString2' has a length of at least
        // 'index2 + numBits', and there is *no* overlap between the swapped
        // ranges of bits.

    static void toggle(bsl::uint64_t *bitString,
                       bsl::size_t    index,
                       bsl::size_t    numBits);
        // Invert the values of the specified 'numBits' in the specified
        // 'bitString' beginning at the specified 'index'.  The behavior is
        // undefined unless 'bitString' has a length of at least
        // 'index + numBits'.

                                // Compare

    static bool areEqual(const bsl::uint64_t *bitString1,
                         const bsl::uint64_t *bitString2,
                         bsl::size_t          numBits);
        // Return 'true' if the specified low-order 'numBits' in the specified
        // 'bitString1' are bitwise equal to the corresponding bits in the
        // specified 'bitString2', and 'false' otherwise.  The behavior is
        // undefined unless both 'bitString1' and 'bitString2' have a length of
        // at least 'numBits'.

    static bool areEqual(const bsl::uint64_t *bitString1,
                         bsl::size_t          index1,
                         const bsl::uint64_t *bitString2,
                         bsl::size_t          index2,
                         bsl::size_t          numBits);
        // Return 'true' if the specified 'numBits' beginning at the specified
        // 'index1' in the specified 'bitString1' are bitwise equal to the
        // 'numBits' beginning at the specified 'index2' in the specified
        // 'bitString2', and 'false' otherwise.  The behavior is undefined
        // unless 'bitString1' has a length of at least 'index1 + numBits' and
        // 'bitString2' has a length of at least 'index2 + numBits'.

                                // Read

    static bool bit(const bsl::uint64_t *bitString, bsl::size_t index);
        // Return the bit value at the specified 'index' in the specified
        // 'bitString'.  The behavior is undefined unless 'index' is less than
        // the length of 'bitString'.

    static bsl::uint64_t bits(const bsl::uint64_t *bitString,
                              bsl::size_t          index,
                              bsl::size_t          numBits);
        // Return the specified 'numBits' beginning at the specified 'index' in
        // the specified 'bitString' as the low-order bits of the returned
        // value.  The behavior is undefined unless
        // 'numBits <= k_BITS_PER_UINT64' and 'bitString' has a length of at
        // least 'index + numBits'.

                                // Find

    static bsl::size_t find0AtMaxIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          length);
        // Return the index of the most-significant 0 bit in the specified
        // 'bitString' having the specified 'length', if such a bit exists, and
        // 'k_INVALID_INDEX' otherwise.

    static bsl::size_t find0AtMaxIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          begin,
                                       bsl::size_t          end);
        // Return the index of the most-significant 0 bit in the specified
        // 'bitString' in the specified range '[begin .. end)', if such a bit
        // exists, and 'k_INVALID_INDEX' otherwise.  The behavior is undefined
        // unless 'begin <= end' and 'end' is less than or equal to the length
        // of 'bitString'.

    static bsl::size_t find0AtMinIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          length);
        // Return the index of the least-significant 0 bit in the specified
        // 'bitString' having the specified 'length', if such a bit exists, and
        // 'k_INVALID_INDEX' otherwise.

    static bsl::size_t find0AtMinIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          begin,
                                       bsl::size_t          end);
        // Return the index of the least-significant 0 bit in the specified
        // 'bitString' in the specified range '[begin .. end)', if such a bit
        // exists, and 'k_INVALID_INDEX' otherwise.  The behavior is undefined
        // unless 'begin <= end' and 'end' is less than or equal to the length
        // of 'bitString'.

    static bsl::size_t find1AtMaxIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          length);
        // Return the index of the most-significant 1 bit in the specified
        // 'bitString' having the specified 'length', if such a bit exists, and
        // 'k_INVALID_INDEX' otherwise.

    static bsl::size_t find1AtMaxIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          begin,
                                       bsl::size_t          end);
        // Return the index of the most-significant 1 bit in the specified
        // 'bitString' in the specified range '[begin .. end)', if such a bit
        // exists, and 'k_INVALID_INDEX' otherwise.  The behavior is undefined
        // unless 'begin <= end' and 'end' is less than or equal to the length
        // of 'bitString'.

    static bsl::size_t find1AtMinIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          length);
        // Return the index of the least-significant 1 bit in the specified
        // 'bitString' having the specified 'length', if such a bit exists, and
        // 'k_INVALID_INDEX' otherwise.

    static bsl::size_t find1AtMinIndex(const bsl::uint64_t *bitString,
                                       bsl::size_t          begin,
                                       bsl::size_t          end);
        // Return the index of the least-significant 1 bit in the specified
        // 'bitString' in the specified range '[begin .. end)', if such a bit
        // exists, and 'k_INVALID_INDEX' otherwise.  The behavior is undefined
        // unless 'begin <= end' and 'end' is less than or equal to the length
        // of 'bitString'.

                                // Count

    static bool isAny0(const bsl::uint64_t *bitString,
                       bsl::size_t          index,
                       bsl::size_t          numBits);
        // Return 'true' if any of the specified 'numBits' beginning at the
        // specified 'index' in the specified 'bitString' are 0, and 'false'
        // otherwise.  The behavior is undefined unless 'bitString' has a
        // length of at least 'index + numBits'.

    static bool isAny1(const bsl::uint64_t *bitString,
                       bsl::size_t          index,
                       bsl::size_t          numBits);
        // Return 'true' if any of the specified 'numBits' beginning at the
        // specified 'index' in the specified 'bitString' are 1, and 'false'
        // otherwise.  The behavior is undefined unless 'bitString' has a
        // length of at least 'index + numBits'.

    static bsl::size_t num0(const bsl::uint64_t *bitString,
                            bsl::size_t          index,
                            bsl::size_t          numBits);
        // Return the number of 0 bits in the specified 'numBits' beginning at
        // the specified 'index' in the specified 'bitString'.  The behavior is
        // undefined unless 'bitString' has a length of at least
        // 'index + numBits'.

    static bsl::size_t num1(const bsl::uint64_t *bitString,
                            bsl::size_t          index,
                            bsl::size_t          numBits);
        // Return the number of 1 bits in the specified 'numBits' beginning at
        // the specified 'index' in the specified 'bitString'.  The behavior is
        // undefined unless 'bitString' has a length of at least
        // 'index + numBits'.

                                // Printing

    static bsl::ostream& print(bsl::ostream&        stream,
                               const bsl::uint64_t *bitString,
                               bsl::size_t          numBits,
                               int                  level          = 1,
                               int                  spacesPerLevel = 4);
        // Format to the specified output 'stream' the specified low-order
        // 'numBits' in the specified 'bitString' in hexadecimal, and return a
        // reference to 'stream'.  The highest order bits are printed first, in
        // groups of 16 nibbles, 64 nibbles per line (in the case of multi-line
        // output).  Optionally specify 'level', the indentation level for each
        // line output.  Optionally specify 'spacesPerLevel', the number of
        // spaces per indentation level.  Each line is indented by the absolute
        // value of 'level * spacesPerLevel'.  If 'spacesPerLevel' is negative,
        // suppress line breaks and format the entire output on one line.  If
        // 'stream' is initially invalid, this operation has no effect.  Note
        // that a trailing newline is provided in multiline mode only.
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                            // --------------------
                            // struct BitStringUtil
                            // --------------------

// CLASS METHODS

                            // Manipulators

                                // Assign

inline
void BitStringUtil::assign(bsl::uint64_t *bitString,
                           bsl::size_t    index,
                           bool           value)
{
    BSLS_ASSERT(bitString);

    const bsl::size_t idx =                       index  / k_BITS_PER_UINT64;
    const int         pos = static_cast<unsigned>(index) % k_BITS_PER_UINT64;

    if (value) {
        bitString[idx] |=  (1ULL << pos);
    }
    else {
        bitString[idx] &= ~(1ULL << pos);
    }
}

inline
void BitStringUtil::assign0(bsl::uint64_t *bitString, bsl::size_t index)
{
    BSLS_ASSERT(bitString);

    const bsl::size_t idx =                       index  / k_BITS_PER_UINT64;
    const int         pos = static_cast<unsigned>(index) % k_BITS_PER_UINT64;

    bitString[idx] &= ~(1ULL << pos);
}

inline
void BitStringUtil::assign1(bsl::uint64_t *bitString, bsl::size_t index)
{
    BSLS_ASSERT(bitString);

    const bsl::size_t idx =                       index  / k_BITS_PER_UINT64;
    const int         pos = static_cast<unsigned>(index) % k_BITS_PER_UINT64;

    bitString[idx] |= 1ULL << pos;
}

                                // Insert / Remove

inline
void BitStringUtil::insert(bsl::uint64_t *bitString,
                           bsl::size_t    initialLength,
                           bsl::size_t    dstIndex,
                           bool           value,
                           bsl::size_t    numBits)
{
    BSLS_ASSERT(bitString);

    insertRaw(bitString, initialLength, dstIndex, numBits);
    assign(bitString, dstIndex, value, numBits);
}

inline
void BitStringUtil::insert0(bsl::uint64_t *bitString,
                            bsl::size_t    initialLength,
                            bsl::size_t    dstIndex,
                            bsl::size_t    numBits)
{
    BSLS_ASSERT(bitString);

    insertRaw(bitString, initialLength, dstIndex, numBits);
    assign0(bitString, dstIndex, numBits);
}

inline
void BitStringUtil::insert1(bsl::uint64_t *bitString,
                            bsl::size_t    initialLength,
                            bsl::size_t    dstIndex,
                            bsl::size_t    numBits)
{
    BSLS_ASSERT(bitString);

    insertRaw(bitString, initialLength, dstIndex, numBits);
    assign1(bitString, dstIndex, numBits);
}

inline
void BitStringUtil::removeAndFill0(bsl::uint64_t *bitString,
                                   bsl::size_t    length,
                                   bsl::size_t    index,
                                   bsl::size_t    numBits)
{
    BSLS_ASSERT(bitString);

    remove(bitString, length, index, numBits);
    assign0(bitString, length - numBits, numBits);
}

inline
void BitStringUtil::removeAndFill1(bsl::uint64_t *bitString,
                                   bsl::size_t    length,
                                   bsl::size_t    index,
                                   bsl::size_t    numBits)
{
    BSLS_ASSERT(bitString);

    remove(bitString, length, index, numBits);
    assign1(bitString, length - numBits, numBits);
}

                                // Accessors

                                // Read
inline
bool BitStringUtil::bit(const bsl::uint64_t *bitString, bsl::size_t index)
{
    BSLS_ASSERT(bitString);

    const bsl::size_t idx =                       index  / k_BITS_PER_UINT64;
    const int         pos = static_cast<unsigned>(index) % k_BITS_PER_UINT64;

    return bitString[idx] & (1ULL << pos);
}

                                // Count

inline
bsl::size_t BitStringUtil::num0(const bsl::uint64_t *bitString,
                                bsl::size_t          index,
                                bsl::size_t          numBits)
{
    BSLS_ASSERT(bitString);

    return numBits - num1(bitString, index, numBits);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 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 ----------------------------------