src/detail/circular_buffer.cpp
100.0% Lines (86/86)
100.0% List of functions (13/13)
84.2% Branches (32/38)
Functions (13)
Function
Calls
Lines
Branches
Blocks
boost::burl::detail::circular_buffer::empty() const
:27
6436x
100.0%
–
100.0%
boost::burl::detail::circular_buffer::full() const
:34
6430x
100.0%
–
100.0%
boost::burl::detail::circular_buffer::wrapped() const
:41
10058x
100.0%
–
100.0%
boost::burl::detail::circular_buffer::size() const
:48
7152x
100.0%
–
100.0%
boost::burl::detail::circular_buffer::data() const
:55
9712x
100.0%
100.0%
100.0%
boost::burl::detail::circular_buffer::first(unsigned long) const
:65
83x
100.0%
100.0%
100.0%
boost::burl::detail::circular_buffer::prepare() const
:73
9581x
100.0%
100.0%
100.0%
boost::burl::detail::circular_buffer::commit(unsigned long)
:87
9549x
100.0%
100.0%
100.0%
boost::burl::detail::circular_buffer::consume(unsigned long)
:96
3765x
100.0%
100.0%
100.0%
boost::burl::detail::circular_buffer::reset(char*)
:108
51x
100.0%
50.0%
67.0%
boost::burl::detail::circular_buffer::shed(unsigned long)
:119
309x
100.0%
50.0%
60.0%
boost::burl::detail::circular_buffer::slide(char*)
:130
205x
100.0%
50.0%
60.0%
boost::burl::detail::circular_buffer::linearize(char*)
:141
550x
100.0%
92.9%
97.0%
| 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 |