diff --git a/src/apps/gemini_app.cpp b/src/apps/gemini_app.cpp index b9704f0..7e7c104 100644 --- a/src/apps/gemini_app.cpp +++ b/src/apps/gemini_app.cpp @@ -103,8 +103,11 @@ void GeminiApp::show(GeminiPage&& page) { } void GeminiApp::analyse() { - types_.clear(); - links_.clear(); + // Sized exactly: the Service budgeted these bytes per line (kBytesPerLine), growth by + // doubling would take up to twice that. + std::vector().swap(types_); + std::vector().swap(links_); + types_.reserve(page_.text.lineCount()); // A window may start inside a preformatted block: the index says (bit 31). size_t entry = page_.windowStart / GeminiService::kIndexEvery; bool pre = page_.windowed && entry < page_.lineIndex.size() && (page_.lineIndex[entry] & 0x80000000u); @@ -114,6 +117,7 @@ void GeminiApp::analyse() { types_.push_back(static_cast(t)); if (t == LineType::Link) links_.push_back(i); } + links_.shrink_to_fit(); layoutDirty_ = true; requestRedraw(); } diff --git a/src/services/gemini_service.cpp b/src/services/gemini_service.cpp index 805c15d..b1842e5 100644 --- a/src/services/gemini_service.cpp +++ b/src/services/gemini_service.cpp @@ -192,7 +192,7 @@ bool GeminiService::loadWindow(const GeminiPage& page, size_t firstLine) { windowPage_.lineIndex = page.lineIndex; windowLine_ = firstLine; // The App drops its current window once the new one is in: count that memory as coming back. - windowReleasing_ = page.text.bytes() + page.text.lineCount() * 8; + windowReleasing_ = page.text.bytes() + page.text.lineCount() * kBytesPerLine; return start(Job::Window); } @@ -618,7 +618,7 @@ void GeminiService::fetchOne(const std::string& url, GeminiPage& page, bool load // what was free before minus the steady floor; meanwhile the heap must stay above the // transient floor. Both counted with the next 4 KB chunk and the line index. size_t take = std::min(n - i, kMaxBody - page.text.bytes()); - size_t pageCost = page.text.bytes() + page.text.lineCount() * 8 + TextBuffer::kChunk + take; + size_t pageCost = page.text.bytes() + page.text.lineCount() * kBytesPerLine + TextBuffer::kChunk + take; if (take < static_cast(n - i)) page.truncatedWhy = "longer than 64 KB"; else if (freeBefore < kSteadyFloor + pageCost) page.truncatedWhy = "not enough memory to keep it"; else if (esp_get_free_heap_size() < kTransientFloor + TextBuffer::kChunk + take) @@ -720,7 +720,7 @@ void GeminiService::loadFromCard(GeminiPage& page, size_t freeBefore, const std: if (page.totalLines % kIndexEvery == 0) page.lineIndex.push_back(lineStart | (pre ? 0x80000000u : 0)); if (line.compare(0, 3, "```") == 0) pre = !pre; if (loading) { - if (page.text.bytes() + page.text.lineCount() * 8 + line.size() + 1 > budget) loading = false; + if (page.text.bytes() + page.text.lineCount() * kBytesPerLine + line.size() + 1 > budget) loading = false; else { line += '\n'; page.text.append(line.data(), line.size()); @@ -768,7 +768,7 @@ void GeminiService::readWindow(GeminiPage& page, size_t firstLine, size_t budget continue; } if (lineNo >= firstLine) { - if (page.text.bytes() + page.text.lineCount() * 8 + line.size() + 1 > budget) done = true; + if (page.text.bytes() + page.text.lineCount() * kBytesPerLine + line.size() + 1 > budget) done = true; else { line += '\n'; page.text.append(line.data(), line.size()); diff --git a/src/services/gemini_service.h b/src/services/gemini_service.h index 8988f92..3b43e05 100644 --- a/src/services/gemini_service.h +++ b/src/services/gemini_service.h @@ -64,6 +64,10 @@ class GeminiService { static constexpr int kMaxLinkedPages = 30; // Q83 static constexpr size_t kIndexEvery = 64; // lines between lineIndex entries static constexpr size_t kMaxLineBytes = 8192; // longer lines are cut + // What a page costs per line on top of its text: TextBuffer's index (8) and the App's tables + // (type, first row, links: about 8). Counting only the first left the steady floor 1.5 to 3 KB + // short on a windowed page (found in M3). + static constexpr size_t kBytesPerLine = 16; static constexpr const char* kBookmarks = "/gemini/bookmarks.gmi"; static constexpr const char* kStartUrl = "about:start";