File indexing completed on 2024-06-02 05:05:36

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "bitset.h"
0007 #include <algorithm>
0008 #include <string.h>
0009 
0010 namespace bt
0011 {
0012 BitSet BitSet::null;
0013 
0014 BitSet::BitSet(Uint32 num_bits)
0015     : num_bits(num_bits)
0016     , data(nullptr)
0017 {
0018     num_bytes = (num_bits >> 3) + (((num_bits & 7) > 0) ? 1 : 0);
0019     data = new Uint8[num_bytes];
0020     std::fill(data, data + num_bytes, 0x00);
0021     num_on = 0;
0022 }
0023 
0024 BitSet::BitSet(const Uint8 *d, Uint32 num_bits)
0025     : num_bits(num_bits)
0026     , data(nullptr)
0027 {
0028     num_bytes = (num_bits >> 3) + (((num_bits & 7) > 0) ? 1 : 0);
0029     data = new Uint8[num_bytes];
0030     memcpy(data, d, num_bytes);
0031     num_on = 0;
0032     updateNumOnBits();
0033 }
0034 
0035 BitSet::BitSet(const BitSet &bs)
0036     : num_bits(bs.num_bits)
0037     , num_bytes(bs.num_bytes)
0038     , data(nullptr)
0039     , num_on(bs.num_on)
0040 {
0041     data = new Uint8[num_bytes];
0042     std::copy(bs.data, bs.data + num_bytes, data);
0043 }
0044 
0045 BitSet::~BitSet()
0046 {
0047     delete[] data;
0048 }
0049 
0050 void BitSet::updateNumOnBits()
0051 {
0052     num_on = 0;
0053     Uint32 i = 0;
0054     while (i < num_bytes) {
0055         num_on += BitCount[data[i]];
0056         i++;
0057     }
0058 }
0059 
0060 BitSet &BitSet::operator=(const BitSet &bs)
0061 {
0062     delete[] data;
0063     num_bytes = bs.num_bytes;
0064     num_bits = bs.num_bits;
0065     data = new Uint8[num_bytes];
0066     std::copy(bs.data, bs.data + num_bytes, data);
0067     num_on = bs.num_on;
0068     return *this;
0069 }
0070 
0071 const Uint8 tail_mask_lookup[8] = {0xFF, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F};
0072 
0073 void BitSet::invert()
0074 {
0075     if (num_bytes <= 0)
0076         return;
0077 
0078     num_on = 0;
0079     Uint32 i = 0;
0080     while (i < num_bytes - 1) {
0081         data[i] = ~data[i];
0082         num_on += BitCount[data[i]];
0083         i++;
0084     }
0085     // i == num_bytes-1
0086     data[i] = ~data[i] & tail_mask_lookup[num_bits & 7];
0087     num_on += BitCount[data[i]];
0088 }
0089 
0090 BitSet &BitSet::operator-=(const BitSet &bs)
0091 {
0092     num_on = 0;
0093     for (Uint32 i = 0; i < num_bytes; i++) {
0094         data[i] &= ~(data[i] & bs.data[i]);
0095         num_on += BitCount[data[i]];
0096     }
0097     return *this;
0098 }
0099 
0100 BitSet BitSet::operator-(const BitSet &bs) const
0101 {
0102     return BitSet(*this) -= bs;
0103 }
0104 
0105 void BitSet::setAll(bool on)
0106 {
0107     std::fill(data, data + num_bytes, on ? 0xFF : 0x00);
0108     num_on = on ? num_bits : 0;
0109 }
0110 
0111 void BitSet::clear()
0112 {
0113     setAll(false);
0114 }
0115 
0116 void BitSet::orBitSet(const BitSet &other)
0117 {
0118     num_on = 0;
0119 
0120     if (num_bits == other.num_bits) {
0121         // best case
0122         for (Uint32 i = 0; i < num_bytes; i++) {
0123             data[i] |= other.data[i];
0124             num_on += BitCount[data[i]];
0125         }
0126         return;
0127     }
0128 
0129     // process till the end of other data or last-1 byte in our data
0130     // whatether comes first
0131     for (Uint32 i = 0; i < qMin(num_bytes - 1, other.num_bytes); i++) {
0132         data[i] |= other.data[i];
0133         num_on += BitCount[data[i]];
0134     }
0135 
0136     // if last-1 not reached yet then the end of other data is reached
0137     // so just add BitCount till last-1 byte
0138     for (Uint32 i = other.num_bytes; i < num_bytes - 1; i++) {
0139         num_on += BitCount[data[i]];
0140     }
0141 
0142     // if other has matching byte for our last byte - OR it with proper mask
0143     if (other.num_bytes >= num_bytes) {
0144         data[num_bytes - 1] = (data[num_bytes - 1] | other.data[num_bytes - 1]) & tail_mask_lookup[num_bytes & 7];
0145     }
0146 
0147     // count bits set in last byte
0148     num_on += BitCount[data[num_bytes - 1]];
0149 }
0150 
0151 void BitSet::andBitSet(const BitSet &other)
0152 {
0153     num_on = 0;
0154 
0155     if (num_bits == other.num_bits) {
0156         // best case
0157         for (Uint32 i = 0; i < num_bytes; i++) {
0158             data[i] &= other.data[i];
0159             num_on += BitCount[data[i]];
0160         }
0161         return;
0162     }
0163 
0164     // we expect 0's at the tail of last byte (if any)
0165     // so just AND matching bytes and clear the others
0166     // no need to worry about mask for last byte
0167     for (Uint32 i = 0; i < qMin(num_bytes, other.num_bytes); i++) {
0168         data[i] &= other.data[i];
0169         num_on += BitCount[data[i]];
0170     }
0171 
0172     if (num_bytes > other.num_bytes) {
0173         memset(data + other.num_bytes, 0, num_bytes - other.num_bytes);
0174     }
0175 }
0176 
0177 bool BitSet::includesBitSet(const BitSet &other) const
0178 {
0179     if (num_bits == other.num_bits) {
0180         // best case
0181         for (Uint32 i = 0; i < num_bytes; i++) {
0182             if ((data[i] | other.data[i]) != data[i]) {
0183                 return false;
0184             }
0185         }
0186         return true;
0187     }
0188 
0189     // process till the end of other data or last-1 byte in our data
0190     // whatether comes first
0191     for (Uint32 i = 0; i < qMin(num_bytes - 1, other.num_bytes); i++) {
0192         if ((data[i] | other.data[i]) != data[i]) {
0193             return false;
0194         }
0195     }
0196 
0197     // if other has matching byte for our last byte - OR it with proper mask
0198     if (other.num_bytes >= num_bytes) {
0199         const Uint8 d = data[num_bytes - 1];
0200         if (((d | other.data[num_bytes - 1]) & tail_mask_lookup[num_bytes & 7]) != d) {
0201             return false;
0202         }
0203     }
0204 
0205     return true;
0206 }
0207 
0208 bool BitSet::allOn() const
0209 {
0210     return num_on == num_bits;
0211 }
0212 
0213 bool BitSet::operator==(const BitSet &bs) const
0214 {
0215     if (this->getNumBits() != bs.getNumBits())
0216         return false;
0217 
0218     return memcmp(data, bs.data, num_bytes) == 0;
0219 }
0220 }