Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbitarray.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2019 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qbitarray.h"
6#include <qalgorithms.h>
7#include <qdatastream.h>
8#include <qdebug.h>
9#include <qendian.h>
10
11#include <limits>
12
13#include <string.h>
14
16
82#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
91#endif
92
100/*
101 * QBitArray construction note:
102 *
103 * We overallocate the byte array by 1 byte. The first user bit is at
104 * d.data()[1]. On the extra first byte, we store the difference between the
105 * number of bits in the byte array (including this byte) and the number of
106 * bits in the bit array. Therefore, for a non-empty QBitArray, it's always a
107 * number between 8 and 15. For the empty one, d is the an empty QByteArray and
108 * *d.constData() is the QByteArray's terminating NUL (0) byte.
109 *
110 * This allows for fast calculation of the bit array size:
111 * inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
112 */
113
115{
116 // avoid overflow when adding 7, by doing the arithmetic in unsigned space:
117 return qsizetype((size_t(size) + 7) / 8);
118}
119
121{
122 return size <= 0 ? 0 : storage_size(size) + 1;
123}
124
125static void adjust_head_and_tail(char *data, qsizetype storageSize, qsizetype logicalSize)
126{
127 quint8 *c = reinterpret_cast<quint8 *>(data);
128 // store the difference between storage and logical size in d[0]:
129 *c = quint8(size_t(storageSize) * 8 - logicalSize);
130 // reset unallocated bits to 0:
131 if (logicalSize & 7)
132 *(c + 1 + logicalSize / 8) &= (1 << (logicalSize & 7)) - 1;
133}
134
140 : d(allocation_size(size), value ? 0xFF : 0x00)
141{
142 Q_ASSERT_X(size >= 0, "QBitArray::QBitArray", "Size must be greater than or equal to 0.");
143 if (size <= 0)
144 return;
145
147}
148
167{
168 qsizetype numBits = 0;
169 const quint8 *bits = reinterpret_cast<const quint8 *>(d.data()) + 1;
170
171 // the loops below will try to read from *end
172 // it's the QByteArray implicit NUL, so it will not change the bit count
173 const quint8 *const end = reinterpret_cast<const quint8 *>(d.end());
174
175 while (bits + 7 <= end) {
176 quint64 v = qFromUnaligned<quint64>(bits);
177 bits += 8;
178 numBits += qsizetype(qPopulationCount(v));
179 }
180 if (bits + 3 <= end) {
181 quint32 v = qFromUnaligned<quint32>(bits);
182 bits += 4;
183 numBits += qsizetype(qPopulationCount(v));
184 }
185 if (bits + 1 < end) {
186 quint16 v = qFromUnaligned<quint16>(bits);
187 bits += 2;
188 numBits += qsizetype(qPopulationCount(v));
189 }
190 if (bits < end)
191 numBits += qsizetype(qPopulationCount(bits[0]));
192
193 return on ? numBits : size() - numBits;
194}
195
209{
210 Q_ASSERT_X(size >= 0, "QBitArray::resize", "Size must be greater than or equal to 0.");
211 if (size <= 0) {
212 d.resize(0);
213 } else {
214 d.resize(allocation_size(size), 0x00);
216 }
217}
218
272{
273 while (begin < end && begin & 0x7)
274 setBit(begin++, value);
276 if (len <= 0)
277 return;
278 qsizetype s = len & ~qsizetype(0x7);
279 uchar *c = reinterpret_cast<uchar *>(d.data());
280 memset(c + (begin >> 3) + 1, value ? 0xff : 0, s >> 3);
281 begin += s;
282 while (begin < end)
283 setBit(begin++, value);
284}
285
310{
311 Q_ASSERT_X(size >= 0, "QBitArray::fromBits", "Size must be greater than or equal to 0.");
313 if (size <= 0)
314 return result;
315
316 auto &d = result.d;
318 memcpy(d.data() + 1, data, d.size() - 1);
320 return result;
321}
322
332quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcept
333{
334 const qsizetype _size = size();
335 if (_size > 32) {
336 if (ok)
337 *ok = false;
338 return 0;
339 }
340
341 if (ok)
342 *ok = true;
343
344 quint32 factor = 1;
345 quint32 total = 0;
346 for (qsizetype i = 0; i < _size; ++i, factor *= 2) {
347 const auto index = endianness == QSysInfo::Endian::LittleEndian ? i : (_size - i - 1);
348 if (testBit(index))
349 total += factor;
350 }
351
352 return total;
353}
354
470#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
495#endif // Qt 6
496
520// Returns a new QBitArray that has the same size as the bigger of \a a1 and
521// \a a2, but whose contents are uninitialized.
523{
525 const QByteArrayData &d1 = a1.data_ptr();
526 const QByteArrayData &d2 = a2.data_ptr();
527 qsizetype n1 = d1.size;
528 qsizetype n2 = d2.size;
529 qsizetype n = qMax(n1, n2);
530
531 QByteArrayData bytes(n, n);
532
533 // initialize the count of bits in the last byte (see construction note)
534 if (n1 > n2)
535 *bytes.ptr = *d1.ptr;
536 else if (n2 > n1)
537 *bytes.ptr = *d2.ptr;
538 else if (n1) // n1 == n2
539 *bytes.ptr = qMin(*d1.ptr, *d2.ptr);
540
541 result.data_ptr() = std::move(bytes);
542 return result;
543}
544
545template <typename BitwiseOp> static Q_NEVER_INLINE
547 const QBitArray &a2, BitwiseOp op)
548{
549 const QByteArrayData &d1 = a1.data_ptr();
550 const QByteArrayData &d2 = a2.data_ptr();
551
552 // Sizes in bytes (including the initial bit difference counter)
553 qsizetype n1 = d1.size;
554 qsizetype n2 = d2.size;
555 Q_ASSERT(out.data_ptr().size == qMax(n1, n2));
556 Q_ASSERT(out.data_ptr().size == 0 || !out.data_ptr().needsDetach());
557
558 // Bypass QByteArray's emptiness verification; we won't dereference
559 // these pointers if their size is zero.
560 auto dst = reinterpret_cast<uchar *>(out.data_ptr().data());
561 auto p1 = reinterpret_cast<const uchar *>(d1.data());
562 auto p2 = reinterpret_cast<const uchar *>(d2.data());
563
564 // Main: perform the operation in the range where both arrays have data
565 if (n1 < n2) {
566 std::swap(n1, n2);
567 std::swap(p1, p2);
568 }
569 for (qsizetype i = 1; i < n2; ++i)
570 dst[i] = op(p1[i], p2[i]);
571
572 // Tail: operate as if both arrays had the same data by padding zeroes to
573 // the end of the shorter of the two (for std::bit_or and std::bit_xor, this is
574 // a memmove; for std::bit_and, it's memset to 0).
575 for (qsizetype i = qMax(n2, qsizetype(1)); i < n1; ++i)
576 dst[i] = op(p1[i], uchar(0));
577
578 return out;
579}
580
581template <typename BitwiseOp> static Q_NEVER_INLINE
583{
584 QBitArray tmp(std::move(self));
585 self = sizedForOverwrite(tmp, other);
586 return performBitwiseOperationHelper(self, tmp, other, op);
587}
588
589template <typename BitwiseOp> static Q_NEVER_INLINE
591{
592 if (self.size() < other.size())
593 self.resize(other.size());
594 return performBitwiseOperationHelper(self, self, other, op);
595}
596
597template <typename BitwiseOp> static
599{
600 if (self.data_ptr().needsDetach())
601 return performBitwiseOperationInCopy(self, other, op);
602 return performBitwiseOperationInPlace(self, other, op);
603}
604
605// SCARY helper
606enum { InCopy, InPlace };
608{
609 QByteArrayData &d1 = self.data_ptr();
610 QByteArrayData &d2 = other.data_ptr();
611 bool detached1 = !d1.needsDetach();
612 bool detached2 = !d2.needsDetach();
613 if (!detached1 && !detached2)
614 return InCopy;
615
616 // at least one of the two is detached, we'll reuse its buffer
617 bool swap = false;
618 if (detached1 && detached2) {
619 // both are detached, so choose the larger of the two
620 swap = d1.allocatedCapacity() < d2.allocatedCapacity();
621 } else if (detached2) {
622 // we can re-use other's buffer but not self's, so swap the two
623 swap = true;
624 }
625 if (swap)
626 self.swap(other);
627 return InPlace;
628}
629
630template <typename BitwiseOp> static
632{
633 auto choice = prepareForBitwiseOperation(self, other);
634 if (choice == InCopy)
635 return performBitwiseOperationInCopy(self, other, std::move(op));
636 return performBitwiseOperationInPlace(self, other, std::move(op));
637}
638
658{
659 return performBitwiseOperation(*this, other, std::bit_and<uchar>());
660}
661
663{
664 return performBitwiseOperation(*this, other, std::bit_and<uchar>());
665}
666
686{
687 return performBitwiseOperation(*this, other, std::bit_or<uchar>());
688}
689
691{
692 return performBitwiseOperation(*this, other, std::bit_or<uchar>());
693}
694
714{
715 return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
716}
717
719{
720 return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
721}
722
734Q_NEVER_INLINE QBitArray QBitArray::inverted_inplace() &&
735{
736 qsizetype n = d.size();
737 uchar *dst = reinterpret_cast<uchar *>(data_ptr().data());
738 const uchar *src = dst;
739 QBitArray result([&] {
740 if (d.isDetached() || n == 0)
741 return std::move(d.data_ptr()); // invert in-place
742
743 QByteArrayData tmp(n, n);
744 dst = reinterpret_cast<uchar *>(tmp.data());
745 return tmp;
746 }());
747
748 uchar bitdiff = 8;
749 if (n)
750 bitdiff = dst[0] = src[0]; // copy the count of bits in the last byte
751
752 for (qsizetype i = 1; i < n; ++i)
753 dst[i] = ~src[i];
754
755 if (int tailCount = 16 - bitdiff; tailCount != 8) {
756 // zero the bits beyond our size in the last byte
757 Q_ASSERT(n > 1);
758 uchar tailMask = (1U << tailCount) - 1;
759 dst[n - 1] &= tailMask;
760 }
761
762 return result;
763}
764
785{
787 performBitwiseOperationHelper(tmp, a1, a2, std::bit_and<uchar>());
788 return tmp;
789}
790
811{
813 performBitwiseOperationHelper(tmp, a1, a2, std::bit_or<uchar>());
814 return tmp;
815}
816
837{
839 performBitwiseOperationHelper(tmp, a1, a2, std::bit_xor<uchar>());
840 return tmp;
841}
842
884/*****************************************************************************
885 QBitArray stream functions
886 *****************************************************************************/
887
888#ifndef QT_NO_DATASTREAM
898{
899 const qsizetype len = ba.size();
900 if (out.version() < QDataStream::Qt_6_0) {
901 if (Q_UNLIKELY(len > qsizetype{(std::numeric_limits<qint32>::max)()})) {
902 out.setStatus(QDataStream::Status::SizeLimitExceeded);
903 return out;
904 }
905 out << quint32(len);
906 } else {
907 out << quint64(len);
908 }
909 if (len > 0)
910 out.writeRawData(ba.d.data() + 1, ba.d.size() - 1);
911 return out;
912}
913
923{
924 ba.clear();
926 if (in.version() < QDataStream::Qt_6_0) {
927 quint32 tmp;
928 in >> tmp;
929 if (Q_UNLIKELY(tmp > quint32((std::numeric_limits<qint32>::max)()))) {
930 in.setStatus(QDataStream::ReadCorruptData);
931 return in;
932 }
933 len = tmp;
934 } else {
935 quint64 tmp;
936 in >> tmp;
937 if (Q_UNLIKELY(tmp > quint64((std::numeric_limits<qsizetype>::max)()))) {
938 in.setStatus(QDataStream::Status::SizeLimitExceeded);
939 return in;
940 }
941 len = tmp;
942 }
943 if (len == 0) {
944 ba.clear();
945 return in;
946 }
947
948 const qsizetype Step = 8 * 1024 * 1024;
949 const qsizetype totalBytes = storage_size(len);
950 qsizetype allocated = 0;
951
952 while (allocated < totalBytes) {
953 qsizetype blockSize = qMin(Step, totalBytes - allocated);
954 ba.d.resize(allocated + blockSize + 1);
955 if (in.readRawData(ba.d.data() + 1 + allocated, blockSize) != blockSize) {
956 ba.clear();
957 in.setStatus(QDataStream::ReadPastEnd);
958 return in;
959 }
960 allocated += blockSize;
961 }
962
963 const auto fromStream = ba.d.back();
965 if (ba.d.back() != fromStream) {
966 ba.clear();
967 in.setStatus(QDataStream::ReadCorruptData);
968 return in;
969 }
970 return in;
971}
972#endif // QT_NO_DATASTREAM
973
974#ifndef QT_NO_DEBUG_STREAM
976{
977 QDebugStateSaver saver(dbg);
978 dbg.nospace() << "QBitArray(";
979 for (qsizetype i = 0; i < array.size();) {
980 if (array.testBit(i))
981 dbg << '1';
982 else
983 dbg << '0';
984 i += 1;
985 if (!(i % 4) && (i < array.size()))
986 dbg << ' ';
987 }
988 dbg << ')';
989 return dbg;
990}
991#endif
992
\inmodule QtCore
Definition qbitarray.h:13
QBitArray & operator&=(QBitArray &&)
Performs the AND operation between all bits in this bit array and other.
bool fill(bool aval, qsizetype asize=-1)
Sets every bit in the bit array to value, returning true if successful; otherwise returns false.
Definition qbitarray.h:124
qsizetype count() const
Same as size().
Definition qbitarray.h:77
void setBit(qsizetype i)
Sets the bit at index position i to 1.
Definition qbitarray.h:91
QBitArray & operator|=(QBitArray &&)
Performs the OR operation between all bits in this bit array and other.
void resize(qsizetype size)
Resizes the bit array to size bits.
static QBitArray fromBits(const char *data, qsizetype len)
quint32 toUInt32(QSysInfo::Endian endianness, bool *ok=nullptr) const noexcept
qsizetype size() const
Returns the number of bits stored in the bit array.
Definition qbitarray.h:76
QBitArray() noexcept
Constructs an empty bit array.
Definition qbitarray.h:64
QBitArray & operator^=(QBitArray &&)
Performs the XOR operation between all bits in this bit array and other.
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last byte in the byte-...
Definition qbytearray.h:447
void clear()
Clears the contents of the byte array and makes it null.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
\inmodule QtCore
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
void swap(QString &other) noexcept
Definition qstring.h:185
DataPointer & data_ptr()
Definition qstring.h:1093
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2668
Endian
\value BigEndian Big-endian byte order (also called Network byte order) \value LittleEndian Little-en...
Definition qsysinfo.h:28
@ LittleEndian
Definition qsysinfo.h:30
QPixmap p2
QPixmap p1
[0]
Combined button and popup list for selecting options.
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
const int blockSize
static constexpr qsizetype storage_size(qsizetype size)
static QBitArray sizedForOverwrite(const QBitArray &a1, const QBitArray &a2)
QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
static constexpr qsizetype allocation_size(qsizetype size)
static void adjust_head_and_tail(char *data, qsizetype storageSize, qsizetype logicalSize)
static Q_NEVER_INLINE QBitArray & performBitwiseOperationHelper(QBitArray &out, const QBitArray &a1, const QBitArray &a2, BitwiseOp op)
static Q_NEVER_INLINE QBitArray & performBitwiseOperationInPlace(QBitArray &self, const QBitArray &other, BitwiseOp op)
QDebug operator<<(QDebug dbg, const QBitArray &array)
QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
static auto prepareForBitwiseOperation(QBitArray &self, QBitArray &other)
@ InCopy
@ InPlace
QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
static QBitArray & performBitwiseOperation(QBitArray &self, const QBitArray &other, BitwiseOp op)
static Q_NEVER_INLINE QBitArray & performBitwiseOperationInCopy(QBitArray &self, const QBitArray &other, BitwiseOp op)
#define Q_UNLIKELY(x)
#define Q_NEVER_INLINE
static bool testBit(long bit, const long *field)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum src
GLenum GLenum dst
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLenum array
GLuint in
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLuint64EXT * result
[6]
GLenum GLsizei len
const void * data_ptr(const QTransform &t)
Definition qpainter_p.h:48
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define a2
#define a1
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned char quint8
Definition qtypes.h:46
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QDataStream & operator>>(QDataStream &in, MyClass &myObj)
QDate d1(1995, 5, 17)
[0]
QDate d2(1995, 5, 20)
QSharedPointer< T > other(t)
[5]
this swap(other)
bool needsDetach() const noexcept