44QrSegment::Mode::Mode(
int mode,
int cc0,
int cc1,
int cc2) :
46 numBitsCharCount[0] = cc0;
47 numBitsCharCount[1] = cc1;
48 numBitsCharCount[2] = cc2;
52int QrSegment::Mode::getModeBits()
const {
57int QrSegment::Mode::numCharCountBits(
int ver)
const {
58 return numBitsCharCount[(ver + 7) / 17];
62const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
63const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
64const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
65const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
66const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
69QrSegment QrSegment::makeBytes(
const vector<uint8_t> &data) {
70 if (data.size() >
static_cast<unsigned int>(INT_MAX))
71 throw std::length_error(
"Data too long");
73 for (uint8_t b : data)
75 return QrSegment(Mode::BYTE,
static_cast<int>(data.size()), std::move(bb));
79QrSegment QrSegment::makeNumeric(
const char *digits) {
84 for (; *digits !=
'\0'; digits++, charCount++) {
86 if (c <
'0' || c >
'9')
87 throw std::domain_error(
"String contains non-numeric characters");
88 accumData = accumData * 10 + (c -
'0');
90 if (accumCount == 3) {
91 bb.appendBits(
static_cast<uint32_t
>(accumData), 10);
97 bb.appendBits(
static_cast<uint32_t
>(accumData), accumCount * 3 + 1);
98 return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
102QrSegment QrSegment::makeAlphanumeric(
const char *text) {
107 for (; *text !=
'\0'; text++, charCount++) {
108 const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
110 throw std::domain_error(
"String contains unencodable characters in alphanumeric mode");
111 accumData = accumData * 45 +
static_cast<int>(temp - ALPHANUMERIC_CHARSET);
113 if (accumCount == 2) {
114 bb.appendBits(
static_cast<uint32_t
>(accumData), 11);
120 bb.appendBits(
static_cast<uint32_t
>(accumData), 6);
121 return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
125vector<QrSegment> QrSegment::makeSegments(
const char *text) {
127 vector<QrSegment> result;
129 else if (isNumeric(text))
130 result.push_back(makeNumeric(text));
131 else if (isAlphanumeric(text))
132 result.push_back(makeAlphanumeric(text));
134 vector<uint8_t> bytes;
135 for (; *text !=
'\0'; text++)
136 bytes.push_back(
static_cast<uint8_t
>(*text));
137 result.push_back(makeBytes(bytes));
143QrSegment QrSegment::makeEci(
long assignVal) {
146 throw std::domain_error(
"ECI assignment value out of range");
147 else if (assignVal < (1 << 7))
148 bb.appendBits(
static_cast<uint32_t
>(assignVal), 8);
149 else if (assignVal < (1 << 14)) {
151 bb.appendBits(
static_cast<uint32_t
>(assignVal), 14);
152 }
else if (assignVal < 1000000L) {
154 bb.appendBits(
static_cast<uint32_t
>(assignVal), 21);
156 throw std::domain_error(
"ECI assignment value out of range");
157 return QrSegment(Mode::ECI, 0, std::move(bb));
161QrSegment::QrSegment(
const Mode &md,
int numCh,
const std::vector<bool> &dt) :
166 throw std::domain_error(
"Invalid value");
170QrSegment::QrSegment(
const Mode &md,
int numCh, std::vector<bool> &&dt) :
173 data(std::move(dt)) {
175 throw std::domain_error(
"Invalid value");
179int QrSegment::getTotalBits(
const vector<QrSegment> &segs,
int version) {
181 for (
const QrSegment &seg : segs) {
182 int ccbits = seg.mode->numCharCountBits(version);
183 if (seg.numChars >= (1L << ccbits))
185 if (4 + ccbits > INT_MAX - result)
187 result += 4 + ccbits;
188 if (seg.data.size() >
static_cast<unsigned int>(INT_MAX - result))
190 result +=
static_cast<int>(seg.data.size());
196bool QrSegment::isNumeric(
const char *text) {
197 for (; *text !=
'\0'; text++) {
199 if (c <
'0' || c >
'9')
206bool QrSegment::isAlphanumeric(
const char *text) {
207 for (; *text !=
'\0'; text++) {
208 if (std::strchr(ALPHANUMERIC_CHARSET, *text) ==
nullptr)
215const QrSegment::Mode &QrSegment::getMode()
const {
220int QrSegment::getNumChars()
const {
225const std::vector<bool> &QrSegment::getData()
const {
230const char *QrSegment::ALPHANUMERIC_CHARSET =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
236int QrCode::getFormatBits(Ecc ecl) {
238 case Ecc::LOW :
return 1;
239 case Ecc::MEDIUM :
return 0;
240 case Ecc::QUARTILE:
return 3;
241 case Ecc::HIGH :
return 2;
242 default:
throw std::logic_error(
"Unreachable");
247QrCode QrCode::encodeText(
const char *text, Ecc ecl) {
248 vector<QrSegment> segs = QrSegment::makeSegments(text);
249 return encodeSegments(segs, ecl);
253QrCode QrCode::encodeBinary(
const vector<uint8_t> &data, Ecc ecl) {
254 vector<QrSegment> segs{QrSegment::makeBytes(data)};
255 return encodeSegments(segs, ecl);
259QrCode QrCode::encodeSegments(
const vector<QrSegment> &segs, Ecc ecl,
260 int minVersion,
int maxVersion,
int mask,
bool boostEcl) {
261 if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
262 throw std::invalid_argument(
"Invalid value");
265 int version, dataUsedBits;
266 for (version = minVersion; ; version++) {
267 int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
268 dataUsedBits = QrSegment::getTotalBits(segs, version);
269 if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
271 if (version >= maxVersion) {
272 std::ostringstream sb;
273 if (dataUsedBits == -1)
274 sb <<
"Segment too long";
276 sb <<
"Data length = " << dataUsedBits <<
" bits, ";
277 sb <<
"Max capacity = " << dataCapacityBits <<
" bits";
279 throw data_too_long(sb.str());
282 assert(dataUsedBits != -1);
285 for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) {
286 if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
292 for (
const QrSegment &seg : segs) {
293 bb.appendBits(
static_cast<uint32_t
>(seg.getMode().getModeBits()), 4);
294 bb.appendBits(
static_cast<uint32_t
>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
295 bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
297 assert(bb.size() ==
static_cast<unsigned int>(dataUsedBits));
300 size_t dataCapacityBits =
static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
301 assert(bb.size() <= dataCapacityBits);
302 bb.appendBits(0, std::min(4,
static_cast<int>(dataCapacityBits - bb.size())));
303 bb.appendBits(0, (8 -
static_cast<int>(bb.size() % 8)) % 8);
304 assert(bb.size() % 8 == 0);
307 for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
308 bb.appendBits(padByte, 8);
311 vector<uint8_t> dataCodewords(bb.size() / 8);
312 for (
size_t i = 0; i < bb.size(); i++)
313 dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
316 return QrCode(version, ecl, dataCodewords, mask);
320QrCode::QrCode(
int ver, Ecc ecl,
const vector<uint8_t> &dataCodewords,
int msk) :
323 errorCorrectionLevel(ecl) {
324 if (ver < MIN_VERSION || ver > MAX_VERSION)
325 throw std::domain_error(
"Version value out of range");
326 if (msk < -1 || msk > 7)
327 throw std::domain_error(
"Mask value out of range");
329 size_t sz =
static_cast<size_t>(size);
330 modules = vector<vector<bool> >(sz, vector<bool>(sz));
331 isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
334 drawFunctionPatterns();
335 const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
336 drawCodewords(allCodewords);
340 long minPenalty = LONG_MAX;
341 for (
int i = 0; i < 8; i++) {
344 long penalty = getPenaltyScore();
345 if (penalty < minPenalty) {
347 minPenalty = penalty;
352 assert(0 <= msk && msk <= 7);
358 isFunction.shrink_to_fit();
362int QrCode::getVersion()
const {
367int QrCode::getSize()
const {
372QrCode::Ecc QrCode::getErrorCorrectionLevel()
const {
373 return errorCorrectionLevel;
377int QrCode::getMask()
const {
382bool QrCode::getModule(
int x,
int y)
const {
383 return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
387void QrCode::drawFunctionPatterns() {
389 for (
int i = 0; i < size; i++) {
390 setFunctionModule(6, i, i % 2 == 0);
391 setFunctionModule(i, 6, i % 2 == 0);
395 drawFinderPattern(3, 3);
396 drawFinderPattern(size - 4, 3);
397 drawFinderPattern(3, size - 4);
400 const vector<int> alignPatPos = getAlignmentPatternPositions();
401 size_t numAlign = alignPatPos.size();
402 for (
size_t i = 0; i < numAlign; i++) {
403 for (
size_t j = 0; j < numAlign; j++) {
405 if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
406 drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
416void QrCode::drawFormatBits(
int msk) {
418 int data = getFormatBits(errorCorrectionLevel) << 3 | msk;
420 for (
int i = 0; i < 10; i++)
421 rem = (rem << 1) ^ ((rem >> 9) * 0x537);
422 int bits = (data << 10 | rem) ^ 0x5412;
423 assert(bits >> 15 == 0);
426 for (
int i = 0; i <= 5; i++)
427 setFunctionModule(8, i, getBit(bits, i));
428 setFunctionModule(8, 7, getBit(bits, 6));
429 setFunctionModule(8, 8, getBit(bits, 7));
430 setFunctionModule(7, 8, getBit(bits, 8));
431 for (
int i = 9; i < 15; i++)
432 setFunctionModule(14 - i, 8, getBit(bits, i));
435 for (
int i = 0; i < 8; i++)
436 setFunctionModule(size - 1 - i, 8, getBit(bits, i));
437 for (
int i = 8; i < 15; i++)
438 setFunctionModule(8, size - 15 + i, getBit(bits, i));
439 setFunctionModule(8, size - 8,
true);
443void QrCode::drawVersion() {
449 for (
int i = 0; i < 12; i++)
450 rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
451 long bits =
static_cast<long>(version) << 12 | rem;
452 assert(bits >> 18 == 0);
455 for (
int i = 0; i < 18; i++) {
456 bool bit = getBit(bits, i);
457 int a = size - 11 + i % 3;
459 setFunctionModule(a, b, bit);
460 setFunctionModule(b, a, bit);
465void QrCode::drawFinderPattern(
int x,
int y) {
466 for (
int dy = -4; dy <= 4; dy++) {
467 for (
int dx = -4; dx <= 4; dx++) {
468 int dist = std::max(std::abs(dx), std::abs(dy));
469 int xx = x + dx, yy = y + dy;
470 if (0 <= xx && xx < size && 0 <= yy && yy < size)
471 setFunctionModule(xx, yy, dist != 2 && dist != 4);
477void QrCode::drawAlignmentPattern(
int x,
int y) {
478 for (
int dy = -2; dy <= 2; dy++) {
479 for (
int dx = -2; dx <= 2; dx++)
480 setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
485void QrCode::setFunctionModule(
int x,
int y,
bool isDark) {
486 size_t ux =
static_cast<size_t>(x);
487 size_t uy =
static_cast<size_t>(y);
488 modules .at(uy).at(ux) = isDark;
489 isFunction.at(uy).at(ux) =
true;
493bool QrCode::module(
int x,
int y)
const {
494 return modules.at(
static_cast<size_t>(y)).at(
static_cast<size_t>(x));
498vector<uint8_t> QrCode::addEccAndInterleave(
const vector<uint8_t> &data)
const {
499 if (data.size() !=
static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
500 throw std::invalid_argument(
"Invalid argument");
503 int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[
static_cast<int>(errorCorrectionLevel)][version];
504 int blockEccLen = ECC_CODEWORDS_PER_BLOCK [
static_cast<int>(errorCorrectionLevel)][version];
505 int rawCodewords = getNumRawDataModules(version) / 8;
506 int numShortBlocks = numBlocks - rawCodewords % numBlocks;
507 int shortBlockLen = rawCodewords / numBlocks;
510 vector<vector<uint8_t> > blocks;
511 const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
512 for (
int i = 0, k = 0; i < numBlocks; i++) {
513 vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
514 k +=
static_cast<int>(dat.size());
515 const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
516 if (i < numShortBlocks)
518 dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
519 blocks.push_back(std::move(dat));
523 vector<uint8_t> result;
524 for (
size_t i = 0; i < blocks.at(0).size(); i++) {
525 for (
size_t j = 0; j < blocks.size(); j++) {
527 if (i !=
static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >=
static_cast<unsigned int>(numShortBlocks))
528 result.push_back(blocks.at(j).at(i));
531 assert(result.size() ==
static_cast<unsigned int>(rawCodewords));
536void QrCode::drawCodewords(
const vector<uint8_t> &data) {
537 if (data.size() !=
static_cast<unsigned int>(getNumRawDataModules(version) / 8))
538 throw std::invalid_argument(
"Invalid argument");
542 for (
int right = size - 1; right >= 1; right -= 2) {
545 for (
int vert = 0; vert < size; vert++) {
546 for (
int j = 0; j < 2; j++) {
547 size_t x =
static_cast<size_t>(right - j);
548 bool upward = ((right + 1) & 2) == 0;
549 size_t y =
static_cast<size_t>(upward ? size - 1 - vert : vert);
550 if (!isFunction.at(y).at(x) && i < data.size() * 8) {
551 modules.at(y).at(x) = getBit(data.at(i >> 3), 7 -
static_cast<int>(i & 7));
559 assert(i == data.size() * 8);
563void QrCode::applyMask(
int msk) {
564 if (msk < 0 || msk > 7)
565 throw std::domain_error(
"Mask value out of range");
566 size_t sz =
static_cast<size_t>(size);
567 for (
size_t y = 0; y < sz; y++) {
568 for (
size_t x = 0; x < sz; x++) {
571 case 0: invert = (x + y) % 2 == 0;
break;
572 case 1: invert = y % 2 == 0;
break;
573 case 2: invert = x % 3 == 0;
break;
574 case 3: invert = (x + y) % 3 == 0;
break;
575 case 4: invert = (x / 3 + y / 2) % 2 == 0;
break;
576 case 5: invert = x * y % 2 + x * y % 3 == 0;
break;
577 case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0;
break;
578 case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
break;
579 default:
throw std::logic_error(
"Unreachable");
581 modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
587long QrCode::getPenaltyScore()
const {
591 for (
int y = 0; y < size; y++) {
592 bool runColor =
false;
594 std::array<int,7> runHistory = {};
595 for (
int x = 0; x < size; x++) {
596 if (module(x, y) == runColor) {
599 result += PENALTY_N1;
603 finderPenaltyAddHistory(runX, runHistory);
605 result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
606 runColor = module(x, y);
610 result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
613 for (
int x = 0; x < size; x++) {
614 bool runColor =
false;
616 std::array<int,7> runHistory = {};
617 for (
int y = 0; y < size; y++) {
618 if (module(x, y) == runColor) {
621 result += PENALTY_N1;
625 finderPenaltyAddHistory(runY, runHistory);
627 result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
628 runColor = module(x, y);
632 result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
636 for (
int y = 0; y < size - 1; y++) {
637 for (
int x = 0; x < size - 1; x++) {
638 bool color = module(x, y);
639 if ( color == module(x + 1, y) &&
640 color == module(x, y + 1) &&
641 color == module(x + 1, y + 1))
642 result += PENALTY_N2;
648 for (
const vector<bool> &row : modules) {
649 for (
bool color : row) {
654 int total = size * size;
656 int k =
static_cast<int>((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1;
657 assert(0 <= k && k <= 9);
658 result += k * PENALTY_N4;
659 assert(0 <= result && result <= 2568888L);
664vector<int> QrCode::getAlignmentPatternPositions()
const {
666 return vector<int>();
668 int numAlign = version / 7 + 2;
669 int step = (version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4) * 2;
671 for (
int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
672 result.insert(result.begin(), pos);
673 result.insert(result.begin(), 6);
679int QrCode::getNumRawDataModules(
int ver) {
680 if (ver < MIN_VERSION || ver > MAX_VERSION)
681 throw std::domain_error(
"Version number out of range");
682 int result = (16 * ver + 128) * ver + 64;
684 int numAlign = ver / 7 + 2;
685 result -= (25 * numAlign - 10) * numAlign - 55;
689 assert(208 <= result && result <= 29648);
694int QrCode::getNumDataCodewords(
int ver, Ecc ecl) {
695 return getNumRawDataModules(ver) / 8
696 - ECC_CODEWORDS_PER_BLOCK [
static_cast<int>(ecl)][ver]
697 * NUM_ERROR_CORRECTION_BLOCKS[
static_cast<int>(ecl)][ver];
701vector<uint8_t> QrCode::reedSolomonComputeDivisor(
int degree) {
702 if (degree < 1 || degree > 255)
703 throw std::domain_error(
"Degree out of range");
706 vector<uint8_t> result(
static_cast<size_t>(degree));
707 result.at(result.size() - 1) = 1;
713 for (
int i = 0; i < degree; i++) {
715 for (
size_t j = 0; j < result.size(); j++) {
716 result.at(j) = reedSolomonMultiply(result.at(j), root);
717 if (j + 1 < result.size())
718 result.at(j) ^= result.at(j + 1);
720 root = reedSolomonMultiply(root, 0x02);
726vector<uint8_t> QrCode::reedSolomonComputeRemainder(
const vector<uint8_t> &data,
const vector<uint8_t> &divisor) {
727 vector<uint8_t> result(divisor.size());
728 for (uint8_t b : data) {
729 uint8_t factor = b ^ result.at(0);
730 result.erase(result.begin());
732 for (
size_t i = 0; i < result.size(); i++)
733 result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
739uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
742 for (
int i = 7; i >= 0; i--) {
743 z = (z << 1) ^ ((z >> 7) * 0x11D);
744 z ^= ((y >> i) & 1) * x;
747 return static_cast<uint8_t
>(z);
751int QrCode::finderPenaltyCountPatterns(
const std::array<int,7> &runHistory)
const {
752 int n = runHistory.at(1);
753 assert(n <= size * 3);
754 bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
755 return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
756 + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
760int QrCode::finderPenaltyTerminateAndCount(
bool currentRunColor,
int currentRunLength, std::array<int,7> &runHistory)
const {
761 if (currentRunColor) {
762 finderPenaltyAddHistory(currentRunLength, runHistory);
763 currentRunLength = 0;
765 currentRunLength += size;
766 finderPenaltyAddHistory(currentRunLength, runHistory);
767 return finderPenaltyCountPatterns(runHistory);
771void QrCode::finderPenaltyAddHistory(
int currentRunLength, std::array<int,7> &runHistory)
const {
772 if (runHistory.at(0) == 0)
773 currentRunLength += size;
774 std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
775 runHistory.at(0) = currentRunLength;
779bool QrCode::getBit(
long x,
int i) {
780 return ((x >> i) & 1) != 0;
786const int QrCode::PENALTY_N1 = 3;
787const int QrCode::PENALTY_N2 = 3;
788const int QrCode::PENALTY_N3 = 40;
789const int QrCode::PENALTY_N4 = 10;
792const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
795 {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
796 {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28},
797 {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
798 {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
801const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
804 {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25},
805 {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49},
806 {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68},
807 {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81},
811data_too_long::data_too_long(
const std::string &msg) :
812 std::length_error(msg) {}
818BitBuffer::BitBuffer()
819 : std::vector<bool>() {}
822void BitBuffer::appendBits(std::uint32_t val,
int len) {
823 if (len < 0 || len > 31 || val >> len != 0)
824 throw std::domain_error(
"Value out of range");
825 for (
int i = len - 1; i >= 0; i--)
826 this->push_back(((val >> i) & 1) != 0);