-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathmessage_render_cache.hpp
More file actions
112 lines (96 loc) · 3.42 KB
/
Copy pathmessage_render_cache.hpp
File metadata and controls
112 lines (96 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#pragma once
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <optional>
#include <string>
#include <vector>
#include <ftxui/dom/elements.hpp>
namespace acecode::tui {
// L1 消息级 Element 渲染缓存键:内容不变且渲染上下文(宽度/主题/语法)
// 不变时,消息的渲染结果可以复用。
struct MessageRenderCacheKey {
std::size_t revision = 0;
int width = 0;
std::uint32_t theme_version = 0;
bool syntax = true;
bool operator==(const MessageRenderCacheKey& o) const {
return revision == o.revision && width == o.width &&
theme_version == o.theme_version && syntax == o.syntax;
}
};
// 缓存的链接区域:坐标是相对消息盒子的偏移,命中重放时按当前布局 box 调整。
struct CachedLinkRegion {
std::string href;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
};
// 每消息的 Element 缓存(纯优化):命中则跳过 format_markdown,直接复用。
// 任何缓存失效/异常都回退到全量渲染路径,缓存不承担正确性。
class MessageRenderCache {
public:
// Grow storage for appended transcript messages without invalidating
// already cached entries. This is intentionally distinct from resize(),
// whose destructive semantics are used for whole-transcript resets.
void ensure_size(std::size_t n) {
if (n <= valid_.size()) return;
valid_.resize(n, false);
keys_.resize(n);
elements_.resize(n);
links_.resize(n);
}
void resize(std::size_t n) {
valid_.assign(n, false);
keys_.assign(n, MessageRenderCacheKey{});
elements_.assign(n, std::nullopt);
links_.assign(n, {});
}
void invalidate_all() {
std::fill(valid_.begin(), valid_.end(), false);
for (auto& e : elements_) e.reset();
for (auto& l : links_) l.clear();
}
void invalidate(std::size_t i) {
if (i < valid_.size()) {
valid_[i] = false;
elements_[i].reset();
links_[i].clear();
}
}
bool valid(std::size_t i, const MessageRenderCacheKey& key) const {
return i < valid_.size() && valid_[i] && keys_[i] == key &&
elements_[i].has_value();
}
void store(std::size_t i, const MessageRenderCacheKey& key,
ftxui::Element element, std::vector<CachedLinkRegion> links) {
// Do not silently discard a cacheable message when conversation
// growth raced or bypassed the normal ensure_size() synchronization.
if (i >= valid_.size()) {
if (i == std::numeric_limits<std::size_t>::max()) return;
ensure_size(i + 1);
}
valid_[i] = true;
keys_[i] = key;
elements_[i] = std::move(element);
links_[i] = std::move(links);
}
const ftxui::Element* element(std::size_t i) const {
if (i < elements_.size() && elements_[i].has_value()) {
return &(*elements_[i]);
}
return nullptr;
}
const std::vector<CachedLinkRegion>& link_regions(std::size_t i) const {
static const std::vector<CachedLinkRegion> kEmpty;
return (i < links_.size()) ? links_[i] : kEmpty;
}
private:
std::vector<bool> valid_;
std::vector<MessageRenderCacheKey> keys_;
std::vector<std::optional<ftxui::Element>> elements_;
std::vector<std::vector<CachedLinkRegion>> links_;
};
} // namespace acecode::tui