refactor: Use std::size instead of sizeof/sizeof (#1819)

## Summary

Simplify code calculating compile-time array sizes with
`sizeof(array)/sizeof(element)` to use `std::size`.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY**_
This commit is contained in:
Zach Nelson
2026-05-04 12:41:27 -05:00
committed by GitHub
parent e026bcb9dc
commit 333286acfc
4 changed files with 42 additions and 57 deletions
+3 -4
View File
@@ -4,6 +4,7 @@
#include "htmlEntities.h" #include "htmlEntities.h"
#include <cstring> #include <cstring>
#include <iterator>
struct EntityPair { struct EntityPair {
const char* key; const char* key;
@@ -62,8 +63,6 @@ static constexpr EntityPair ENTITY_LOOKUP[] = {
{"&yen;", "¥"}, {"&yuml;", "ÿ"}, {"&zeta;", "ζ"}, {"&zwj;", "\u200D"}, {"&zwnj;", "\u200C"}, {"&yen;", "¥"}, {"&yuml;", "ÿ"}, {"&zeta;", "ζ"}, {"&zwj;", "\u200D"}, {"&zwnj;", "\u200C"},
}; };
static const size_t ENTITY_LOOKUP_COUNT = sizeof(ENTITY_LOOKUP) / sizeof(ENTITY_LOOKUP[0]);
// Verify the table is sorted at compile time. // Verify the table is sorted at compile time.
static constexpr int constexprStrcmp(const char* a, const char* b) { static constexpr int constexprStrcmp(const char* a, const char* b) {
for (size_t i = 0;; i++) { for (size_t i = 0;; i++) {
@@ -73,7 +72,7 @@ static constexpr int constexprStrcmp(const char* a, const char* b) {
} }
static constexpr bool isTableSorted() { static constexpr bool isTableSorted() {
for (size_t i = 1; i < ENTITY_LOOKUP_COUNT; i++) { for (size_t i = 1; i < std::size(ENTITY_LOOKUP); i++) {
if (constexprStrcmp(ENTITY_LOOKUP[i - 1].key, ENTITY_LOOKUP[i].key) >= 0) return false; if (constexprStrcmp(ENTITY_LOOKUP[i - 1].key, ENTITY_LOOKUP[i].key) >= 0) return false;
} }
return true; return true;
@@ -85,7 +84,7 @@ const char* lookupHtmlEntity(const char* entity, size_t len) {
if (entity == nullptr || len == 0) return nullptr; if (entity == nullptr || len == 0) return nullptr;
size_t lo = 0; size_t lo = 0;
size_t hi = ENTITY_LOOKUP_COUNT; size_t hi = std::size(ENTITY_LOOKUP);
while (lo < hi) { while (lo < hi) {
const size_t mid = lo + (hi - lo) / 2; const size_t mid = lo + (hi - lo) / 2;
+25 -37
View File
@@ -8,42 +8,30 @@
#include <XmlParserUtils.h> #include <XmlParserUtils.h>
#include <expat.h> #include <expat.h>
#include <iterator>
#include "../../Epub.h" #include "../../Epub.h"
#include "../Page.h" #include "../Page.h"
#include "../converters/ImageDecoderFactory.h" #include "../converters/ImageDecoderFactory.h"
#include "../converters/ImageToFramebufferDecoder.h" #include "../converters/ImageToFramebufferDecoder.h"
#include "../htmlEntities.h" #include "../htmlEntities.h"
const char* HEADER_TAGS[] = {"h1", "h2", "h3", "h4", "h5", "h6"};
constexpr int NUM_HEADER_TAGS = sizeof(HEADER_TAGS) / sizeof(HEADER_TAGS[0]);
// Minimum file size (in bytes) to show indexing popup - smaller chapters don't benefit from it // Minimum file size (in bytes) to show indexing popup - smaller chapters don't benefit from it
constexpr size_t MIN_SIZE_FOR_POPUP = 10 * 1024; // 10KB constexpr size_t MIN_SIZE_FOR_POPUP = 10 * 1024; // 10KB
constexpr size_t PARSE_BUFFER_SIZE = 1024; constexpr size_t PARSE_BUFFER_SIZE = 1024;
const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"}; constexpr const char* HEADER_TAGS[] = {"h1", "h2", "h3", "h4", "h5", "h6"};
constexpr int NUM_BLOCK_TAGS = sizeof(BLOCK_TAGS) / sizeof(BLOCK_TAGS[0]); constexpr const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"};
constexpr const char* BOLD_TAGS[] = {"b", "strong"};
const char* BOLD_TAGS[] = {"b", "strong"}; constexpr const char* ITALIC_TAGS[] = {"i", "em"};
constexpr int NUM_BOLD_TAGS = sizeof(BOLD_TAGS) / sizeof(BOLD_TAGS[0]); constexpr const char* UNDERLINE_TAGS[] = {"u", "ins"};
constexpr const char* IMAGE_TAGS[] = {"img"};
const char* ITALIC_TAGS[] = {"i", "em"}; constexpr const char* SKIP_TAGS[] = {"head"};
constexpr int NUM_ITALIC_TAGS = sizeof(ITALIC_TAGS) / sizeof(ITALIC_TAGS[0]);
const char* UNDERLINE_TAGS[] = {"u", "ins"};
constexpr int NUM_UNDERLINE_TAGS = sizeof(UNDERLINE_TAGS) / sizeof(UNDERLINE_TAGS[0]);
const char* IMAGE_TAGS[] = {"img"};
constexpr int NUM_IMAGE_TAGS = sizeof(IMAGE_TAGS) / sizeof(IMAGE_TAGS[0]);
const char* SKIP_TAGS[] = {"head"};
constexpr int NUM_SKIP_TAGS = sizeof(SKIP_TAGS) / sizeof(SKIP_TAGS[0]);
bool isWhitespace(const char c) { return c == ' ' || c == '\r' || c == '\n' || c == '\t'; } bool isWhitespace(const char c) { return c == ' ' || c == '\r' || c == '\n' || c == '\t'; }
// given the start and end of a tag, check to see if it matches a known tag bool matches(const char* tag_name, const char* const* possible_tags, size_t count) {
bool matches(const char* tag_name, const char* possible_tags[], const int possible_tag_count) { for (size_t i = 0; i < count; i++) {
for (int i = 0; i < possible_tag_count; i++) {
if (strcmp(tag_name, possible_tags[i]) == 0) { if (strcmp(tag_name, possible_tags[i]) == 0) {
return true; return true;
} }
@@ -70,7 +58,7 @@ bool isInternalEpubLink(const char* href) {
} }
bool isHeaderOrBlock(const char* name) { bool isHeaderOrBlock(const char* name) {
return matches(name, HEADER_TAGS, NUM_HEADER_TAGS) || matches(name, BLOCK_TAGS, NUM_BLOCK_TAGS); return matches(name, HEADER_TAGS, std::size(HEADER_TAGS)) || matches(name, BLOCK_TAGS, std::size(BLOCK_TAGS));
} }
bool isTableStructuralTag(const char* name) { bool isTableStructuralTag(const char* name) {
@@ -271,7 +259,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
return; return;
} }
if (matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS)) { if (matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS))) {
std::string src; std::string src;
std::string alt; std::string alt;
if (atts != nullptr) { if (atts != nullptr) {
@@ -541,7 +529,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
} }
} }
if (matches(name, SKIP_TAGS, NUM_SKIP_TAGS)) { if (matches(name, SKIP_TAGS, std::size(SKIP_TAGS))) {
// start skip // start skip
self->skipUntilDepth = self->depth; self->skipUntilDepth = self->depth;
self->depth += 1; self->depth += 1;
@@ -608,7 +596,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle( const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle(
cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth); cssStyle, emSize, static_cast<CssTextAlign>(self->paragraphAlignment), self->viewportWidth);
if (matches(name, HEADER_TAGS, NUM_HEADER_TAGS)) { if (matches(name, HEADER_TAGS, std::size(HEADER_TAGS))) {
self->currentCssStyle = cssStyle; self->currentCssStyle = cssStyle;
auto headerBlockStyle = BlockStyle::fromCssStyle(cssStyle, emSize, CssTextAlign::Center, self->viewportWidth); auto headerBlockStyle = BlockStyle::fromCssStyle(cssStyle, emSize, CssTextAlign::Center, self->viewportWidth);
headerBlockStyle.textAlignDefined = true; headerBlockStyle.textAlignDefined = true;
@@ -621,7 +609,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
self->startNewTextBlock(accumulated.withoutBottom()); self->startNewTextBlock(accumulated.withoutBottom());
self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth); self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth);
self->updateEffectiveInlineStyle(); self->updateEffectiveInlineStyle();
} else if (matches(name, BLOCK_TAGS, NUM_BLOCK_TAGS)) { } else if (matches(name, BLOCK_TAGS, std::size(BLOCK_TAGS))) {
if (strcmp(name, "br") == 0) { if (strcmp(name, "br") == 0) {
if (self->partWordBufferIndex > 0) { if (self->partWordBufferIndex > 0) {
// flush word preceding <br/> to currentTextBlock before calling startNewTextBlock // flush word preceding <br/> to currentTextBlock before calling startNewTextBlock
@@ -640,7 +628,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
self->currentTextBlock->addWord("\xe2\x80\xa2", EpdFontFamily::REGULAR); self->currentTextBlock->addWord("\xe2\x80\xa2", EpdFontFamily::REGULAR);
} }
} }
} else if (matches(name, UNDERLINE_TAGS, NUM_UNDERLINE_TAGS)) { } else if (matches(name, UNDERLINE_TAGS, std::size(UNDERLINE_TAGS))) {
// Flush buffer before style change so preceding text gets current style // Flush buffer before style change so preceding text gets current style
if (self->partWordBufferIndex > 0) { if (self->partWordBufferIndex > 0) {
self->flushPartWordBuffer(); self->flushPartWordBuffer();
@@ -662,7 +650,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
} }
self->inlineStyleStack.push_back(entry); self->inlineStyleStack.push_back(entry);
self->updateEffectiveInlineStyle(); self->updateEffectiveInlineStyle();
} else if (matches(name, BOLD_TAGS, NUM_BOLD_TAGS)) { } else if (matches(name, BOLD_TAGS, std::size(BOLD_TAGS))) {
// Flush buffer before style change so preceding text gets current style // Flush buffer before style change so preceding text gets current style
if (self->partWordBufferIndex > 0) { if (self->partWordBufferIndex > 0) {
self->flushPartWordBuffer(); self->flushPartWordBuffer();
@@ -684,7 +672,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
} }
self->inlineStyleStack.push_back(entry); self->inlineStyleStack.push_back(entry);
self->updateEffectiveInlineStyle(); self->updateEffectiveInlineStyle();
} else if (matches(name, ITALIC_TAGS, NUM_ITALIC_TAGS)) { } else if (matches(name, ITALIC_TAGS, std::size(ITALIC_TAGS))) {
// Flush buffer before style change so preceding text gets current style // Flush buffer before style change so preceding text gets current style
if (self->partWordBufferIndex > 0) { if (self->partWordBufferIndex > 0) {
self->flushPartWordBuffer(); self->flushPartWordBuffer();
@@ -946,12 +934,12 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
// Flush buffer with current style BEFORE any style changes // Flush buffer with current style BEFORE any style changes
if (self->partWordBufferIndex > 0) { if (self->partWordBufferIndex > 0) {
// Flush if style will change OR if we're closing a block/structural element // Flush if style will change OR if we're closing a block/structural element
const bool isInlineTag = const bool isInlineTag = !headerOrBlockTag && !tableStructuralTag &&
!headerOrBlockTag && !tableStructuralTag && !matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS) && self->depth != 1; !matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS)) && self->depth != 1;
const bool shouldFlush = styleWillChange || headerOrBlockTag || matches(name, BOLD_TAGS, NUM_BOLD_TAGS) || const bool shouldFlush = styleWillChange || headerOrBlockTag || matches(name, BOLD_TAGS, std::size(BOLD_TAGS)) ||
matches(name, ITALIC_TAGS, NUM_ITALIC_TAGS) || matches(name, ITALIC_TAGS, std::size(ITALIC_TAGS)) ||
matches(name, UNDERLINE_TAGS, NUM_UNDERLINE_TAGS) || tableStructuralTag || matches(name, UNDERLINE_TAGS, std::size(UNDERLINE_TAGS)) || tableStructuralTag ||
matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS) || self->depth == 1; matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS)) || self->depth == 1;
if (shouldFlush) { if (shouldFlush) {
self->flushPartWordBuffer(); self->flushPartWordBuffer();
+9 -10
View File
@@ -22,8 +22,7 @@
namespace { namespace {
// Folders/files to hide from the web interface file browser // Folders/files to hide from the web interface file browser
// Note: Items starting with "." are automatically hidden // Note: Items starting with "." are automatically hidden
const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; constexpr const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"};
constexpr size_t HIDDEN_ITEMS_COUNT = sizeof(HIDDEN_ITEMS) / sizeof(HIDDEN_ITEMS[0]);
constexpr uint16_t UDP_PORTS[] = {54982, 48123, 39001, 44044, 59678}; constexpr uint16_t UDP_PORTS[] = {54982, 48123, 39001, 44044, 59678};
constexpr uint16_t LOCAL_UDP_PORT = 8134; constexpr uint16_t LOCAL_UDP_PORT = 8134;
@@ -75,8 +74,8 @@ bool isProtectedItemName(const String& name) {
if (name.startsWith(".")) { if (name.startsWith(".")) {
return true; return true;
} }
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (name.equals(HIDDEN_ITEMS[i])) { if (name.equals(item)) {
return true; return true;
} }
} }
@@ -389,8 +388,8 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function<void(F
// Check against explicitly hidden items list // Check against explicitly hidden items list
if (!shouldHide) { if (!shouldHide) {
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (fileName.equals(HIDDEN_ITEMS[i])) { if (fileName.equals(item)) {
shouldHide = true; shouldHide = true;
break; break;
} }
@@ -497,8 +496,8 @@ void CrossPointWebServer::handleDownload() const {
server->send(403, "text/plain", "Cannot access system files"); server->send(403, "text/plain", "Cannot access system files");
return; return;
} }
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (itemName.equals(HIDDEN_ITEMS[i])) { if (itemName.equals(item)) {
server->send(403, "text/plain", "Cannot access protected items"); server->send(403, "text/plain", "Cannot access protected items");
return; return;
} }
@@ -1033,8 +1032,8 @@ void CrossPointWebServer::handleDelete() const {
// Check against explicitly protected items // Check against explicitly protected items
bool isProtected = false; bool isProtected = false;
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (itemName.equals(HIDDEN_ITEMS[i])) { if (itemName.equals(item)) {
isProtected = true; isProtected = true;
break; break;
} }
+5 -6
View File
@@ -7,8 +7,7 @@
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
namespace { namespace {
const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; constexpr const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"};
constexpr size_t HIDDEN_ITEMS_COUNT = sizeof(HIDDEN_ITEMS) / sizeof(HIDDEN_ITEMS[0]);
// RFC 1123 date format helper: "Sun, 06 Nov 1994 08:49:37 GMT" // RFC 1123 date format helper: "Sun, 06 Nov 1994 08:49:37 GMT"
// ESP32 doesn't have real-time clock set by default, so we use a fixed epoch date // ESP32 doesn't have real-time clock set by default, so we use a fixed epoch date
@@ -230,8 +229,8 @@ void WebDAVHandler::handlePropfind(WebServer& s) {
// Skip hidden/protected items // Skip hidden/protected items
bool shouldHide = fileName.startsWith("."); bool shouldHide = fileName.startsWith(".");
if (!shouldHide) { if (!shouldHide) {
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (fileName.equals(HIDDEN_ITEMS[i])) { if (fileName.equals(item)) {
shouldHide = true; shouldHide = true;
break; break;
} }
@@ -774,8 +773,8 @@ bool WebDAVHandler::isProtectedPath(const String& path) const {
if (segment.startsWith(".")) return true; if (segment.startsWith(".")) return true;
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { for (const auto* item : HIDDEN_ITEMS) {
if (segment.equals(HIDDEN_ITEMS[i])) return true; if (segment.equals(item)) return true;
} }
start = end + 1; start = end + 1;