// bdlb_bitstringimputil.h -*-C++-*- #ifndef INCLUDED_BDLB_BITSTRINGIMPUTIL #define INCLUDED_BDLB_BITSTRINGIMPUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide functional bit-manipulation of 'uint64_t' values. // //@CLASSES: // bdlb::BitStringImpUtil: namespace for 'uint64_t' utilities // //@SEE_ALSO: bdlb_bitstringutil // //@DESCRIPTION: This component provides a utility 'struct', // 'bdlb::BitStringImpUtil', that serves as a namespace for a collection of // functions that provide bit-level operations on 'uint64_t' values. Some of // these functions consist of a single bitwise logical operation. The point of // implementing them as functions is to facilitate providing these functions as // arguments to templates in 'bdlb_bitstringutil'. // // Note that no functions supporting 'uint32_t' are provided here. This // component exists solely to support 'bdlb::BitStringUtil', which deals // entirely in 'uint64_t' values. // // Note that the 'find*' functions defined here only find set bits -- there is // never a context in 'bdlb_bitstringutil' where a 'find*' that found clear // bits is needed. // ///Usage ///----- // This section illustrates the intended use of this component. // // Note that, in all of these examples, the low-order bit is considered bit 0 // and resides on the right edge of the bit string. // ///Example 1: Manipulators ///- - - - - - - - - - - - // This example demonstrates the "manipulator" static functions defined in this // component, which can change the state of a 'uint64_t'. // // The '*EqBits' functions ('andEqBits', 'minusEqBits', 'orEqBits', and // 'xorEqBits'), have the following signature: //.. // void function(uint64_t *dstValue, // int dstIndex, // uint64_t srcValue, // int numBits); //.. // First, we demonstrate the 'andEqBits' function: //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::andEqBits(&dstValue, 8, 0, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..00000000000000000011001100110011 | // | 'srcValue == 0' in binary: 0..00000000000000000000000000000000 | // | 'srcValue', 0x00, at index 8: 00000000 | // | 'dstValue' after in binary: 0..00000000000000000000000000110011 | // +--------------------------------------------------------------------------+ // // uint64_t dstValue; // // dstValue = 0x3333; // bdlb::BitStringImpUtil::andEqBits(&dstValue, 8, 0, 8); // assert(static_cast<uint64_t>(0x33) == dstValue); //.. // Then, we apply 'andEqBits' with all bits set in the relevant part of // 'srcValue, which has no effect: //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::andEqBits(&dstValue, 8, 0, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..00000000000000000011001100110011 | // | 'srcValue == 0xffff' in binary: 0..00000000000000001111111111111111 | // | 'srcValue', 0xff, at index 8: 11111111 | // | 'dstValue' after in binary: 0..00000000000000000011001100110011 | // +--------------------------------------------------------------------------+ // // dstValue = 0x3333; // bdlb::BitStringImpUtil::andEqBits(&dstValue, 8, 0xffff, 8); // assert(static_cast<uint64_t>(0x3333) == dstValue); //.. // Next, we demonstrate 'orEqBits', which takes low-order bits of a 'srcValue' // and bitwise ORs them with 'dstValue': //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::orEqBits(&dstValue, 16, 0xffff, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..00110011001100110011001100110011 | // | 'srcValue == 0xffff' in binary: 0..00000000000000001111111111111111 | // | 'srcValue', 0xff, at index 16: 11111111 | // | 'dstValue' after in binary: 0..00110011111111110011001100110011 | // +--------------------------------------------------------------------------+ // // dstValue = 0x33333333; // bdlb::BitStringImpUtil::orEqBits(&dstValue, 16, 0xffff, 8); // assert(static_cast<uint64_t>(0x33ff3333) == dstValue); //.. // Then, we demonstrate applying the same operation where '*dstValue' is // initially 0: //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::orEqBits(&dstValue, 16, 0xffff, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..00000000000000000000000000000000 | // | 'srcValue == 0xffff' in binary: 0..00000000000000001111111111111111 | // | 'srcValue', 0xff, at index 16: 11111111 | // | 'dstValue' after in binary: 0..00000000111111110000000000000000 | // +--------------------------------------------------------------------------+ // // dstValue = 0; // bdlb::BitStringImpUtil::orEqBits(&dstValue, 16, 0xffff, 8); // assert(static_cast<uint64_t>(0x00ff0000) == dstValue); //.. // Now, we apply another function, 'xorEqBits', that takes the low-order bits // of 'srcValue' and bitwise XORs them with 'dstValue': //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::xorEqBits(&dstValue, 16, 0xffff, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..01110111011101110111011101110111 | // | 'srcValue', 0xff, at index 16: 11111111 | // | 'dstValue' after in binary: 0..01110111100010000111011101110111 | // ---------------------------------------------------------------------------- // // dstValue = 0x77777777; // bdlb::BitStringImpUtil::xorEqBits(&dstValue, 16, 0xffff, 8); // assert(static_cast<uint64_t>(0x77887777) == dstValue); //.. // Finally, we apply the same function with a different value of 'srcValue' // and observe the result: //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::xorEqBits(&dstValue, 16, 0x5555, 8)' in binary: | // | | // | 'dstValue' before in binary: 0..01110111011101110111011101110111 | // | 'srcValue', 0x55, at index 16: 01010101 | // | 'dstValue' after in binary: 0..01110111001000100111011101110111 | // +--------------------------------------------------------------------------+ // // dstValue = 0x77777777; // bdlb::BitStringImpUtil::xorEqBits(&dstValue, 16, 0x5555, 8); // assert(static_cast<uint64_t>(0x77227777) == dstValue); //.. // ///Accessors ///- - - - - // This example demonstrates the "accessor" static functions, which read, but // do not modify, the state of a 'uint64_t'. // // The 'find1At(Max,Min)IndexRaw' routines are used for finding the // highest-order (or lowest-order) set bit in a 'uint64_t'. These functions // are "raw" because the behavior is undefined if they are passed 0. // // First, we apply 'find1AtMaxIndexRaw': //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::find1AtMaxIndexRaw(0x10a)' in binary: | // | | // | input: 0..000000000000000000000000100001010 | // | bit 8, highest bit set: 1 | // +--------------------------------------------------------------------------+ // // assert(8 == bdlb::BitStringImpUtil::find1AtMaxIndexRaw(0x10a)); //.. // Finally, we apply 'find1AtMinIndexRaw': //.. // +--------------------------------------------------------------------------+ // | 'bdlb::BitStringImpUtil::find1AtMinIndexRaw(0xffff0180)' in binary: | // | | // | input: 0..011111111111111110000000110000000 | // | bit 7, lowest bit set: 1 | // +--------------------------------------------------------------------------+ // // assert(7 == bdlb::BitStringImpUtil::find1AtMinIndexRaw(0xffff0180)); //.. #include <bdlscm_version.h> #include <bdlb_bitmaskutil.h> #include <bdlb_bitutil.h> #include <bsls_assert.h> #include <bsls_performancehint.h> #include <bsls_review.h> #include <bsl_cstdint.h> namespace BloombergLP { namespace bdlb { // ======================= // struct BitStringImpUtil // ======================= struct BitStringImpUtil { // This 'struct' provides a namespace for static functions to be used // solely in the implementation of 'BitStringUtil'. The "Manipulators" // are intended to be provided as arguments to templates in // 'bdlb_bitstringutil', whereas the "Accessors" are to be called directly // within that component. // PUBLIC TYPES enum { k_BITS_PER_UINT64 = 64 }; // number of bits in 'uint64_t' // CLASS METHODS // Manipulators static void andEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits); // Bitwise AND the specified least-significant 'numBits' in the // specified 'srcValue' to those in the specified 'dstValue' starting // at the specified 'dstIndex'. The behavior is undefined unless // '0 <= dstIndex', '0 <= numBits', and // 'dstIndex + numBits <= k_BITS_PER_UINT64'. static void andEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue); // Assign to the specified '*dstValue' the value of '*dstValue' bitwise // AND-ed with the specified 'srcValue'. static void minusEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits); // Bitwise MINUS the specified least-significant 'numBits' in the // specified 'srcValue' from those in the specified 'dstValue' starting // at the specified 'dstIndex'. The behavior is undefined unless // '0 <= dstIndex', '0 <= numBits', and // 'dstIndex + numBits <= k_BITS_PER_UINT64'. Note that the bitwise // difference, 'a - b', is defined in C++ code as 'a & ~b'. static void minusEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue); // Assign to the specified '*dstValue' the value of '*dstValue' bitwise // AND-ed with the complement of the specified 'srcValue'. static void orEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits); // Bitwise OR the specified least-significant 'numBits' in the // specified 'srcValue' to those in the specified 'dstValue' starting // at the specified 'dstIndex'. The behavior is undefined unless // '0 <= dstIndex', '0 <= numBits', and // 'dstIndex + numBits <= k_BITS_PER_UINT64'. static void orEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue); // Assign to the specified '*dstValue' the value of '*dstValue' bitwise // OR-ed with the specified 'srcValue'. static void setEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits); // Replace the specified 'numBits' in the specified 'dstValue' starting // at the specified 'dstIndex' with the least-significant 'numBits' of // the specified 'srcValue'. The behavior is undefined unless // '0 <= dstIndex', '0 <= numBits', and // 'dstIndex + numBits <= k_BITS_PER_UINT64'. static void setEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue); // Assign to the specified '*dstValue' the value of the specified // 'srcValue'. static void xorEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits); // Bitwise XOR the specified least-significant 'numBits' in the // specified 'srcValue' to those in the specified 'dstValue' starting // at the specified 'dstIndex'. The behavior is undefined unless // '0 <= dstIndex', '0 <= numBits', and // 'dstIndex + numBits <= k_BITS_PER_UINT64'. static void xorEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue); // Assign to the specified '*dstValue' the value of '*dstValue' bitwise // XOR-ed with the specified 'srcValue'. // Accessors static int find1AtMaxIndexRaw(bsl::uint64_t value); // Return the index of the highest-order set bit in the specified // non-zero 'value'. The behavior is undefined unless '0 != value'. // Note that this method is "raw" due to the requirement that at least // one bit in 'value' must be set. static int find1AtMinIndexRaw(bsl::uint64_t value); // Return the index of the lowest-order set bit in the specified // non-zero 'value'. The behavior is undefined unless '0 != value'. // Note that this method is "raw" due to the requirement that at least // one bit in 'value' must be set. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ----------------------- // struct BitStringImpUtil // ----------------------- // Manipulators inline void BitStringImpUtil::andEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits) { BSLS_ASSERT(dstValue); BSLS_ASSERT( 0 <= dstIndex); BSLS_ASSERT( 0 <= numBits); BSLS_ASSERT(dstIndex + numBits <= k_BITS_PER_UINT64); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(dstIndex < k_BITS_PER_UINT64)) { *dstValue &= BitMaskUtil::zero64(dstIndex, numBits) | (srcValue << dstIndex); } } inline void BitStringImpUtil::andEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue) { BSLS_ASSERT(dstValue); *dstValue &= srcValue; } inline void BitStringImpUtil::minusEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits) { BSLS_ASSERT(dstValue); BSLS_ASSERT( 0 <= dstIndex); BSLS_ASSERT( 0 <= numBits); BSLS_ASSERT(dstIndex + numBits <= k_BITS_PER_UINT64); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(dstIndex < k_BITS_PER_UINT64)) { *dstValue &= BitMaskUtil::zero64(dstIndex, numBits) | (~srcValue << dstIndex); } } inline void BitStringImpUtil::minusEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue) { BSLS_ASSERT(dstValue); *dstValue &= ~srcValue; } inline void BitStringImpUtil::orEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits) { BSLS_ASSERT(dstValue); BSLS_ASSERT( 0 <= dstIndex); BSLS_ASSERT( 0 <= numBits); BSLS_ASSERT(dstIndex + numBits <= k_BITS_PER_UINT64); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(dstIndex < k_BITS_PER_UINT64)) { *dstValue |= (srcValue & BitMaskUtil::lt64(numBits)) << dstIndex; } } inline void BitStringImpUtil::orEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue) { BSLS_ASSERT(dstValue); *dstValue |= srcValue; } inline void BitStringImpUtil::setEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits) { BSLS_ASSERT(dstValue); BSLS_ASSERT(0 <= dstIndex); BSLS_ASSERT(0 <= numBits); BSLS_ASSERT(dstIndex + numBits <= k_BITS_PER_UINT64); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(dstIndex < k_BITS_PER_UINT64)) { const bsl::uint64_t mask = BitMaskUtil::lt64(numBits); *dstValue &= ~(mask << dstIndex); *dstValue |= (srcValue & mask) << dstIndex; } } inline void BitStringImpUtil::setEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue) { BSLS_ASSERT(dstValue); *dstValue = srcValue; } inline void BitStringImpUtil::xorEqBits(bsl::uint64_t *dstValue, int dstIndex, bsl::uint64_t srcValue, int numBits) { BSLS_ASSERT(dstValue); BSLS_ASSERT( 0 <= dstIndex); BSLS_ASSERT( 0 <= numBits); BSLS_ASSERT(dstIndex + numBits <= k_BITS_PER_UINT64); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(dstIndex < k_BITS_PER_UINT64)) { *dstValue ^= (srcValue & BitMaskUtil::lt64(numBits)) << dstIndex; } } inline void BitStringImpUtil::xorEqWord(bsl::uint64_t *dstValue, bsl::uint64_t srcValue) { BSLS_ASSERT(dstValue); *dstValue ^= srcValue; } // Accessors inline int BitStringImpUtil::find1AtMaxIndexRaw(bsl::uint64_t value) { BSLS_ASSERT(0 != value); return k_BITS_PER_UINT64 - 1 - BitUtil::numLeadingUnsetBits(value); } inline int BitStringImpUtil::find1AtMinIndexRaw(bsl::uint64_t value) { BSLS_ASSERT(0 != value); return BitUtil::numTrailingUnsetBits(value); } } // 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 ----------------------------------