src/detail/circular_buffer.cpp

100.0% Lines (86/86) 100.0% List of functions (13/13) 84.2% Branches (32/38)
circular_buffer.cpp
f(x) Functions (13)
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 6436x circular_buffer::
28 empty() const noexcept
29 {
30 6436x return len == 0;
31 }
32
33 bool
34 6430x circular_buffer::
35 full() const noexcept
36 {
37 6430x return len == cap;
38 }
39
40 bool
41 10058x circular_buffer::
42 wrapped() const noexcept
43 {
44 10058x return pos + len > cap;
45 }
46
47 std::size_t
48 7152x circular_buffer::
49 size() const noexcept
50 {
51 7152x return len;
52 }
53
54 std::array<capy::const_buffer, 2>
55 9712x circular_buffer::
56 data() const noexcept
57 {
58
2/2
✓ Branch 1 taken 9030 times.
✓ Branch 2 taken 682 times.
9712x if(!wrapped())
59 9030x return { { { ptr + pos, len }, { ptr, 0 } } };
60 682x return { { { ptr + pos, cap - pos },
61 682x { ptr, len - (cap - pos) } } };
62 }
63
64 capy::const_buffer
65 83x circular_buffer::
66 first(std::size_t n) const noexcept
67 {
68
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 81 times.
83x auto const k = wrapped() ? cap - pos : len;
69 83x return { ptr + pos, clamp(k, n) };
70 }
71
72 std::array<capy::mutable_buffer, 2>
73 9581x circular_buffer::
74 prepare() const noexcept
75 {
76 9581x std::size_t w = pos + len;
77
2/2
✓ Branch 0 taken 682 times.
✓ Branch 1 taken 8899 times.
9581x if(w >= cap)
78 682x w -= cap;
79 9581x std::size_t const free = cap - len;
80
2/2
✓ Branch 0 taken 4263 times.
✓ Branch 1 taken 5318 times.
9581x if(w + free <= cap)
81 4263x return { { { ptr + w, free }, { ptr, 0 } } };
82 5318x return { { { ptr + w, cap - w },
83 5318x { ptr, free - (cap - w) } } };
84 }
85
86 void
87 9549x circular_buffer::
88 commit(std::size_t n) noexcept
89 {
90
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9548 times.
9549x if(n > cap - len)
91 1x n = cap - len;
92 9549x len += n;
93 9549x }
94
95 void
96 3765x circular_buffer::
97 consume(std::size_t n) noexcept
98 {
99
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3764 times.
3765x if(n > len)
100 1x n = len;
101 3765x pos += n;
102
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3759 times.
3765x if(pos >= cap)
103 6x pos -= cap;
104 3765x len -= n;
105 3765x }
106
107 void
108 51x circular_buffer::
109 reset(char* p) noexcept
110 {
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51x BOOST_ASSERT(p <= ptr + cap);
112 51x cap = static_cast<std::size_t>((ptr + cap) - p);
113 51x ptr = p;
114 51x pos = 0;
115 51x len = 0;
116 51x }
117
118 void
119 309x circular_buffer::
120 shed(std::size_t n) noexcept
121 {
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 309 times.
309x BOOST_ASSERT(pos == 0);
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 309 times.
309x BOOST_ASSERT(n <= len);
124 309x ptr += n;
125 309x cap -= n;
126 309x len -= n;
127 309x }
128
129 void
130 205x circular_buffer::
131 slide(char* p) noexcept
132 {
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205x BOOST_ASSERT(pos == 0);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205x BOOST_ASSERT(p <= ptr);
135 205x std::memmove(p, ptr, len);
136 205x cap += static_cast<std::size_t>(ptr - p);
137 205x ptr = p;
138 205x }
139
140 char*
141 550x circular_buffer::
142 linearize(char* floor) noexcept
143 {
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 550 times.
550x BOOST_ASSERT(floor <= ptr);
145 550x char* p = floor;
146
6/6
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 334 times.
✓ Branch 3 taken 175 times.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 175 times.
✓ Branch 6 taken 375 times.
550x if(len != 0 && !wrapped())
147 {
148 175x p = ptr + pos;
149 }
150
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 334 times.
375x else if(len != 0)
151 {
152 41x auto const bufs = data();
153 41x auto const* a = static_cast<char const*>(bufs[0].data());
154 41x auto an = bufs[0].size();
155 41x auto const* b = static_cast<char const*>(bufs[1].data());
156 41x auto const bn = bufs[1].size();
157 41x auto const gap = static_cast<std::size_t>(ptr - floor) + (cap - len);
158
159 // leapfrogging to the floor runs ceil(an / gap) rounds
160 // and re-moves the wrapped range each round; past a
161 // bound the in-place rotate is cheaper, and it is the
162 // only option when gap == 0
163
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 19 times.
41x if(an <= gap * 16)
164 {
165 22x char* base = floor;
166 do
167 {
168 24x auto const k = (std::min)(an, gap);
169 24x b = static_cast<char const*>(std::memmove(base + k, b, bn));
170 24x std::memcpy(base, a, k);
171 24x an -= k;
172 24x base += k;
173 24x a += k;
174
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24x } while(an);
175 }
176 else
177 {
178 19x std::rotate(ptr, ptr + pos, ptr + cap);
179 19x p = ptr;
180 }
181 }
182 550x cap = static_cast<std::size_t>((ptr + cap) - p);
183 550x ptr = p;
184 550x pos = 0;
185 550x return p;
186 }
187
188 } // namespace detail
189 } // namespace burl
190 } // namespace boost
191