From 5a47e04b52fac3f975f2e7912afde6eae3e6c904 Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Thu, 17 Aug 2017 21:18:31 +0000 Subject: [PATCH] Revamped C++ BitBuffer code to be based on std::vector, updated dependent code. --- cpp/BitBuffer.cpp | 37 ++++++++----------------------------- cpp/BitBuffer.hpp | 20 ++------------------ cpp/QrCode.cpp | 13 +++++++------ cpp/QrSegment.cpp | 4 ++-- 4 files changed, 19 insertions(+), 55 deletions(-) diff --git a/cpp/BitBuffer.cpp b/cpp/BitBuffer.cpp index 058b5d3..3ed13a4 100644 --- a/cpp/BitBuffer.cpp +++ b/cpp/BitBuffer.cpp @@ -27,44 +27,23 @@ namespace qrcodegen { -BitBuffer::BitBuffer() : - data(), - bitLength(0) {} - - -int BitBuffer::getBitLength() const { - return bitLength; -} +BitBuffer::BitBuffer() + : std::vector() {} std::vector BitBuffer::getBytes() const { - return data; + std::vector result((size() + 7) / 8); + for (std::size_t i = 0; i < size(); i++) + result[i >> 3] |= (*this)[i] ? 1 << (7 - (i & 7)) : 0; + return result; } void BitBuffer::appendBits(std::uint32_t val, int len) { if (len < 0 || len > 32 || (len < 32 && (val >> len) != 0)) throw "Value out of range"; - if (len > INT_MAX - bitLength) - throw "Buffer too long"; - unsigned int newByteLen = ((unsigned int)bitLength + len + 7) / 8; - while (data.size() < newByteLen) - data.push_back(0); - for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit - data.at(bitLength >> 3) |= ((val >> i) & 1) << (7 - (bitLength & 7)); -} - - -void BitBuffer::appendData(const QrSegment &seg) { - if (seg.bitLength > INT_MAX - bitLength) - throw "Buffer too long"; - unsigned int newByteLen = ((unsigned int)bitLength + seg.bitLength + 7) / 8; - while (data.size() < newByteLen) - data.push_back(0); - for (int i = 0; i < seg.bitLength; i++, bitLength++) { // Append bit by bit - int bit = (seg.data.at(i >> 3) >> (7 - (i & 7))) & 1; - data.at(bitLength >> 3) |= bit << (7 - (bitLength & 7)); - } + for (int i = len - 1; i >= 0; i--) // Append bit by bit + this->push_back(((val >> i) & 1) != 0); } } diff --git a/cpp/BitBuffer.hpp b/cpp/BitBuffer.hpp index f91e428..2e6e673 100644 --- a/cpp/BitBuffer.hpp +++ b/cpp/BitBuffer.hpp @@ -25,7 +25,6 @@ #include #include -#include "QrSegment.hpp" namespace qrcodegen { @@ -33,14 +32,7 @@ namespace qrcodegen { /* * An appendable sequence of bits. Bits are packed in big endian within a byte. */ -class BitBuffer final { - - /*---- Fields ----*/ - - private: std::vector data; - private: int bitLength; - - +class BitBuffer final : public std::vector { /*---- Constructor ----*/ @@ -51,11 +43,7 @@ class BitBuffer final { /*---- Methods ----*/ - // Returns the number of bits in the buffer, which is a non-negative value. - public: int getBitLength() const; - - - // Returns a copy of all bytes, padding up to the nearest byte. + // Returns a copy of all bytes, padding up to the nearest byte. Bits are packed in big endian within a byte. public: std::vector getBytes() const; @@ -63,10 +51,6 @@ class BitBuffer final { // If 0 <= len <= 31, then this requires 0 <= val < 2^len. public: void appendBits(std::uint32_t val, int len); - - // Appends the data of the given segment to this bit buffer. - public: void appendData(const QrSegment &seg); - }; } diff --git a/cpp/QrCode.cpp b/cpp/QrCode.cpp index 717018b..ea94a6c 100644 --- a/cpp/QrCode.cpp +++ b/cpp/QrCode.cpp @@ -88,22 +88,23 @@ QrCode QrCode::encodeSegments(const vector &segs, const Ecc &ecl, } // Create the data bit string by concatenating all segments - int dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8; + size_t dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8; BitBuffer bb; for (const QrSegment &seg : segs) { bb.appendBits(seg.mode.modeBits, 4); bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version)); - bb.appendData(seg); + for (int i = 0; i < seg.bitLength; i++) + bb.push_back(((seg.data.at(i >> 3) >> (7 - (i & 7))) & 1) != 0); } // Add terminator and pad up to a byte if applicable - bb.appendBits(0, std::min(4, dataCapacityBits - bb.getBitLength())); - bb.appendBits(0, (8 - bb.getBitLength() % 8) % 8); + bb.appendBits(0, std::min(static_cast(4), dataCapacityBits - bb.size())); + bb.appendBits(0, (8 - bb.size() % 8) % 8); // Pad with alternate bytes until data capacity is reached - for (uint8_t padByte = 0xEC; bb.getBitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) bb.appendBits(padByte, 8); - if (bb.getBitLength() % 8 != 0) + if (bb.size() % 8 != 0) throw "Assertion error"; // Create the QR Code symbol diff --git a/cpp/QrSegment.cpp b/cpp/QrSegment.cpp index b05c7e8..f46f950 100644 --- a/cpp/QrSegment.cpp +++ b/cpp/QrSegment.cpp @@ -83,7 +83,7 @@ QrSegment QrSegment::makeNumeric(const char *digits) { } if (accumCount > 0) // 1 or 2 digits remaining bb.appendBits(accumData, accumCount * 3 + 1); - return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.getBitLength()); + return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.size()); } @@ -106,7 +106,7 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) { } if (accumCount > 0) // 1 character remaining bb.appendBits(accumData, 6); - return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.getBitLength()); + return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.size()); }