C++: refactor bit manipulation into discrete functions

backup
Christian Seiler 2 weeks ago
parent 96d9123f19
commit 6602bec421
  1. 68
      cpp/src/monoformat_bithelpers.hpp
  2. 136
      cpp/src/monoformat_parseonly.cpp
  3. 9
      cpp/src/monoformat_schema.cpp

@ -0,0 +1,68 @@
#ifndef MONOFORMAT_BITHELPERS_HPP
#define MONOFORMAT_BITHELPERS_HPP
#include <cstddef>
#include <cstdint>
#include <climits>
#include <concepts>
namespace monoformat {
template<std::integral Int, std::integral OtherInt>
constexpr inline bool isBitSet(Int value, OtherInt bit) {
if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] {
return false;
}
Int mask = Int{1} << static_cast<Int>(bit);
return (value & mask) == mask;
}
template<std::integral OtherInt>
constexpr inline bool isBitSet(std::byte value, OtherInt bit) {
return isBitSet(static_cast<std::uint8_t>(value), bit);
}
template<std::integral Int, std::integral OtherInt>
constexpr inline void setBit(Int& value, OtherInt bit) {
if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] {
return;
}
Int mask = Int{1} << static_cast<Int>(bit);
value |= mask;
}
template<std::integral OtherInt>
constexpr inline void setBit(std::byte& value, OtherInt bit) {
if (bit < 0 || bit >= CHAR_BIT) [[unlikely]] {
return;
}
std::uint8_t mask = std::uint8_t{1} << static_cast<std::uint8_t>(bit);
value = static_cast<std::byte>(static_cast<std::uint8_t>(value) | mask);
}
template<std::integral Int, std::integral OtherInt>
constexpr inline void unsetBit(Int& value, OtherInt bit) {
if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] {
return;
}
Int mask = Int{1} << static_cast<Int>(bit);
value &= ~mask;
}
template<std::integral OtherInt>
constexpr inline void unsetBit(std::byte& value, OtherInt bit) {
if (bit < 0 || bit >= CHAR_BIT) [[unlikely]] {
return;
}
std::uint8_t mask = std::uint8_t{1} << static_cast<std::uint8_t>(bit);
value = static_cast<std::byte>(static_cast<std::uint8_t>(value) & ~mask);
}
} // namespace monoformat
#endif // MONOFORMAT_BITHELPERS_HPP

@ -1,6 +1,7 @@
#include "monoformat_parseonly.hpp" #include "monoformat_parseonly.hpp"
#include "monoformat_parsehelpers.hpp" #include "monoformat_parsehelpers.hpp"
#include "monoformat_fontreader.hpp" #include "monoformat_fontreader.hpp"
#include "monoformat_bithelpers.hpp"
#include <string_view> #include <string_view>
#include <string> #include <string>
@ -58,10 +59,15 @@ static std::expected<AlwaysDrawnSectionMetaData, ParseError> parseAlwaysDrawnSec
data = data.subspan(*size - 8); data = data.subspan(*size - 8);
AlwaysDrawnSectionMetaData result; AlwaysDrawnSectionMetaData result;
result.drawOnFront = (((*flags) >> 0u) & 0x01u) == 0x01u; result.drawOnFront = isBitSet(*flags, 0);
result.drawOnBack = (((*flags) >> 0u) & 0x02u) == 0x02u; result.drawOnBack = isBitSet(*flags, 1);
result.clearBeforeDrawing = (((*flags) >> 0u) & 0x04u) == 0x04u; result.clearBeforeDrawing = isBitSet(*flags, 2);
result.elementData = sectionData; result.elementData = sectionData;
#if defined(DEBUG)
std::cerr << "[Debug] AlwaysDrawnSection, drawOnFront = " << result.drawOnFront << ", drawOnBack = " << result.drawOnBack << ", clearBeforeDrawing = " << result.clearBeforeDrawing << ", element data size = " << result.elementData.size() << " bytes" << std::endl;
#endif
return result; return result;
} }
@ -100,12 +106,17 @@ static std::expected<TimeBasedDrawnSectionMetaData, ParseError> parseTimeBasedDr
data = data.subspan(*size - 24); data = data.subspan(*size - 24);
TimeBasedDrawnSectionMetaData result; TimeBasedDrawnSectionMetaData result;
result.base.drawOnFront = (((*flags) >> 0u) & 0x01u) == 0x01u; result.base.drawOnFront = isBitSet(*flags, 0);
result.base.drawOnBack = (((*flags) >> 0u) & 0x02u) == 0x02u; result.base.drawOnBack = isBitSet(*flags, 1);
result.base.clearBeforeDrawing = (((*flags) >> 0u) & 0x04u) == 0x04u; result.base.clearBeforeDrawing = isBitSet(*flags, 2);
result.base.elementData = sectionData; result.base.elementData = sectionData;
result.startTimestamp = std::bit_cast<std::int64_t>(*startTimestamp); result.startTimestamp = std::bit_cast<std::int64_t>(*startTimestamp);
result.endTimestamp = std::bit_cast<std::int64_t>(*endTimestamp); result.endTimestamp = std::bit_cast<std::int64_t>(*endTimestamp);
#if defined(DEBUG)
std::cerr << "[Debug] TimeBasedDrawnSection, drawOnFront = " << result.base.drawOnFront << ", drawOnBack = " << result.base.drawOnBack << ", clearBeforeDrawing = " << result.base.clearBeforeDrawing << ", element data size = " << result.base.elementData.size() << " bytes, timestamp between " << result.startTimestamp << " and " << result.endTimestamp << std::endl;
#endif
return result; return result;
} }
@ -135,6 +146,10 @@ static std::expected<std::span<std::byte const>, ParseError> parseCustomFontSect
auto fontData = data.subspan(0, *size - 8); auto fontData = data.subspan(0, *size - 8);
data = data.subspan(*size - 8); data = data.subspan(*size - 8);
#if defined(DEBUG)
std::cerr << "[Debug] CustomFontSection, font data size = " << *actualSize << " bytes" << std::endl;
#endif
return readBuffer(fontData, *actualSize); return readBuffer(fontData, *actualSize);
} }
@ -292,6 +307,10 @@ std::expected<void, ParseError> handleImage(std::span<std::byte const>& buffer,
buffer = buffer.subspan(rounded - imageSize); buffer = buffer.subspan(rounded - imageSize);
} }
#if defined(DEBUG)
std::cerr << "[Debug] - Image, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) << std::endl;
#endif
std::ignore = animationTick; std::ignore = animationTick;
std::ignore = currentTimestamp; std::ignore = currentTimestamp;
std::ignore = customFonts; std::ignore = customFonts;
@ -345,15 +364,22 @@ std::expected<void, ParseError> handleAnimation(std::span<std::byte const>& buff
return std::unexpected(reserved_.error()); return std::unexpected(reserved_.error());
} }
std::size_t imageSize = ((*width) * (*height) + 8 - 1) / 8; std::size_t imageSize = ((*width) * (*height) + 8 - 1) / 8;
auto imageData = readBuffer(buffer, imageSize); auto imageData = readBuffer(buffer, imageSize * (*numberOfFrames));
if (!imageData) { if (!imageData) {
return std::unexpected(reserved_.error()); return std::unexpected(reserved_.error());
} }
std::size_t rounded = (imageSize + 4 - 1) / 4 * 4; std::size_t rounded = (imageSize * (*numberOfFrames) + 4 - 1) / 4 * 4;
if (imageSize < rounded) { if (imageSize * (*numberOfFrames) < rounded) {
buffer = buffer.subspan(rounded - imageSize); buffer = buffer.subspan(rounded - imageSize * (*numberOfFrames));
} }
#if defined(DEBUG)
std::cerr << "[Debug] - Animation, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", numberOfFrames = " << (*numberOfFrames)
<< ", updateInterval = " << (*updateInterval)
<< std::endl;
#endif
if (*numberOfFrames == 0) { if (*numberOfFrames == 0) {
return {}; return {};
} }
@ -426,14 +452,22 @@ std::expected<void, ParseError> handleHScrollImage(std::span<std::byte const>& b
auto ownImage = ConstMemoryOneBitBuffer{*imageData, *contentWidth, *height}; auto ownImage = ConstMemoryOneBitBuffer{*imageData, *contentWidth, *height};
ClippedImage target{screen, *x, *y, *width, *height}; ClippedImage target{screen, *x, *y, *width, *height};
#if defined(DEBUG)
std::cerr << "[Debug] - HScrollImage, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", contentWidth = " << (*contentWidth)
<< ", scrollSpeed = " << int(*scrollSpeed)
<< ", flags = " << int(*flags)
<< std::endl;
#endif
if (*contentWidth == 0) { if (*contentWidth == 0) {
return {}; return {};
} }
bool restarting = ((*flags) & 0x01) == 0x00; bool restarting = !isBitSet(*flags, 0);
bool invert = ((*flags) & 0x02) == 0x02; bool invert = isBitSet(*flags, 1);
bool padBefore = ((*flags) & 0x04) == 0x04; bool padBefore = isBitSet(*flags, 2);
bool padAfter = ((*flags) & 0x08) == 0x08; bool padAfter = isBitSet(*flags, 3);
if (!padBefore && !padAfter && *contentWidth < *width) { if (!padBefore && !padAfter && *contentWidth < *width) {
std::int16_t offset = invert ? (*width - *contentWidth) : 0; std::int16_t offset = invert ? (*width - *contentWidth) : 0;
@ -581,14 +615,22 @@ std::expected<void, ParseError> handleVScrollImage(std::span<std::byte const>& b
auto ownImage = ConstMemoryOneBitBuffer{*imageData, *width, *contentHeight}; auto ownImage = ConstMemoryOneBitBuffer{*imageData, *width, *contentHeight};
ClippedImage target{screen, *x, *y, *width, *height}; ClippedImage target{screen, *x, *y, *width, *height};
#if defined(DEBUG)
std::cerr << "[Debug] - VScrollImage, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", contentHeight = " << (*contentHeight)
<< ", scrollSpeed = " << int(*scrollSpeed)
<< ", flags = " << int(*flags)
<< std::endl;
#endif
if (*contentHeight == 0) { if (*contentHeight == 0) {
return {}; return {};
} }
bool restarting = ((*flags) & 0x01) == 0x00; bool restarting = !isBitSet(*flags, 0);
bool invert = ((*flags) & 0x02) == 0x02; bool invert = isBitSet(*flags, 1);
bool padBefore = ((*flags) & 0x04) == 0x04; bool padBefore = isBitSet(*flags, 2);
bool padAfter = ((*flags) & 0x08) == 0x08; bool padAfter = isBitSet(*flags, 3);
if (!padBefore && !padAfter && *contentHeight < *height) { if (!padBefore && !padAfter && *contentHeight < *height) {
std::int16_t offset = invert ? (*height - *contentHeight) : 0; std::int16_t offset = invert ? (*height - *contentHeight) : 0;
@ -720,6 +762,12 @@ std::expected<void, ParseError> handleLine(std::span<std::byte const>& buffer, O
return std::unexpected(flags.error()); return std::unexpected(flags.error());
} }
#if defined(DEBUG)
std::cerr << "[Debug] - Line, originX = " << (*originX) << ", originY = " << (*originY) << ", targetX = " << (*targetX) << ", targetY = " << (*targetY)
<< ", lineStyle = " << int(*lineStyle)
<< std::endl;
#endif
std::int32_t dx = static_cast<std::int32_t>(*targetX) - static_cast<std::int32_t>(*originX); std::int32_t dx = static_cast<std::int32_t>(*targetX) - static_cast<std::int32_t>(*originX);
std::int32_t dy = static_cast<std::int32_t>(*targetY) - static_cast<std::int32_t>(*originY); std::int32_t dy = static_cast<std::int32_t>(*targetY) - static_cast<std::int32_t>(*originY);
bool value = true; bool value = true;
@ -785,9 +833,16 @@ std::expected<void, ParseError> handleClippedText(std::span<std::byte const>& bu
} }
std::string_view text{reinterpret_cast<char const*>(textData->data()), *textLength}; std::string_view text{reinterpret_cast<char const*>(textData->data()), *textLength};
#if defined(DEBUG)
std::cerr << "[Debug] - ClippedText, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", fontIndex = " << int(*fontIndex)
<< ", text = \"" << text << "\""
<< std::endl;
#endif
std::span<std::byte const> fontData; std::span<std::byte const> fontData;
if ((*fontIndex) & 0x8000u) { if (isBitSet(*fontIndex, 15)) {
fontIndex = (*fontIndex) & ~0x8000u; unsetBit(*fontIndex, 15);
if (*fontIndex >= customFonts.size()) { if (*fontIndex >= customFonts.size()) {
return {}; return {};
} }
@ -854,9 +909,18 @@ std::expected<void, ParseError> handleHScrollText(std::span<std::byte const>& bu
} }
std::string_view text{reinterpret_cast<char const*>(textData->data()), *textLength}; std::string_view text{reinterpret_cast<char const*>(textData->data()), *textLength};
#if defined(DEBUG)
std::cerr << "[Debug] - HScrollText, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", scrollSpeed = " << int(*scrollSpeed)
<< ", flags = " << int(*flags)
<< ", fontIndex = " << int(*fontIndex)
<< ", text = \"" << text << "\""
<< std::endl;
#endif
std::span<std::byte const> fontData; std::span<std::byte const> fontData;
if ((*fontIndex) & 0x8000u) { if (isBitSet(*fontIndex, 15)) {
fontIndex = (*fontIndex) & ~0x8000u; unsetBit(*fontIndex, 15);
if (*fontIndex >= customFonts.size()) { if (*fontIndex >= customFonts.size()) {
return {}; return {};
} }
@ -880,10 +944,10 @@ std::expected<void, ParseError> handleHScrollText(std::span<std::byte const>& bu
return {}; return {};
} }
bool restarting = ((*flags) & 0x01) == 0x00; bool restarting = !isBitSet(*flags, 0);
bool invert = ((*flags) & 0x02) == 0x02; bool invert = isBitSet(*flags, 1);
bool padBefore = ((*flags) & 0x04) == 0x04; bool padBefore = isBitSet(*flags, 2);
bool padAfter = ((*flags) & 0x08) == 0x08; bool padAfter = isBitSet(*flags, 3);
if (!padBefore && !padAfter && contentWidth < *width) { if (!padBefore && !padAfter && contentWidth < *width) {
std::uint16_t offset = invert ? (*width - contentWidth) : 0; std::uint16_t offset = invert ? (*width - contentWidth) : 0;
@ -994,9 +1058,17 @@ std::expected<void, ParseError> handleCurrentTime(std::span<std::byte const>& bu
return std::unexpected(flags.error()); return std::unexpected(flags.error());
} }
#if defined(DEBUG)
std::cerr << "[Debug] - CurrentTime, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height)
<< ", fontIndex = " << int(*fontIndex)
<< ", utcOffset = " << int(*utcOffset)
<< ", flags = " << int(*flags)
<< std::endl;
#endif
std::span<std::byte const> fontData; std::span<std::byte const> fontData;
if ((*fontIndex) & 0x8000u) { if (isBitSet(*fontIndex, 15)) {
fontIndex = (*fontIndex) & ~0x8000u; unsetBit(*fontIndex, 15);
if (*fontIndex >= customFonts.size()) { if (*fontIndex >= customFonts.size()) {
return {}; return {};
} }
@ -1009,10 +1081,10 @@ std::expected<void, ParseError> handleCurrentTime(std::span<std::byte const>& bu
} }
ClippedImage target{screen, *x, *y, *width, *height}; ClippedImage target{screen, *x, *y, *width, *height};
bool use12h = ((*flags) & 0x01u) == 0x01u; bool use12h = isBitSet(*flags, 0);
bool showHours = ((*flags) & 0x02u) == 0x02u; bool showHours = isBitSet(*flags, 1);
bool showMinutes = ((*flags) & 0x04u) == 0x04u; bool showMinutes = isBitSet(*flags, 2);
bool showSeconds = ((*flags) & 0x08u) == 0x08u; bool showSeconds = isBitSet(*flags, 3);
if (showHours && showSeconds) { if (showHours && showSeconds) {
showMinutes = true; showMinutes = true;
} }

@ -1,4 +1,5 @@
#include "monoformat_schema.hpp" #include "monoformat_schema.hpp"
#include "monoformat_bithelpers.hpp"
#include <tuple> #include <tuple>
@ -26,7 +27,7 @@ bool MemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const {
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x; std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8; std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8; std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01; return isBitSet(m_buffer[byteIndex], bitIndex);
} }
void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) { void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {
@ -37,9 +38,9 @@ void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value)
std::size_t byteIndex = pxIndex / 8; std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8; std::size_t bitIndex = pxIndex % 8;
if (value) { if (value) {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) | (1u << bitIndex)); setBit(m_buffer[byteIndex], bitIndex);
} else { } else {
m_buffer[byteIndex] = static_cast<std::byte>(static_cast<std::uint8_t>(m_buffer[byteIndex]) & ~(1u << bitIndex)); unsetBit(m_buffer[byteIndex], bitIndex);
} }
} }
@ -65,7 +66,7 @@ bool ConstMemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const
std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x; std::size_t pxIndex = static_cast<std::size_t>(y) * m_width + x;
std::size_t byteIndex = pxIndex / 8; std::size_t byteIndex = pxIndex / 8;
std::size_t bitIndex = pxIndex % 8; std::size_t bitIndex = pxIndex % 8;
return ((static_cast<std::uint8_t>(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01; return isBitSet(m_buffer[byteIndex], bitIndex);
} }
void ConstMemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) { void ConstMemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {

Loading…
Cancel
Save