21 static_assert(std::is_trivially_copyable_v<T>);
22 static_assert(
sizeof(T) <= 64 * 1024);
23 static constexpr std::size_t kValues = 64 * 1024 /
sizeof(T);
39 return owner_ == o.owner_ && index_ == o.index_;
45 : owner_(owner), index_(index) {}
47 std::size_t index_ = 0;
51 file_.set_directory(directory);
52 directory_ = directory;
54 std::size_t
size() const noexcept {
return end_ - base_; }
59 base_ = end_ = page_ = loaded_ = 0;
62 T
at(std::size_t index)
const {
63 if (index >=
size())
throw std::out_of_range(
"scratch sequence index");
65 return window_[(base_ + index) % kValues];
69 if (index >=
size())
throw std::out_of_range(
"scratch sequence index");
71 window_[(base_ + index) % kValues] =
value;
75 if (end_ == std::numeric_limits<std::size_t>::max())
79 window_[end_ % kValues] =
value;
80 loaded_ = std::max(loaded_, end_ % kValues + 1);
86 if (count ==
size())
return;
94 if (first.owner_ !=
this || last.owner_ !=
this
95 || first.index_ != 0 || last.index_ >
size())
96 throw std::logic_error(
"scratch sequence erase is not a prefix");
99 template<
class Compare>
103 for (std::size_t width = 1; width <
size();) {
105 PageReader left_page(*
this), right_page(*
this);
106 for (std::size_t start = 0; start <
size();) {
107 const auto middle = start + std::min(width,
size() - start);
108 const auto stop = middle + std::min(width,
size() - middle);
109 auto left = start, right = middle;
110 while (left < middle || right < stop) {
111 if (right == stop || (left < middle
112 && !before(right_page.at(right), left_page.at(left))))
115 scratch.
push_back(right_page.at(right++));
120 swap(*
this, scratch);
121 if (width >
size() / 2)
break;
129 T at(std::size_t index) {
130 if (index < first_ || index - first_ >= count_) {
132 const auto first = index - index % kValues;
133 const auto count = std::min(kValues, source_.
size() - first);
135 source_.file_.
read(byte_offset(source_.base_ + first),
136 values_.data(), count *
sizeof(T));
140 return values_[index - first_];
144 std::array<T, kValues> values_{};
145 std::size_t first_ = 0, count_ = 0;
147 static std::uint64_t byte_offset(std::size_t index) {
148 if (index > std::numeric_limits<std::uint64_t>::max() /
sizeof(T))
150 return static_cast<std::uint64_t
>(index) *
sizeof(T);
154 file_.open(
"pineforge-sequence");
155 file_.write(byte_offset(page_), window_.data(), loaded_ *
sizeof(T));
158 void load(std::size_t global)
const {
159 const std::size_t next = global - global % kValues;
160 if (loaded_ != 0 && page_ == next)
return;
162 const auto count = next < end_ ? std::min(kValues, end_ - next) : 0;
165 file_.read(byte_offset(next), window_.data(), count *
sizeof(T));
169 mutable ScratchFile file_;
170 std::string directory_;
171 mutable std::array<T, kValues> window_{};
172 std::size_t base_ = 0, end_ = 0;
173 mutable std::size_t page_ = 0, loaded_ = 0;
174 mutable bool dirty_ =
false;