src/detail/circular_buffer.cpp

100.0% Lines (91/91) 100.0% List of functions (14/14) 85.0% Branches (34/40)
circular_buffer.cpp
f(x) Functions (14)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Mohammad Nejati
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/burl
8 //
9
10 #include <boost/burl/detail/circular_buffer.hpp>
11
12 #include "util.hpp"
13
14 #include <boost/assert.hpp>
15
16 #include <algorithm>
17 #include <cstring>
18
19 namespace boost
20 {
21 namespace burl
22 {
23 namespace detail
24 {
25
26 bool
27 6441x circular_buffer::
28 empty() const noexcept
29 {
30 6441x return len == 0;
31 }
32
33 bool
34 6439x circular_buffer::
35 full() const noexcept
36 {
37 6439x return len == cap;
38 }
39
40 bool
41 10060x circular_buffer::
42 wrapped() const noexcept
43 {
44 10060x return pos + len > cap;
45 }
46
47 std::size_t
48 7190x circular_buffer::
49 size() const noexcept
50 {
51 7190x return len;
52 }
53
54 std::array<capy::const_buffer, 2>
55 9721x circular_buffer::
56 data() const noexcept
57 {
58
2/2
✓ Branch 1 taken 9038 times.
✓ Branch 2 taken 683 times.
9721x if(!wrapped())
59 9038x return { { { ptr + pos, len }, { ptr, 0 } } };
60 683x return { { { ptr + pos, cap - pos },
61 683x { ptr, len - (cap - pos) } } };
62 }
63
64 capy::const_buffer
65 93x circular_buffer::
66 first(std::size_t n) const noexcept
67 {
68
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 91 times.
93x auto const k = wrapped() ? cap - pos : len;
69 93x return { ptr + pos, clamp(k, n) };
70 }
71
72 std::array<capy::mutable_buffer, 2>
73 9575x circular_buffer::
74 prepare() const noexcept
75 {
76 9575x std::size_t w = pos + len;
77
2/2
✓ Branch 0 taken 687 times.
✓ Branch 1 taken 8888 times.
9575x if(w >= cap)
78 687x w -= cap;
79 9575x std::size_t const free = cap - len;
80
2/2
✓ Branch 0 taken 4257 times.
✓ Branch 1 taken 5318 times.
9575x if(w + free <= cap)
81 4257x return { { { ptr + w, free }, { ptr, 0 } } };
82 5318x return { { { ptr + w, cap - w },
83 5318x { ptr, free - (cap - w) } } };
84 }
85
86 capy::mutable_buffer
87 40x circular_buffer::
88 prepare_one() const noexcept
89 {
90 40x std::size_t w = pos + len;
91
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
40x if(w >= cap)
92 4x w -= cap;
93 40x return { ptr + w, clamp(cap - len, cap - w) };
94 }
95
96 void
97 9553x circular_buffer::
98 commit(std::size_t n) noexcept
99 {
100
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9552 times.
9553x if(n > cap - len)
101 1x n = cap - len;
102 9553x len += n;
103 9553x }
104
105 void
106 3796x circular_buffer::
107 consume(std::size_t n) noexcept
108 {
109
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3795 times.
3796x if(n > len)
110 1x n = len;
111 3796x pos += n;
112
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3790 times.
3796x if(pos >= cap)
113 6x pos -= cap;
114 3796x len -= n;
115 3796x }
116
117 void
118 52x circular_buffer::
119 reset(char* p) noexcept
120 {
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52x BOOST_ASSERT(p <= ptr + cap);
122 52x cap = static_cast<std::size_t>((ptr + cap) - p);
123 52x ptr = p;
124 52x pos = 0;
125 52x len = 0;
126 52x }
127
128 void
129 318x circular_buffer::
130 shed(std::size_t n) noexcept
131 {
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
318x BOOST_ASSERT(pos == 0);
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
318x BOOST_ASSERT(n <= len);
134 318x ptr += n;
135 318x cap -= n;
136 318x len -= n;
137 318x }
138
139 void
140 207x circular_buffer::
141 slide(char* p) noexcept
142 {
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207x BOOST_ASSERT(pos == 0);
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207x BOOST_ASSERT(p <= ptr);
145 207x std::memmove(p, ptr, len);
146 207x cap += static_cast<std::size_t>(ptr - p);
147 207x ptr = p;
148 207x }
149
150 char*
151 521x circular_buffer::
152 linearize(char* floor) noexcept
153 {
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 521 times.
521x BOOST_ASSERT(floor <= ptr);
155 521x char* p = floor;
156
6/6
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 324 times.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 156 times.
✓ Branch 6 taken 365 times.
521x if(len != 0 && !wrapped())
157 {
158 156x p = ptr + pos;
159 }
160
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 324 times.
365x else if(len != 0)
161 {
162 41x auto const bufs = data();
163 41x auto const* a = static_cast<char const*>(bufs[0].data());
164 41x auto an = bufs[0].size();
165 41x auto const* b = static_cast<char const*>(bufs[1].data());
166 41x auto const bn = bufs[1].size();
167 41x auto const gap = static_cast<std::size_t>(ptr - floor) + (cap - len);
168
169 // leapfrogging to the floor runs ceil(an / gap) rounds
170 // and re-moves the wrapped range each round; past a
171 // bound the in-place rotate is cheaper, and it is the
172 // only option when gap == 0
173
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 19 times.
41x if(an <= gap * 16)
174 {
175 22x char* base = floor;
176 do
177 {
178 24x auto const k = (std::min)(an, gap);
179 24x b = static_cast<char const*>(std::memmove(base + k, b, bn));
180 24x std::memcpy(base, a, k);
181 24x an -= k;
182 24x base += k;
183 24x a += k;
184
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24x } while(an);
185 }
186 else
187 {
188 19x std::rotate(ptr, ptr + pos, ptr + cap);
189 19x p = ptr;
190 }
191 }
192 521x cap = static_cast<std::size_t>((ptr + cap) - p);
193 521x ptr = p;
194 521x pos = 0;
195 521x return p;
196 }
197
198 } // namespace detail
199 } // namespace burl
200 } // namespace boost
201