// bdlc_bitarray.h -*-C++-*- #ifndef INCLUDED_BDLC_BITARRAY #define INCLUDED_BDLC_BITARRAY #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a space-efficient, sequential container of boolean values. // //@CLASSES: // bdlc::BitArray: vector-like, sequential container of boolean values // //@DESCRIPTION: This component implements 'bdlc::BitArray', an efficient // value-semantic, sequential container of boolean values (i.e., 0 or 1) of // type 'bool'. A 'BitArray' may be thought of as an arbitrary-precision // 'unsigned int'. This metaphor is used to motivate the rich set of "bitwise" // operations on 'BitArray' objects provided by this component, as well as the // notion of "zero extension" of a (shorter) bit array during binary operations // on bit arrays having lengths that are not the same. // ///Bit-Array-Specific Functionality ///-------------------------------- // In addition to many typical vector-like container methods, this component // supports "boolean" functionality unique to 'BitArray'. However, unlike // other standard container types such as 'bsl::bitset', there is no // 'operator[](bsl::size_t index)' that returns a reference to a (modifiable) // boolean element at the specified index position. This difference is due to // the densely-packed internal representation of bits within bit arrays: //.. // bdlc::BitArray mA(128); // assert(0 == mA[13]); // Ok // mA[13] = 'false'; // Error -- 'mA[13]' is not an lvalue. // mA.assign(13, 1); // Ok // // const bdlc::BitArray& A = mA; // Ok // assert(1 == A[13]); // Ok // const bool *bp = &A[13] // Error -- 'A[13]' is not an lvalue. // const bool bit = A[13]; // Ok //.. // Also note that there is no 'data' method returning a contiguous sequence of // 'bool'. // // Finally note that, wherever an argument of non-boolean type -- e.g., the // literal '5' (of type 'int') -- is used in a 'BitArray' method to specify a // boolean (bit) value, every non-zero value is automatically converted (via a // standard conversion) to a 'bool' value 'true', before the method of the // 'BitArray' is invoked: //.. // bdlc::BitArray a(10); // assert(0 == a[5]); // a.assign(5, 24); // Ok -- non-boolean value converted to 'true'. // assert(1 == a[5]); //.. // ///Performance and Exception-Safety Guarantees ///------------------------------------------- // The asymptotic worst-case performance of representative operations is // characterized using big-O notation, 'O[f(N,M)]', where 'N' and 'M' refer to // the number of respective bits (i.e., 'length') of arrays 'X' and 'Y', // respectively. Here, *Amortized* *Case* complexity, denoted by 'A[f(N)]', is // defined as the average of 'N' successive invocations, as 'N' gets very // large. //.. // Average Exception-Safety // Operation Worst Case Case Guarantee // --------- ---------- ------- ---------------- // DEFAULT CTOR O[1] No-Throw // COPY CTOR(Y) O[M] Exception Safe // // X.DTOR() O[1] No-Throw // // X.OP=(Y) O[M] Basic <*> // X.insert(index, value) O[N] Basic <*> // // X.reserveCapacity(M) O[N] Strong <*> // X.append(value) O[N] A[1] Strong <*> // // X.assign(index, value) O[1] No-Throw // X.assign1(value) O[1] No-Throw // X.assign0(value) O[1] No-Throw // // X.remove(index) O[N] No-Throw // X.assignAll0() O[N] No-Throw // X.assignAll1() O[N] No-Throw // // X.length() O[1] No-Throw // X.OP[](index) O[1] No-Throw // // X.isAny1 O[N] No-Throw // X.isAny0 O[N] No-Throw // // other 'const' methods O[1] .. O[N] No-Throw // // OP==(X, Y) O[min(N, M)] No-Throw // OP!=(X, Y) O[min(N, M)] No-Throw // // <*> No-Throw guarantee when capacity is sufficient. //.. // Note that *all* of the non-creator methods of 'BitArray' provide the // *No-Throw* guarantee whenever sufficient capacity is already available. // ///Usage ///----- // This section illustrates the intended use of this component. // ///Example 1: Creating a 'NullableVector' Class /// - - - - - - - - - - - - - - - - - - - - - - // An efficient implementation of an arbitrary precision bit sequence container // has myriad applications. For example, a 'bdlc::BitArray' can be used // effectively as a parallel array of flags indicating some special property, // such as 'isNull', 'isBusinessDay', etc.; its use is especially indicated // when (1) the number of elements of the primary array can grow large, and (2) // the individual elements do not have the capacity or capability to store the // information directly. // // As a simple example, we'll implement a (heavily elided) value-semantic // template class, 'NullableVector<TYPE>', that behaves like a // 'bsl::vector<TYPE>' but additionally allows storing a nullness flag to // signify that the corresponding element was not specified. Elements added to // a 'NullableVector' are null by default, although there are manipulator // functions that allow appending a non-null element. Each null element // stores the default value for 'TYPE'. // // Note that this class has a minimal interface (suitable for illustration // purpose only) that allows users to either append a (non-null) 'TYPE' value // or a null value. A real 'NullableVector' class would support a complete set // of *value* *semantic* operations, including copy construction, assignment, // equality comparison, 'ostream' printing, and BDEX serialization. Also note // that, for simplicity, exception-neutrality is ignored (some methods are // clearly not exception-neutral). // // First, we define the interface of 'NullableVector': //.. // template <class TYPE> // class NullableVector { // // This class implements a sequential container of elements of the // // template parameter 'TYPE'. // // // DATA // bsl::vector<TYPE> d_values; // data elements // bdlc::BitArray d_nullFlags; // 'true' indicates i'th element is // // null // // private: // // NOT IMPLEMENTED // NullableVector(const NullableVector&); // NullableVector& operator=(const NullableVector&); // // public: // // TRAITS // BSLMF_NESTED_TRAIT_DECLARATION(NullableVector, // bslma::UsesBslmaAllocator); // // public: // // CREATORS // explicit // NullableVector(bsl::size_t initialLength, // bslma::Allocator *basicAllocator = 0); // // Construct a vector having the specified 'initialLength' null // // elements. Optionally specify a 'basicAllocator' used to supply // // memory. If 'basicAllocator' is 0, the currently supplied // // default allocator is used. // // // ... // // ~NullableVector(); // // Destroy this vector. // // // MANIPULATORS // void appendNullElement(); // // Append a null element to this vector. Note that the appended // // element will have the same value as a default constructed 'TYPE' // // object. // // void appendElement(const TYPE& value); // // Append an element having the specified 'value' to the end of // // this vector. // // void makeNonNull(bsl::size_t index); // // Make the element at the specified 'index' in this vector // // non-null. The behavior is undefined unless 'index < length()'. // // void makeNull(bsl::size_t index); // // Make the element at the specified 'index' in this vector null. // // The behavior is undefined unless 'index < length()'. Note that // // the new value of the element will be the default constructed // // value for 'TYPE'. // // TYPE& modifiableElement(bsl::size_t index); // // Return a reference providing modifiable access to the (valid) // // element at the specified 'index' in this vector. The behavior // // is undefined unless 'index < length()'. Note that if the // // element at 'index' is null then the nullness flag is reset and // // the returned value is the default constructed value for 'TYPE'. // // void removeElement(bsl::size_t index); // // Remove the element at the specified 'index' in this vector. The // // behavior is undefined unless 'index < length()'. // // // ACCESSORS // const TYPE& constElement(bsl::size_t index) const; // // Return a reference providing non-modifiable access to the // // element at the specified 'index' in this vector. The behavior // // is undefined unless 'index < length()'. Note that if the // // element at 'index' is null then the nullness flag is not reset // // and the returned value is the default constructed value for // // 'TYPE'. // // bool isAnyElementNonNull() const; // // Return 'true' if any element in this vector is non-null, and // // 'false' otherwise. // // bool isAnyElementNull() const; // // Return 'true' if any element in this vector is null, and 'false' // // otherwise. // // bool isElementNull(bsl::size_t index) const; // // Return 'true' if the element at the specified 'index' in this // // vector is null, and 'false' otherwise. The behavior is // // undefined unless 'index < length()'. // // bsl::size_t length() const; // // Return the number of elements in this vector. // // bsl::size_t numNullElements() const; // // Return the number of null elements in this vector. // }; //.. // Then, we implement, in turn, each of the methods declared above: //.. // // -------------------- // // class NullableVector // // -------------------- // // // CREATORS // template <class TYPE> // NullableVector<TYPE>::NullableVector(bsl::size_t initialLength, // bslma::Allocator *basicAllocator) // : d_values(initialLength, TYPE(), basicAllocator) // , d_nullFlags(initialLength, true, basicAllocator) // { // } // // template <class TYPE> // NullableVector<TYPE>::~NullableVector() // { // BSLS_ASSERT(d_values.size() == d_nullFlags.length()); // } // // // MANIPULATORS // template <class TYPE> // inline // void NullableVector<TYPE>::appendElement(const TYPE& value) // { // d_values.push_back(value); // d_nullFlags.append(false); // } // // template <class TYPE> // inline // void NullableVector<TYPE>::appendNullElement() // { // d_values.push_back(TYPE()); // d_nullFlags.append(true); // } // // template <class TYPE> // inline // void NullableVector<TYPE>::makeNonNull(bsl::size_t index) // { // BSLS_ASSERT_SAFE(index < length()); // // d_nullFlags.assign(index, false); // } // // template <class TYPE> // inline // void NullableVector<TYPE>::makeNull(bsl::size_t index) // { // BSLS_ASSERT_SAFE(index < length()); // // d_values[index] = TYPE(); // d_nullFlags.assign(index, true); // } // // template <class TYPE> // inline // TYPE& NullableVector<TYPE>::modifiableElement(bsl::size_t index) // { // BSLS_ASSERT_SAFE(index < length()); // // d_nullFlags.assign(index, false); // return d_values[index]; // } // // template <class TYPE> // inline // void NullableVector<TYPE>::removeElement(bsl::size_t index) // { // BSLS_ASSERT_SAFE(index < length()); // // d_values.erase(d_values.begin() + index); // d_nullFlags.remove(index); // } // // // ACCESSORS // template <class TYPE> // inline // const TYPE& NullableVector<TYPE>::constElement(bsl::size_t index) const // { // BSLS_ASSERT_SAFE(index < length()); // // return d_values[index]; // } // // template <class TYPE> // inline // bool NullableVector<TYPE>::isAnyElementNonNull() const // { // return d_nullFlags.isAny0(); // } // // template <class TYPE> // inline // bool NullableVector<TYPE>::isAnyElementNull() const // { // return d_nullFlags.isAny1(); // } // // template <class TYPE> // inline // bool NullableVector<TYPE>::isElementNull(bsl::size_t index) const // { // BSLS_ASSERT_SAFE(index < length()); // // return d_nullFlags[index]; // } // // template <class TYPE> // inline // bsl::size_t NullableVector<TYPE>::length() const // { // return d_values.size(); // } // // template <class TYPE> // inline // bsl::size_t NullableVector<TYPE>::numNullElements() const // { // return d_nullFlags.num1(); // } //.. // Next, we create an empty 'NullableVector': //.. // NullableVector<int> array(0); // const NullableVector<int>& ARRAY = array; // const int DEFAULT_INT = 0; // // assert(0 == ARRAY.length()); // assert(0 == ARRAY.numNullElements()); // assert(false == ARRAY.isAnyElementNonNull()); // assert(false == ARRAY.isAnyElementNull()); //.. // Then, we append a non-null element to it: //.. // array.appendElement(5); // assert(1 == ARRAY.length()); // assert(5 == ARRAY.constElement(0)); // assert(false == ARRAY.isElementNull(0)); // assert(0 == ARRAY.numNullElements()); // assert(true == ARRAY.isAnyElementNonNull()); // assert(false == ARRAY.isAnyElementNull()); //.. // Next, we append a null element: //.. // array.appendNullElement(); // assert(2 == ARRAY.length()); // assert(5 == ARRAY.constElement(0)); // assert(DEFAULT_INT == ARRAY.constElement(1)); // assert(false == ARRAY.isElementNull(0)); // assert(true == ARRAY.isElementNull(1)); // assert(1 == ARRAY.numNullElements()); // assert(true == ARRAY.isAnyElementNonNull()); // assert(true == ARRAY.isAnyElementNull()); //.. // Then, we make the null element non-null: //.. // array.makeNonNull(1); // assert(2 == ARRAY.length()); // assert(5 == ARRAY.constElement(0)); // assert(DEFAULT_INT == ARRAY.constElement(1)); // assert(false == ARRAY.isElementNull(0)); // assert(false == ARRAY.isElementNull(1)); // assert(0 == ARRAY.numNullElements()); // assert(true == ARRAY.isAnyElementNonNull()); // assert(false == ARRAY.isAnyElementNull()); //.. // Next, we make the first element null: //.. // array.makeNull(0); // assert(2 == ARRAY.length()); // assert(DEFAULT_INT == ARRAY.constElement(0)); // assert(DEFAULT_INT == ARRAY.constElement(1)); // assert(true == ARRAY.isElementNull(0)); // assert(false == ARRAY.isElementNull(1)); // assert(1 == ARRAY.numNullElements()); // assert(true == ARRAY.isAnyElementNonNull()); // assert(true == ARRAY.isAnyElementNull()); //.. // Now, we remove the front element: //.. // array.removeElement(0); // assert(1 == ARRAY.length()); // assert(DEFAULT_INT == ARRAY.constElement(0)); // assert(false == ARRAY.isElementNull(0)); // assert(0 == ARRAY.numNullElements()); // assert(true == ARRAY.isAnyElementNonNull()); // assert(false == ARRAY.isAnyElementNull()); //.. // Finally, we remove the last remaining element and observe that the object is // empty again: //.. // array.removeElement(0); // assert(0 == ARRAY.length()); // assert(0 == ARRAY.numNullElements()); // assert(false == ARRAY.isAnyElementNonNull()); // assert(false == ARRAY.isAnyElementNull()); //.. #include <bdlscm_version.h> #include <bdlb_bitmaskutil.h> #include <bdlb_bitstringutil.h> #include <bslalg_swaputil.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_integralconstant.h> #include <bslmf_isbitwisemoveable.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsls_types.h> #include <bsl_cstddef.h> #include <bsl_cstdint.h> #include <bsl_climits.h> #include <bsl_cstring.h> #include <bsl_iosfwd.h> #include <bsl_vector.h> #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bsl_algorithm.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace BloombergLP { namespace bdlc { // ============== // class BitArray // ============== class BitArray { // This class implements an efficient, value-semantic array of boolean // (a.k.a. bit, i.e., binary digit) values stored in contiguous memory. // The physical capacity of this array may grow, but never shrinks. // Capacity may be reserved initially via a constructor, or at any time // thereafter by using the 'reserveCapacity' method; otherwise, capacity // will be increased automatically as needed. Note that capacity is not a // *salient* attribute of this object, and, as such, does not contribute to // overall value. Also note that this class provides an implicit no-throw // guarantee for all methods (including manipulators) that do not attempt // to alter capacity. public: // PUBLIC TYPES enum { k_BITS_PER_UINT64 = 64 }; // bits used to represent a 'uint64_t' // PUBLIC CLASS DATA static const bsl::size_t k_INVALID_INDEX = bdlb::BitStringUtil::k_INVALID_INDEX; private: // DATA bsl::vector<bsl::uint64_t> d_array; // array of 64-bit words bsl::size_t d_length; // number of significant bits in this // array // CLASS DATA static const bsl::uint64_t s_one = 1; static const bsl::uint64_t s_minusOne = ~static_cast<bsl::uint64_t>(0); // FRIENDS friend bool operator==(const BitArray&, const BitArray&); private: // PRIVATE CLASS METHODS static bsl::size_t arraySize(bsl::size_t numBits); // Return the size, in 64-bit words, of the integer array required to // store the specified 'numBits'. // PRIVATE MANIPULATORS bsl::uint64_t *data(); // Return an address providing modifiable access to the array of // 'uint64_t' values managed by this array. // PRIVATE ACCESSORS const bsl::uint64_t *data() const; // Return an address providing non-modifiable access to the array of // 'uint64_t' values managed by this array. public: // CLASS METHODS // Aspects static int maxSupportedBdexVersion(int versionSelector); // Return the maximum valid BDEX format version, as indicated by the // specified 'versionSelector', to be passed to the 'bdexStreamOut' // method. Note that it is highly recommended that 'versionSelector' // be formatted as "YYYYMMDD", a date representation. Also note that // 'versionSelector' should be a *compile*-time-chosen value that // selects a format version supported by both externalizer and // unexternalizer. See the 'bslx' package-level documentation for more // information on BDEX streaming of value-semantic types and // containers. // CREATORS explicit BitArray(bslma::Allocator *basicAllocator = 0); explicit BitArray(bsl::size_t initialLength, bslma::Allocator *basicAllocator = 0); BitArray(bsl::size_t initialLength, bool value, bslma::Allocator *basicAllocator = 0); // Create an array of binary digits (bits). By default, the array is // empty and has a capacity of 0 bits. Optionally specify the // 'initialLength' (in bits) of the array. If 'initialLength' is not // specified, the default length is 0. If 'initialLength' is // specified, optionally specify the 'value' for each bit in the // 'initialLength'. If 'value' is not specified, the default value for // each bit is 'false' (0). Optionally specify a 'basicAllocator' used // to supply memory. If 'basicAllocator' is 0, the currently installed // default allocator is used. BitArray(const BitArray& original, bslma::Allocator *basicAllocator = 0); // Create an array of binary digits (bits) having the same value as the // specified 'original' array. Optionally specify a 'basicAllocator' // used to supply memory. If 'basicAllocator' is 0, the currently // installed default allocator is used. ~BitArray(); // Destroy this object. // MANIPULATORS BitArray& operator=(const BitArray& rhs); // Assign to this array the value of the specified 'rhs' array, and // return a non-'const' reference to this array. BitArray& operator&=(const BitArray& rhs); // Bitwise AND the value of the specified 'rhs' array with the value of // this array (retaining the results), and return a non-'const' // reference to this object. The length of the result will be the // maximum of the lengths of this object and 'rhs', where any // most-significant bits that are represented in one of the two but not // the other will be set to 0. Note that 'a &= b;' will result in the // same value of 'a' as 'a = a & b;'. BitArray& operator-=(const BitArray& rhs); // Bitwise MINUS the value of the specified 'rhs' array from the value // of this array (retaining the results), and return a non-'const' // reference to this object. The length of the result will be the // maximum of the lengths of this object and 'rhs'. If // 'length() > rhs.length()', the unmatched most-significant bits in // this array are left unchanged; otherwise, any high-order bits of the // result that were not present in this object prior to the operation // will be set to 0. Note that 'a -= b;' will result in the same value // of 'a' as 'a = a - b;' and if 'a' and 'b' are the same length, // 'a -= b;' will result in the same value of 'a' as 'a &= ~b;' or // 'a = a & ~b;'. BitArray& operator|=(const BitArray& rhs); // Bitwise OR the value of the specified 'rhs' array with the value of // this array (retaining the results), and return a non-'const' // reference to this object. If 'length() > rhs.length()', the // unmatched most-significant bits in this array are left unchanged; // otherwise, any unmatched most-significant bits in 'rhs' are // propagated to the result without modification. Note that 'a |= b;' // will result in the same value of 'a' as 'a = a | b;'. BitArray& operator^=(const BitArray& rhs); // Bitwise XOR the value of the specified 'rhs' array with the value of // this array (retaining the results), and return a non-'const' // reference to this object. If 'length() > rhs.length()', the // unmatched most-significant bits in this array are left unchanged; // otherwise, any unmatched most-significant bits in 'rhs' are // propagated to the result without modification. Note that 'a ^= b;' // will result in the same value of 'a' as 'a = a ^ b;'. BitArray& operator<<=(bsl::size_t numBits); // Shift the bits in this array LEFT by the specified 'numBits', // filling lower-order bits with zeros (retaining the results), and // return a non-'const' reference to this object. The behavior is // undefined unless 'numBits <= length()'. Note that the length of // this array is unchanged and the highest-order 'numBits' are // discarded. BitArray& operator>>=(bsl::size_t numBits); // Shift the bits in this array RIGHT by the specified 'numBits', // filling higher-order bits with zeros and discarding low-order bits, // and return a non-'const' reference to this object. The behavior is // undefined unless 'numBits <= length()'. Note that the length of // this array is unchanged. void andEqual(bsl::size_t index, bool value); // AND the bit at the specified 'index' in this array with the // specified 'value' (retaining the result). The behavior is undefined // unless 'index < length()'. void andEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Bitwise AND the specified 'numBits' in this array, beginning at the // specified 'dstIndex', with values from the specified 'srcArray', // beginning at the specified 'srcIndex' (retaining the results). The // behavior is undefined unless 'dstIndex + numBits <= length()' and // 'srcIndex + numBits <= srcArray.length()'. void append(bool value); // Append to this array the specified 'value'. Note that this method // has the same behavior as: //.. // insert(length(), value); //.. void append(bool value, bsl::size_t numBits); // Append to this array the specified 'numBits' having the specified // 'value'. Note that this method has the same behavior as: //.. // insert(length(), value, numBits); //.. void append(const BitArray& srcArray); // Append to this array the values from the specified 'srcArray'. Note // that this method has the same behavior as: //.. // insert(length(), srcArray); //.. void append(const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Append to this array the specified 'numBits' from the specified // 'srcArray', beginning at the specified 'srcIndex'. The behavior is // undefined unless 'srcIndex + numBits <= srcArray.length()'. Note // that this method has the same behavior as: //.. // insert(length(), srcArray, srcIndex, numBits); //.. void assign(bsl::size_t index, bool value); // Set the value at the specified 'index' in this array to the // specified 'value'. The behavior is undefined unless // 'index < length()'. void assign(bsl::size_t index, bool value, bsl::size_t numBits); // Set the value of the specified 'numBits' bits starting at the // specified 'index' in this array to the specified 'value'. The // behavior is undefined unless 'index + numBits < length()'. void assign(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Replace the specified 'numBits' in this array, beginning at the // specified 'dstIndex', with values from the specified 'srcArray' // beginning at the specified 'srcIndex'. The behavior is undefined // unless 'dstIndex + numBits <= length()' and // 'srcIndex + numBits <= srcArray.length()'. Note that, absent // aliasing, this method has the same behavior as, but is more // efficient than: //.. // remove(dstIndex, numBits); // insert(dstIndex, srcArray, srcIndex, numBits); //.. void assign0(bsl::size_t index); // Set to 0 the value of the bit at the specified 'index' in this // array. The behavior is undefined unless 'index < length()'. void assign0(bsl::size_t index, bsl::size_t numBits); // Set to 0 the specified 'numBits' values in this array, beginning at // the specified 'index'. The behavior is undefined unless // 'index + numBits <= length()'. void assign1(bsl::size_t index); // Set to 1 the value of the bit at the specified 'index' in this // array. The behavior is undefined unless 'index < length()'. void assign1(bsl::size_t index, bsl::size_t numBits); // Set to 1 the specified 'numBits' values in this array, beginning at // the specified 'index'. The behavior is undefined unless // 'index + numBits <= length()'. void assignAll(bool value); // Set all bits in this array to the specified 'value'. void assignAll0(); // Set to 0 the value of every bit in this array. void assignAll1(); // Set to 1 the value of every bit in this array. void assignBits(bsl::size_t index, bsl::uint64_t srcBits, bsl::size_t numBits); // Assign the low-order specified 'numBits' from the specified // 'srcBits' to this object, starting at the specified 'index'. The // behavior is undefined unless 'numBits <= k_BITS_PER_UINT64' and // 'index + numBits <= length()'. void insert(bsl::size_t dstIndex, bool value); // Insert into this array at the specified 'dstIndex' the specified // 'value'. All values with indices at or above 'dstIndex' in this // array are shifted up by one bit position. The behavior is undefined // unless 'dstIndex <= length()'. void insert(bsl::size_t dstIndex, bool value, bsl::size_t numBits); // Insert into this array at the specified 'dstIndex' the specified // 'numBits' having the specified 'value'. All values with indices at // or above 'dstIndex' in this array are shifted up by 'numBits' bit // positions. The behavior is undefined unless 'dstIndex <= length()'. void insert(bsl::size_t dstIndex, const BitArray& srcArray); // Insert into this array, beginning at the specified 'dstIndex', the // values from the specified 'srcArray'. All values with indices at or // above 'dstIndex' in this array are shifted up by 'srcArray.length()' // bit positions. The behavior is undefined unless // 'dstIndex <= length()'. void insert(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Insert into this array, beginning at the specified 'dstIndex', the // specified 'numBits' from the specified 'srcArray' beginning at the // specified 'srcIndex'. All values with initial indices at or above // 'dstIndex' are shifted up by 'numBits' positions. The behavior is // undefined unless 'dstIndex <= length()' and // 'srcIndex + numBits <= srcArray.length()'. void minusEqual(bsl::size_t index, bool value); // MINUS (subtract) from the bit at the specified 'index' in this array // the specified 'value' (retaining the result). The behavior is // undefined unless 'index < length()'. Note that the logical // difference 'A - B' is defined to be 'A & !B'. void minusEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Bitwise MINUS (subtract) from the specified 'numBits' in this array, // beginning at the specified 'dstIndex', values from the specified // 'srcArray' beginning at the specified 'srcIndex' (retaining the // results). The behavior is undefined unless // 'dstIndex + numBits <= length()' and // 'srcIndex + numBits <= srcArray.length()'. Note that the logical // difference 'A - B' is defined to be 'A & !B'. void orEqual(bsl::size_t index, bool value); // OR the bit at the specified 'index' in this array with the specified // 'value' (retaining the result). The behavior is undefined unless // 'index < length()'. void orEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Bitwise OR the specified 'numBits' in this array, beginning at the // specified 'dstIndex', with values from the specified 'srcArray' // beginning at the specified 'srcIndex' (retaining the results). The // behavior is undefined unless 'dstIndex + numBits <= length()' and // 'srcIndex + numBits <= srcArray.length()'. void remove(bsl::size_t index); // Remove from this array the bit at the specified 'index'. All values // at indices above 'index' in this array are shifted down by one bit // position. The length of this array is reduced by 1. The behavior // is undefined unless 'index < length()'. void remove(bsl::size_t index, bsl::size_t numBits); // Remove from this array the specified 'numBits', beginning at the // specified 'index'. All values at indices above 'index' in this // array are shifted down by 'numBits' positions. The length of this // array is reduced by 'numBits'. The behavior is undefined unless // 'index + numBits <= length()'. void removeAll(); // Remove all of the bits in this array, leaving the length 0, but // having no effect on capacity. void reserveCapacity(bsl::size_t numBits); // Reserve sufficient internal capacity to accommodate a length of at // least the specified 'numBits' without reallocation. If an exception // is thrown during this reallocation attempt (i.e., by the memory // allocator indicated at construction) the value of this array is // guaranteed to be unchanged. void rotateLeft(bsl::size_t numBits); // Shift the values in this array to the left by the specified // 'numBits' positions, with the high-order values "rotating" into the // low-order bits. The behavior is undefined unless // 'numBits <= length()'. Note that the length of this array remains // unchanged. void rotateRight(bsl::size_t numBits); // Shift the values in this array to the right by the specified // 'numBits' positions, with the low-order values "rotating" into the // high-order bits. The behavior is undefined unless // 'numBits <= length()'. Note that the length of this array remains // unchanged. void setLength(bsl::size_t newLength, bool value = false); // Set the number of bits in this array to the specified 'newLength'. // If 'newLength < length()', bits at index positions at or above // 'newLength' are removed; otherwise, any new bits (at or above the // current length) are initialized to the optionally specified 'value', // or to 0 if 'value' is not specified. void swapBits(bsl::size_t index1, bsl::size_t index2); // Efficiently exchange the values of the bits at the specified // 'index1' and 'index2' indices. The behavior is undefined unless // 'index1 < length()' and 'index2 < length()'. void toggle(bsl::size_t index); // Complement the value of the bit at the specified 'index' in this // array. The behavior is undefined unless 'index < length()'. void toggle(bsl::size_t index, bsl::size_t numBits); // Complement the values of each of the specified 'numBits' in this // array, beginning at the specified 'index'. The behavior is // undefined unless 'index + numBits <= length()'. void toggleAll(); // Complement the value of every bit in this array. Note that the // behavior is analogous to applying the '~' operator to an object of // fundamental type 'unsigned int'. void xorEqual(bsl::size_t index, bool value); // XOR the bit at the specified 'index' in this array with the // specified 'value' (retaining the result). The behavior is undefined // unless 'index < length()'. void xorEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits); // Bitwise XOR the specified 'numBits' in this array, beginning at the // specified 'dstIndex', with values from the specified 'srcArray' // beginning at the specified 'srcIndex' (retaining the results). The // behavior is undefined unless 'dstIndex + numBits <= length()' and // 'srcIndex + numBits <= srcArray.length()'. // Aspects template <class STREAM> STREAM& bdexStreamIn(STREAM& stream, int version); // Assign to this object the value read from the specified input // 'stream' using the specified 'version' format, and return a // reference to 'stream'. If 'stream' is initially invalid, this // operation has no effect. If 'version' is not supported, this object // is unaltered and 'stream' is invalidated, but otherwise unmodified. // If 'version' is supported but 'stream' becomes invalid during this // operation, this object has an undefined, but valid, state. Note // that no version is read from 'stream'. See the 'bslx' package-level // documentation for more information on BDEX streaming of // value-semantic types and containers. void swap(BitArray& other); // Efficiently exchange the value of this object with the value of the // specified 'other' object. This method provides the no-throw // exception-safety guarantee. The behavior is undefined unless this // object was created with the same allocator as 'other'. // ACCESSORS bool operator[](bsl::size_t index) const; // Return the value of the bit at the specified 'index' in this array. // The behavior is undefined unless 'index < length()'. bsl::uint64_t bits(bsl::size_t index, bsl::size_t numBits) const; // Return the specified 'numBits' beginning at the specified 'index' in // this array as the low-order bits of the returned value. The // behavior is undefined unless // 'numBits <= sizeof(uint64_t) * CHAR_BIT' and // 'index + numBits <= length()'. bsl::size_t find0AtMaxIndex(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the index of the most-significant 0 bit in this array in the // range optionally specified by 'begin' and 'end', and // 'k_INVALID_INDEX' otherwise. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. bsl::size_t find0AtMinIndex(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the index of the least-significant 0 bit in this array in the // range optionally specified by 'begin' and 'end', and // 'k_INVALID_INDEX' otherwise. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. bsl::size_t find1AtMaxIndex(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the index of the most-significant 1 bit in this array in the // range optionally specified by 'begin' and 'end', and // 'k_INVALID_INDEX' otherwise. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. bsl::size_t find1AtMinIndex(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the index of the least-significant 1 bit in this array in the // range optionally specified by 'begin' and 'end', and // 'k_INVALID_INDEX' otherwise. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. bool isAny0() const; // Return 'true' if the value of any bit in this array is 0, and // 'false' otherwise. bool isAny1() const; // Return 'true' if the value of any bit in this array is 1, and // 'false' otherwise. bool isEmpty() const; // Return 'true' if the length of this bit array is 0, and 'false' // otherwise. bsl::size_t length() const; // Return the number of bits in this array. bsl::size_t num0(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the number of bits in the range optionally specified by // 'begin' and 'end' having a value of 0. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. bsl::size_t num1(bsl::size_t begin = 0, bsl::size_t end = k_INVALID_INDEX) const; // Return the number of bits in the range optionally specified by // 'begin' and 'end' having a value of 1. The range is // '[begin .. effectiveEnd)', where 'effectiveEnd == length()' if 'end' // is not specified and 'effectiveEnd == end' otherwise. The behavior // is undefined unless 'begin <= effectiveEnd <= length()'. // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. template <class STREAM> STREAM& bdexStreamOut(STREAM& stream, int version) const; // Write the value of this object, using the specified 'version' // format, to the specified output 'stream', and return a reference to // 'stream'. If 'stream' is initially invalid, this operation has no // effect. If 'version' is not supported, 'stream' is invalidated, but // otherwise unmodified. Note that 'version' is not written to // 'stream'. See the 'bslx' package-level documentation for more // information on BDEX streaming of value-semantic types and // containers. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the // optionally specified indentation 'level' and return a non-'const' // reference to 'stream'. If 'level' is specified, optionally specify // 'spacesPerLevel', the number of spaces per indentation level for // this and all of its nested objects. Each line is indented by the // absolute value of 'level * spacesPerLevel'. If 'level' is negative, // suppress indentation of the first line. 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. #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation // DEPRECATED METHODS static int maxSupportedBdexVersion(); // !DEPRECATED!: Use 'maxSupportedBdexVersion(int)' instead. // // Return the most current BDEX streaming version number supported by // this class. #endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation }; // FREE OPERATORS bool operator==(const BitArray& lhs, const BitArray& rhs); // Return 'true' if the specified 'lhs' and 'rhs' arrays have the same // value, and 'false' otherwise. Two arrays have the same value if they // have the same length, and corresponding bits at each bit position have // the same value. bool operator!=(const BitArray& lhs, const BitArray& rhs); // Return 'true' if the specified 'lhs' and 'rhs' arrays do not have the // same value, and 'false' otherwise. Two arrays do not have the same // value if they do not have the same length, or there is at least one // valid index position at which corresponding bits do not have the same // value. BitArray operator~(const BitArray& array); // Return the bitwise complement ("toggle") of the specified 'array'. BitArray operator&(const BitArray& lhs, const BitArray& rhs); // Return the value that is the bitwise AND of the specified 'lhs' and // 'rhs' arrays. The length of the resulting bit array will be the maximum // of that of 'lhs' and 'rhs', with any unmatched high-order bits set to 0. // Note that this behavior is consistent with zero-extending a copy of the // shorter array. BitArray operator-(const BitArray& lhs, const BitArray& rhs); // Return the value that is the bitwise MINUS of the specified 'lhs' and // 'rhs' arrays. The length of the resulting bit array will be the maximum // of that of 'lhs' and 'rhs', with any unmatched high-order 'lhs' bits // copied unchanged, and any unmatched high-order 'rhs' bits set to 0. // Note that this behavior is consistent with zero-extending a copy of the // shorter array. BitArray operator|(const BitArray& lhs, const BitArray& rhs); // Return the value that is the bitwise OR of the specified 'lhs' and 'rhs' // arrays. The length of the resulting bit array will be the maximum of // that of 'lhs' and 'rhs', with any unmatched high-order bits copied // unchanged. Note that this behavior is consistent with zero-extending a // copy of the shorter array. BitArray operator^(const BitArray& lhs, const BitArray& rhs); // Return the value that is the bitwise XOR of the specified 'lhs' and // 'rhs' arrays. The length of the resulting bit array will be the maximum // of that of 'lhs' and 'rhs', with any unmatched high-order bits copied // unchanged. Note that this behavior is consistent with zero-extending a // copy of the shorter array. BitArray operator<<(const BitArray& array, bsl::size_t numBits); // Return the value of the specified 'array' left-shifted by the specified // 'numBits' positions, having filled the lower-index positions with zeros. // The behavior is undefined unless 'numBits <= array.length()'. Note that // the length of the result equals the length of the original array, and // that the highest-order 'numBits' are discarded in the result. BitArray operator>>(const BitArray& array, bsl::size_t numBits); // Return the value of the specified 'array' right-shifted by the specified // 'numBits' positions, having filled the higher-index positions with // zeros. The behavior is undefined unless 'numBits <= array.length()'. // Note that the length of the result equals the length of the original // array, and that the lowest-order 'numBits' are discarded in the result. bsl::ostream& operator<<(bsl::ostream& stream, const BitArray& rhs); // Format the bits in the specified 'rhs' bit array to the specified output // 'stream' in a single-line format, and return a reference to 'stream'. // FREE FUNCTIONS void swap(BitArray& a, BitArray& b); // Exchange the values of the specified 'a' and 'b' objects. This function // provides the no-throw exception-safety guarantee if the two objects were // created with the same allocator and the basic guarantee otherwise. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------- // class BitArray // -------------- // PRIVATE CLASS METHODS inline bsl::size_t BitArray::arraySize(bsl::size_t numBits) { // Note that we ensure that the capacity of 'd_array' is at least 1 at all // times. This way we know that 'd_array.front()' is valid. const bsl::size_t ret = (numBits + k_BITS_PER_UINT64 - 1) / k_BITS_PER_UINT64; return ret ? ret : 1; } // PRIVATE MANIPULATORS inline bsl::uint64_t *BitArray::data() { BSLS_ASSERT_SAFE(!d_array.empty()); return d_array.data(); } // PRIVATE ACCESSORS inline const bsl::uint64_t *BitArray::data() const { BSLS_ASSERT_SAFE(!d_array.empty()); return d_array.data(); } // CLASS METHODS // Aspects inline int BitArray::maxSupportedBdexVersion(int) { return 1; } // MANIPULATORS inline BitArray& BitArray::operator=(const BitArray& rhs) { d_array.resize(rhs.d_array.size()); bsl::memcpy(d_array.data(), rhs.d_array.data(), d_array.size() * sizeof(bsl::uint64_t)); d_length = rhs.d_length; return *this; } inline BitArray& BitArray::operator&=(const BitArray& rhs) { if (this == &rhs) { return *this; // RETURN } const bsl::size_t rLen = rhs.d_length; if (rLen > d_length) { setLength(rLen, false); } else if (rLen < d_length) { assign0(rLen, d_length - rLen); } bdlb::BitStringUtil::andEqual(data(), 0, rhs.data(), 0, rLen); return *this; } inline BitArray& BitArray::operator-=(const BitArray& rhs) { if (this == &rhs) { assignAll0(); return *this; // RETURN } if (d_length < rhs.d_length) { setLength(rhs.d_length, false); } bdlb::BitStringUtil::minusEqual(data(), 0, rhs.data(), 0, rhs.d_length); return *this; } inline BitArray& BitArray::operator|=(const BitArray& rhs) { if (this == &rhs) { return *this; // RETURN } if (d_length < rhs.d_length) { setLength(rhs.d_length, false); } bdlb::BitStringUtil::orEqual(data(), 0, rhs.data(), 0, rhs.d_length); return *this; } inline BitArray& BitArray::operator^=(const BitArray& rhs) { if (this == &rhs) { assignAll0(); return *this; // RETURN } if (d_length < rhs.d_length) { setLength(rhs.d_length, false); } bdlb::BitStringUtil::xorEqual(data(), 0, rhs.data(), 0, rhs.d_length); return *this; } inline BitArray& BitArray::operator>>=(bsl::size_t numBits) { BSLS_ASSERT(numBits <= d_length); if (numBits) { if (d_length > numBits) { const bsl::size_t remBits = d_length - numBits; bdlb::BitStringUtil::copyRaw(data(), 0, data(), numBits, remBits); assign0(remBits, numBits); } else { assignAll0(); } } return *this; } inline BitArray& BitArray::operator<<=(bsl::size_t numBits) { BSLS_ASSERT(numBits <= d_length); if (numBits) { if (d_length > numBits) { const bsl::size_t remBits = d_length - numBits; bdlb::BitStringUtil::copy(data(), numBits, data(), 0, remBits); assign0(0, numBits); } else { assignAll0(); } } return *this; } inline void BitArray::andEqual(bsl::size_t index, bool value) { BSLS_ASSERT_SAFE(index < d_length); if (!value) { assign0(index); } } inline void BitArray::andEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(dstIndex + numBits <= d_length); BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); bdlb::BitStringUtil::andEqual(data(), dstIndex, srcArray.data(), srcIndex, numBits); } inline void BitArray::append(bool value) { if (d_length && 0 == d_length % k_BITS_PER_UINT64) { d_array.push_back(value); } else if (value) { bdlb::BitStringUtil::assign1(data(), d_length); } ++d_length; } inline void BitArray::append(bool value, bsl::size_t numBits) { insert(d_length, value, numBits); } inline void BitArray::append(const BitArray& srcArray) { insert(d_length, srcArray, 0, srcArray.d_length); } inline void BitArray::append(const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); insert(d_length, srcArray, srcIndex, numBits); } inline void BitArray::assign(bsl::size_t index, bool value) { BSLS_ASSERT_SAFE(index < d_length); bdlb::BitStringUtil::assign(data(), index, value); } inline void BitArray::assign(bsl::size_t index, bool value, bsl::size_t numBits) { BSLS_ASSERT(index + numBits <= d_length); bdlb::BitStringUtil::assign(data(), index, value, numBits); } inline void BitArray::assign(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(dstIndex + numBits <= d_length); BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); if (&srcArray == this) { // Might be overlapping copy. bdlb::BitStringUtil::copy(data(), dstIndex, srcArray.data(), srcIndex, numBits); } else { // Definitely not overlapping copy. bdlb::BitStringUtil::copyRaw(data(), dstIndex, srcArray.data(), srcIndex, numBits); } } inline void BitArray::assign0(bsl::size_t index) { BSLS_ASSERT_SAFE(index < d_length); bdlb::BitStringUtil::assign0(data(), index); } inline void BitArray::assign0(bsl::size_t index, bsl::size_t numBits) { BSLS_ASSERT(index + numBits <= d_length); bdlb::BitStringUtil::assign0(data(), index, numBits); } inline void BitArray::assign1(bsl::size_t index) { BSLS_ASSERT_SAFE(index < d_length); bdlb::BitStringUtil::assign1(data(), index); } inline void BitArray::assign1(bsl::size_t index, bsl::size_t numBits) { BSLS_ASSERT(index + numBits <= d_length); bdlb::BitStringUtil::assign1(data(), index, numBits); } inline void BitArray::assignAll(bool value) { if (value) { assignAll1(); } else { assignAll0(); } } inline void BitArray::assignAll0() { bdlb::BitStringUtil::assign0(data(), 0, d_length); } inline void BitArray::assignAll1() { bdlb::BitStringUtil::assign1(data(), 0, d_length); } inline void BitArray::assignBits(bsl::size_t index, bsl::uint64_t srcBits, bsl::size_t numBits) { BSLS_ASSERT( numBits <= k_BITS_PER_UINT64); BSLS_ASSERT(index + numBits <= d_length); bdlb::BitStringUtil::assignBits(data(), index, srcBits, numBits); } inline void BitArray::insert(bsl::size_t dstIndex, const BitArray& srcArray) { BSLS_ASSERT(dstIndex <= d_length); insert(dstIndex, srcArray, 0, srcArray.d_length); } inline void BitArray::insert(bsl::size_t dstIndex, bool value) { BSLS_ASSERT(dstIndex <= d_length); setLength(d_length + 1); bdlb::BitStringUtil::insert(data(), d_length - 1, dstIndex, value, 1); } inline void BitArray::insert(bsl::size_t dstIndex, bool value, bsl::size_t numBits) { BSLS_ASSERT(dstIndex <= d_length); setLength(d_length + numBits); bdlb::BitStringUtil::insert(data(), d_length - numBits, dstIndex, value, numBits); } inline void BitArray::minusEqual(bsl::size_t index, bool value) { BSLS_ASSERT_SAFE(index < d_length); if (value) { assign0(index); } } inline void BitArray::minusEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(dstIndex + numBits <= d_length); BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); bdlb::BitStringUtil::minusEqual(data(), dstIndex, srcArray.data(), srcIndex, numBits); } inline void BitArray::orEqual(bsl::size_t index, bool value) { BSLS_ASSERT(index < d_length); if (value) { assign1(index); } } inline void BitArray::orEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(dstIndex + numBits <= d_length); BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); bdlb::BitStringUtil::orEqual(data(), dstIndex, srcArray.data(), srcIndex, numBits); } inline void BitArray::remove(bsl::size_t index) { BSLS_ASSERT_SAFE(index < d_length); remove(index, 1); } inline void BitArray::remove(bsl::size_t index, bsl::size_t numBits) { BSLS_ASSERT(index + numBits <= d_length); bdlb::BitStringUtil::remove(data(), d_length, index, numBits); setLength(d_length - numBits); } inline void BitArray::removeAll() { d_array.clear(); d_array.resize(1); d_length = 0; } inline void BitArray::reserveCapacity(bsl::size_t numBits) { d_array.reserve(arraySize(numBits)); } inline void BitArray::swapBits(bsl::size_t index1, bsl::size_t index2) { BSLS_ASSERT(index1 < d_length); BSLS_ASSERT(index2 < d_length); if (index1 != index2) { const bool tmp = (*this)[index1]; assign(index1, (*this)[index2]); assign(index2, tmp); } } inline void BitArray::toggle(bsl::size_t index) { BSLS_ASSERT_SAFE(index < d_length); const bsl::size_t idx = index / k_BITS_PER_UINT64; const int pos = static_cast<unsigned>(index) % k_BITS_PER_UINT64; d_array[idx] ^= (s_one << pos); } inline void BitArray::toggle(bsl::size_t index, bsl::size_t numBits) { BSLS_ASSERT(index + numBits <= d_length); // 'index' and 'numBits' non-negative checked by 'BitStringUtil'. bdlb::BitStringUtil::toggle(data(), index, numBits); } inline void BitArray::toggleAll() { toggle(0, d_length); } inline void BitArray::xorEqual(bsl::size_t index, bool value) { BSLS_ASSERT_SAFE(index < d_length); if (value) { toggle(index); } } inline void BitArray::xorEqual(bsl::size_t dstIndex, const BitArray& srcArray, bsl::size_t srcIndex, bsl::size_t numBits) { BSLS_ASSERT(dstIndex + numBits <= d_length); BSLS_ASSERT(srcIndex + numBits <= srcArray.d_length); bdlb::BitStringUtil::xorEqual(data(), dstIndex, srcArray.data(), srcIndex, numBits); } // Aspects template <class STREAM> STREAM& BitArray::bdexStreamIn(STREAM& stream, int version) { if (stream) { switch (version) { // Switch on the schema version (starting with 1). case 1: { int newLength; stream.getLength(newLength); if (!stream) { return stream; // RETURN } if (0 == newLength) { removeAll(); return stream; // RETURN } const bsl::size_t len = arraySize(newLength); removeAll(); d_array.resize(len); // 'getArrayUint64' will throw if there is bad input, so to prevent // invariants tests in the bit array destructor from failing, we // must make 'd_length' consistent with 'd_array.size()' before // that happens. d_length = newLength; stream.getArrayUint64( reinterpret_cast<bsls::Types::Uint64 *>(d_array.data()), static_cast<int>(len)); if (!stream) { removeAll(); return stream; // RETURN } // Test for corrupted data. const int rem = static_cast<unsigned>(d_length) % k_BITS_PER_UINT64; if (rem) { const bsl::uint64_t mask = (s_one << rem) - 1; if (d_array.back() & ~mask) { // Correct invalid bit array and invalidate stream. This // is fastest way to valid, arbitrary state. d_array.back() &= mask; stream.invalidate(); return stream; // RETURN } } } break; default: { stream.invalidate(); } } } return stream; } inline void BitArray::swap(BitArray& other) { // 'swap' is undefined for objects with non-equal allocators. BSLS_ASSERT(allocator() == other.allocator()); bslalg::SwapUtil::swap(&d_array, &other.d_array); bslalg::SwapUtil::swap(&d_length, &other.d_length); } // ACCESSORS inline bool BitArray::operator[](bsl::size_t index) const { BSLS_ASSERT_SAFE(index < d_length); return bdlb::BitStringUtil::bit(data(), index); } inline bsl::uint64_t BitArray::bits(bsl::size_t index, bsl::size_t numBits) const { BSLS_ASSERT_SAFE(index + numBits <= d_length); return bdlb::BitStringUtil::bits(data(), index, numBits); } inline bsl::size_t BitArray::find0AtMaxIndex(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::find0AtMaxIndex(data(), begin, end); } inline bsl::size_t BitArray::find0AtMinIndex(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::find0AtMinIndex(data(), begin, end); } inline bsl::size_t BitArray::find1AtMaxIndex(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::find1AtMaxIndex(data(), begin, end); } inline bsl::size_t BitArray::find1AtMinIndex(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::find1AtMinIndex(data(), begin, end); } inline bool BitArray::isAny0() const { return bdlb::BitStringUtil::isAny0(data(), 0, d_length); } inline bool BitArray::isAny1() const { return bdlb::BitStringUtil::isAny1(data(), 0, d_length); } inline bool BitArray::isEmpty() const { return 0 == d_length; } inline bsl::size_t BitArray::length() const { return d_length; } inline bsl::size_t BitArray::num0(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::num0(data(), begin, end - begin); } inline bsl::size_t BitArray::num1(bsl::size_t begin, bsl::size_t end) const { if (k_INVALID_INDEX == end) { end = d_length; } BSLS_ASSERT(begin <= end); BSLS_ASSERT( end <= d_length); return bdlb::BitStringUtil::num1(data(), begin, end - begin); } // Aspects inline bslma::Allocator *BitArray::allocator() const { return d_array.get_allocator().mechanism(); } template <class STREAM> STREAM& BitArray::bdexStreamOut(STREAM& stream, int version) const { switch (version) { case 1: { BSLS_ASSERT(d_length <= INT_MAX); stream.putLength(static_cast<int>(d_length)); if (0 != d_length) { stream.putArrayUint64( reinterpret_cast<const bsls::Types::Uint64 *>(d_array.data()), static_cast<int>(d_array.size())); } } break; default: { stream.invalidate(); } } return stream; } #ifndef BDE_OPENSOURCE_PUBLICATION // pending deprecation // DEPRECATED METHODS inline int BitArray::maxSupportedBdexVersion() { return 1; } #endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation } // close package namespace // FREE OPERATORS inline bool bdlc::operator==(const BitArray& lhs, const BitArray& rhs) { if (lhs.d_length != rhs.d_length) { return false; // RETURN } return bdlb::BitStringUtil::areEqual(lhs.data(), rhs.data(), lhs.d_length); } inline bool bdlc::operator!=(const BitArray& lhs, const BitArray& rhs) { return !(lhs == rhs); } inline bdlc::BitArray bdlc::operator~(const BitArray& array) { BitArray tmp(array); tmp.toggleAll(); return tmp; } inline bdlc::BitArray bdlc::operator&(const BitArray& lhs, const BitArray& rhs) { BitArray tmp(lhs); tmp &= rhs; return tmp; } inline bdlc::BitArray bdlc::operator|(const BitArray& lhs, const BitArray& rhs) { BitArray tmp(lhs); tmp |= rhs; return tmp; } inline bdlc::BitArray bdlc::operator^(const BitArray& lhs, const BitArray& rhs) { BitArray tmp(lhs); tmp ^= rhs; return tmp; } inline bdlc::BitArray bdlc::operator-(const BitArray& lhs, const BitArray& rhs) { BitArray tmp(lhs); tmp -= rhs; return tmp; } inline bdlc::BitArray bdlc::operator<<(const BitArray& array, bsl::size_t numBits) { BSLS_ASSERT(numBits <= array.length()); BitArray tmp(array); tmp <<= numBits; return tmp; } inline bdlc::BitArray bdlc::operator>>(const BitArray& array, bsl::size_t numBits) { BSLS_ASSERT(numBits <= array.length()); BitArray tmp(array); tmp >>= numBits; return tmp; } inline bsl::ostream& bdlc::operator<<(bsl::ostream& stream, const BitArray& rhs) { return rhs.print(stream, 0, -1); } namespace bslmf { template <> struct IsBitwiseMoveable<bdlc::BitArray> : public IsBitwiseMoveable<bsl::vector<bsl::uint64_t> > { // This template specialization for 'IsBitwiseMoveable' indicates that // 'BitArray' is a bitwise movable type if 'vector<uint64_t>' is a bitwise // movable type. }; } // close namespace bslmf namespace bslma { template <> struct UsesBslmaAllocator<bdlc::BitArray> : bsl::true_type { // This template specialization for 'UsesBslmaAllocator' indicates that // 'BitArray' uses 'bslma::Allocator'. }; } // close namespace bslma } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 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 ----------------------------------