From 333286acfc0c5cd8b4a85d107dab422b60e2af6f Mon Sep 17 00:00:00 2001 From: Zach Nelson Date: Mon, 4 May 2026 12:41:27 -0500 Subject: [PATCH] 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**_ --- lib/Epub/Epub/htmlEntities.cpp | 7 +-- .../Epub/parsers/ChapterHtmlSlimParser.cpp | 62 ++++++++----------- src/network/CrossPointWebServer.cpp | 19 +++--- src/network/WebDAVHandler.cpp | 11 ++-- 4 files changed, 42 insertions(+), 57 deletions(-) diff --git a/lib/Epub/Epub/htmlEntities.cpp b/lib/Epub/Epub/htmlEntities.cpp index 6fdcb71c..2fd35b8a 100644 --- a/lib/Epub/Epub/htmlEntities.cpp +++ b/lib/Epub/Epub/htmlEntities.cpp @@ -4,6 +4,7 @@ #include "htmlEntities.h" #include +#include struct EntityPair { const char* key; @@ -62,8 +63,6 @@ static constexpr EntityPair ENTITY_LOOKUP[] = { {"¥", "¥"}, {"ÿ", "ÿ"}, {"ζ", "ζ"}, {"‍", "\u200D"}, {"‌", "\u200C"}, }; -static const size_t ENTITY_LOOKUP_COUNT = sizeof(ENTITY_LOOKUP) / sizeof(ENTITY_LOOKUP[0]); - // Verify the table is sorted at compile time. static constexpr int constexprStrcmp(const char* a, const char* b) { for (size_t i = 0;; i++) { @@ -73,7 +72,7 @@ static constexpr int constexprStrcmp(const char* a, const char* b) { } 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; } return true; @@ -85,7 +84,7 @@ const char* lookupHtmlEntity(const char* entity, size_t len) { if (entity == nullptr || len == 0) return nullptr; size_t lo = 0; - size_t hi = ENTITY_LOOKUP_COUNT; + size_t hi = std::size(ENTITY_LOOKUP); while (lo < hi) { const size_t mid = lo + (hi - lo) / 2; diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index 3c8694af..92f0280a 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -8,42 +8,30 @@ #include #include +#include + #include "../../Epub.h" #include "../Page.h" #include "../converters/ImageDecoderFactory.h" #include "../converters/ImageToFramebufferDecoder.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 constexpr size_t MIN_SIZE_FOR_POPUP = 10 * 1024; // 10KB constexpr size_t PARSE_BUFFER_SIZE = 1024; -const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"}; -constexpr int NUM_BLOCK_TAGS = sizeof(BLOCK_TAGS) / sizeof(BLOCK_TAGS[0]); - -const char* BOLD_TAGS[] = {"b", "strong"}; -constexpr int NUM_BOLD_TAGS = sizeof(BOLD_TAGS) / sizeof(BOLD_TAGS[0]); - -const char* ITALIC_TAGS[] = {"i", "em"}; -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]); +constexpr const char* HEADER_TAGS[] = {"h1", "h2", "h3", "h4", "h5", "h6"}; +constexpr const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"}; +constexpr const char* BOLD_TAGS[] = {"b", "strong"}; +constexpr const char* ITALIC_TAGS[] = {"i", "em"}; +constexpr const char* UNDERLINE_TAGS[] = {"u", "ins"}; +constexpr const char* IMAGE_TAGS[] = {"img"}; +constexpr const char* SKIP_TAGS[] = {"head"}; 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* possible_tags[], const int possible_tag_count) { - for (int i = 0; i < possible_tag_count; i++) { +bool matches(const char* tag_name, const char* const* possible_tags, size_t count) { + for (size_t i = 0; i < count; i++) { if (strcmp(tag_name, possible_tags[i]) == 0) { return true; } @@ -70,7 +58,7 @@ bool isInternalEpubLink(const char* href) { } 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) { @@ -271,7 +259,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* return; } - if (matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS)) { + if (matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS))) { std::string src; std::string alt; 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 self->skipUntilDepth = self->depth; self->depth += 1; @@ -608,7 +596,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* const auto userAlignmentBlockStyle = BlockStyle::fromCssStyle( cssStyle, emSize, static_cast(self->paragraphAlignment), self->viewportWidth); - if (matches(name, HEADER_TAGS, NUM_HEADER_TAGS)) { + if (matches(name, HEADER_TAGS, std::size(HEADER_TAGS))) { self->currentCssStyle = cssStyle; auto headerBlockStyle = BlockStyle::fromCssStyle(cssStyle, emSize, CssTextAlign::Center, self->viewportWidth); headerBlockStyle.textAlignDefined = true; @@ -621,7 +609,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* self->startNewTextBlock(accumulated.withoutBottom()); self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth); 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 (self->partWordBufferIndex > 0) { // flush word preceding
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); } } - } 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 if (self->partWordBufferIndex > 0) { self->flushPartWordBuffer(); @@ -662,7 +650,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* } self->inlineStyleStack.push_back(entry); 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 if (self->partWordBufferIndex > 0) { self->flushPartWordBuffer(); @@ -684,7 +672,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* } self->inlineStyleStack.push_back(entry); 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 if (self->partWordBufferIndex > 0) { 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 if (self->partWordBufferIndex > 0) { // Flush if style will change OR if we're closing a block/structural element - const bool isInlineTag = - !headerOrBlockTag && !tableStructuralTag && !matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS) && self->depth != 1; - const bool shouldFlush = styleWillChange || headerOrBlockTag || matches(name, BOLD_TAGS, NUM_BOLD_TAGS) || - matches(name, ITALIC_TAGS, NUM_ITALIC_TAGS) || - matches(name, UNDERLINE_TAGS, NUM_UNDERLINE_TAGS) || tableStructuralTag || - matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS) || self->depth == 1; + const bool isInlineTag = !headerOrBlockTag && !tableStructuralTag && + !matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS)) && self->depth != 1; + const bool shouldFlush = styleWillChange || headerOrBlockTag || matches(name, BOLD_TAGS, std::size(BOLD_TAGS)) || + matches(name, ITALIC_TAGS, std::size(ITALIC_TAGS)) || + matches(name, UNDERLINE_TAGS, std::size(UNDERLINE_TAGS)) || tableStructuralTag || + matches(name, IMAGE_TAGS, std::size(IMAGE_TAGS)) || self->depth == 1; if (shouldFlush) { self->flushPartWordBuffer(); diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 0ad2f1ab..2346f221 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -22,8 +22,7 @@ namespace { // Folders/files to hide from the web interface file browser // Note: Items starting with "." are automatically hidden -const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; -constexpr size_t HIDDEN_ITEMS_COUNT = sizeof(HIDDEN_ITEMS) / sizeof(HIDDEN_ITEMS[0]); +constexpr const char* HIDDEN_ITEMS[] = {"System Volume Information", "XTCache"}; constexpr uint16_t UDP_PORTS[] = {54982, 48123, 39001, 44044, 59678}; constexpr uint16_t LOCAL_UDP_PORT = 8134; @@ -75,8 +74,8 @@ bool isProtectedItemName(const String& name) { if (name.startsWith(".")) { return true; } - for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { - if (name.equals(HIDDEN_ITEMS[i])) { + for (const auto* item : HIDDEN_ITEMS) { + if (name.equals(item)) { return true; } } @@ -389,8 +388,8 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function