Pixie
Loading...
Searching...
No Matches
sliding_window.h
Go to the documentation of this file.
1#pragma once
2
7
8#include <pixie/storage.h>
9
10#include <algorithm>
11#include <cstddef>
12#include <cstdint>
13#include <limits>
14#include <span>
15#include <stdexcept>
16#include <utility>
17#include <vector>
18
19namespace pixie {
20
35class SlidingWindowStorage : public StorageBase<SlidingWindowStorage> {
36 public:
39 : capacity_bytes_(validate_capacity(capacity_bytes)),
40 data_(capacity_bytes_) {}
41
43
46 : capacity_bytes_(std::exchange(other.capacity_bytes_, 0)),
47 data_(std::move(other.data_)),
48 begin_position_(std::exchange(other.begin_position_, 0)),
49 end_position_(std::exchange(other.end_position_, 0)) {}
50
51 SlidingWindowStorage& operator=(const SlidingWindowStorage&) = delete;
52 SlidingWindowStorage& operator=(SlidingWindowStorage&&) = delete;
53
55 std::size_t capacity_bytes() const { return capacity_bytes_; }
56
58 std::size_t size_bytes_impl() const {
59 return static_cast<std::size_t>(end_position_ - begin_position_);
60 }
61
63 position_type begin_position_impl() const { return begin_position_; }
64
66 position_type end_position_impl() const { return end_position_; }
67
69 std::size_t allocated_bytes_impl() const { return data_.capacity(); }
70
79 void extend(std::size_t count_bytes) {
80 if (count_bytes == 0) {
81 return;
82 }
83 if (capacity_bytes_ == 0) {
84 throw std::length_error("Cannot extend a zero-capacity sliding window");
85 }
86 if (count_bytes >
87 std::numeric_limits<position_type>::max() - end_position_) {
88 throw std::length_error("Sliding-window position overflow");
89 }
90
91 const position_type new_end = end_position_ + count_bytes;
92 begin_position_ = new_end > capacity_bytes_ ? new_end - capacity_bytes_ : 0;
93 end_position_ = new_end;
94 }
95
101 void prepare_segments_impl(position_type position, std::size_t count_bytes) {
102 if (count_bytes == 0 || (position <= end_position_ &&
103 count_bytes <= end_position_ - position)) {
104 return;
105 }
106 if (count_bytes > std::numeric_limits<position_type>::max() - position) {
107 throw std::length_error("Sliding-window range overflow");
108 }
109
110 const position_type requested_end = position + count_bytes;
111 if (count_bytes > capacity_bytes_ || position < begin_position_) {
112 throw std::out_of_range(
113 "Storage range cannot fit inside the working window");
114 }
115 const position_type extension = requested_end - end_position_;
116 if constexpr (sizeof(position_type) > sizeof(std::size_t)) {
117 if (extension > std::numeric_limits<std::size_t>::max()) {
118 throw std::length_error("Sliding-window extension is too large");
119 }
120 }
121 extend(static_cast<std::size_t>(extension));
122 }
123
126 std::size_t count_bytes) {
127 return physical_segments(position, count_bytes,
128 std::span<std::byte>(data_));
129 }
130
133 std::size_t count_bytes) const {
134 return physical_segments(position, count_bytes,
135 std::span<const std::byte>(data_));
136 }
137
138 private:
139 static std::size_t validate_capacity(std::size_t capacity_bytes) {
140 if constexpr (sizeof(std::size_t) > sizeof(position_type)) {
141 if (capacity_bytes > std::numeric_limits<position_type>::max()) {
142 throw std::length_error("Sliding-window capacity is too large");
143 }
144 }
145 return capacity_bytes;
146 }
147
148 template <class Byte>
149 SplitSpan<Byte> physical_segments(position_type position,
150 std::size_t count_bytes,
151 std::span<Byte> data) const {
152 if (count_bytes == 0) {
153 return {};
154 }
155 const std::size_t physical_begin =
156 static_cast<std::size_t>(position % capacity_bytes_);
157 const std::size_t first_size =
158 std::min(count_bytes, capacity_bytes_ - physical_begin);
159 return SplitSpan<Byte>(data.subspan(physical_begin, first_size),
160 data.first(count_bytes - first_size));
161 }
162
163 std::size_t capacity_bytes_;
164 std::vector<std::byte> data_;
165 position_type begin_position_ = 0;
166 position_type end_position_ = 0;
167};
168
169} // namespace pixie
Owning fixed-capacity storage over a monotonically positioned window.
Definition sliding_window.h:35
position_type begin_position_impl() const
Return the oldest retained logical byte position.
Definition sliding_window.h:63
void prepare_segments_impl(position_type position, std::size_t count_bytes)
Extend through a requested future writable range when necessary.
Definition sliding_window.h:101
SlidingWindowStorage(std::size_t capacity_bytes)
Construct an empty window with immutable byte capacity.
Definition sliding_window.h:38
position_type end_position_impl() const
Return the position one past the newest retained byte.
Definition sliding_window.h:66
SlidingWindowStorage(SlidingWindowStorage &&other) noexcept
Transfer the fixed backing allocation.
Definition sliding_window.h:45
std::size_t capacity_bytes() const
Return the immutable logical ring capacity in bytes.
Definition sliding_window.h:55
std::size_t allocated_bytes_impl() const
Return the bytes in the fixed backing allocation.
Definition sliding_window.h:69
SplitSpan< const std::byte > segments_impl(position_type position, std::size_t count_bytes) const
Return a retained logical range as read-only physical segments.
Definition sliding_window.h:132
std::size_t size_bytes_impl() const
Return the number of bytes currently retained.
Definition sliding_window.h:58
SplitSpan< std::byte > segments_impl(position_type position, std::size_t count_bytes)
Return a retained logical range as writable physical segments.
Definition sliding_window.h:125
void extend(std::size_t count_bytes)
Advance the logical end by a number of bytes.
Definition sliding_window.h:79
A logical contiguous sequence stored in at most two physical spans.
Definition split_span.h:25
CRTP facade for byte-addressable storage.
Definition storage.h:65
std::uint64_t position_type
Definition storage.h:68
Common interface for byte-addressable storage.