100.00% Lines (105/105) 100.00% Functions (14/14)
TLA Baseline Branch
Line Hits Code Line Hits Code
  1 + //
  2 + // Copyright (c) 2026 Michael Vandeberg
  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/capy
  8 + //
  9 +
  10 + /*
  11 + Implementation type for the public buffer_slice() free function.
  12 + Users see this only via auto + the Slice concept; the type is
  13 + documented as unspecified. Maintained alongside Slice in
  14 + include/boost/capy/concept/slice.hpp.
  15 + */
  16 +
  17 + #ifndef BOOST_CAPY_DETAIL_SLICE_IMPL_HPP
  18 + #define BOOST_CAPY_DETAIL_SLICE_IMPL_HPP
  19 +
  20 + #include <boost/capy/detail/config.hpp>
  21 + #include <boost/capy/buffers.hpp>
  22 +
  23 + #include <cstddef>
  24 + #include <iterator>
  25 + #include <type_traits>
  26 +
  27 + namespace boost {
  28 + namespace capy {
  29 + namespace detail {
  30 +
  31 + template<class T>
  32 + struct slice_buffer_type_for;
  33 +
  34 + template<MutableBufferSequence T>
  35 + struct slice_buffer_type_for<T>
  36 + {
  37 + using type = mutable_buffer;
  38 + };
  39 +
  40 + template<ConstBufferSequence T>
  41 + requires (!MutableBufferSequence<T>)
  42 + struct slice_buffer_type_for<T>
  43 + {
  44 + using type = const_buffer;
  45 + };
  46 +
  47 + template<class BufferSequence>
  48 + requires MutableBufferSequence<BufferSequence>
  49 + || ConstBufferSequence<BufferSequence>
  50 + class slice_impl
  51 + {
  52 + public:
  53 + using iterator_type =
  54 + decltype(capy::begin(std::declval<BufferSequence const&>()));
  55 + using end_iterator_type =
  56 + decltype(capy::end(std::declval<BufferSequence const&>()));
  57 + using buffer_type =
  58 + typename slice_buffer_type_for<BufferSequence>::type;
  59 +
  60 + private:
  61 + iterator_type first_{};
  62 + end_iterator_type last_{};
  63 + std::size_t front_skip_ = 0;
  64 + std::size_t back_skip_ = 0;
  65 +
HITGNC   66 + 493 static buffer_type adjust_buffer(
  67 + buffer_type const& buf,
  68 + std::size_t front,
  69 + std::size_t back) noexcept
  70 + {
  71 + if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
  72 + {
HITGNC   73 + 247 return mutable_buffer(
HITGNC   74 + 247 static_cast<char*>(buf.data()) + front,
HITGNC   75 + 494 buf.size() - front - back);
  76 + }
  77 + else
  78 + {
HITGNC   79 + 246 return const_buffer(
HITGNC   80 + 246 static_cast<char const*>(buf.data()) + front,
HITGNC   81 + 492 buf.size() - front - back);
  82 + }
  83 + }
  84 +
  85 + public:
  86 + /// View returned by `slice_impl::data()`.
  87 + class data_view
  88 + {
  89 + iterator_type first_{};
  90 + end_iterator_type last_{};
  91 + std::size_t front_skip_ = 0;
  92 + std::size_t back_skip_ = 0;
  93 +
  94 + public:
  95 + class const_iterator
  96 + {
  97 + iterator_type cur_{};
  98 + iterator_type anchor_first_{};
  99 + end_iterator_type anchor_last_{};
  100 + std::size_t front_skip_ = 0;
  101 + std::size_t back_skip_ = 0;
  102 +
  103 + public:
  104 + using iterator_category = std::bidirectional_iterator_tag;
  105 + using value_type = buffer_type;
  106 + using difference_type = std::ptrdiff_t;
  107 + using pointer = value_type*;
  108 + using reference = value_type;
  109 +
  110 + const_iterator() noexcept = default;
  111 +
HITGNC   112 + 942 const_iterator(
  113 + iterator_type cur,
  114 + iterator_type anchor_first,
  115 + end_iterator_type anchor_last,
  116 + std::size_t front_skip,
  117 + std::size_t back_skip) noexcept
HITGNC   118 + 942 : cur_(cur)
HITGNC   119 + 942 , anchor_first_(anchor_first)
HITGNC   120 + 942 , anchor_last_(anchor_last)
HITGNC   121 + 942 , front_skip_(front_skip)
HITGNC   122 + 942 , back_skip_(back_skip)
  123 + {
HITGNC   124 + 942 }
  125 +
HITGNC   126 + 598 bool operator==(const_iterator const& other) const noexcept
  127 + {
HITGNC   128 + 598 return cur_ == other.cur_;
  129 + }
  130 +
HITGNC   131 + 598 bool operator!=(const_iterator const& other) const noexcept
  132 + {
HITGNC   133 + 598 return !(*this == other);
  134 + }
  135 +
HITGNC   136 + 493 value_type operator*() const noexcept
  137 + {
HITGNC   138 + 493 buffer_type buf = *cur_;
HITGNC   139 + 493 auto front = (cur_ == anchor_first_) ? front_skip_ : 0;
HITGNC   140 + 493 auto next = cur_;
HITGNC   141 + 493 ++next;
HITGNC   142 + 493 auto back = (next == anchor_last_) ? back_skip_ : 0;
HITGNC   143 + 493 return adjust_buffer(buf, front, back);
  144 + }
  145 +
HITGNC   146 + 463 const_iterator& operator++() noexcept
  147 + {
HITGNC   148 + 463 ++cur_;
HITGNC   149 + 463 return *this;
  150 + }
  151 +
HITGNC   152 + 262 const_iterator operator++(int) noexcept
  153 + {
HITGNC   154 + 262 const_iterator tmp = *this;
HITGNC   155 + 262 ++*this;
HITGNC   156 + 262 return tmp;
  157 + }
  158 +
  159 + const_iterator& operator--() noexcept
  160 + {
  161 + --cur_;
  162 + return *this;
  163 + }
  164 +
  165 + const_iterator operator--(int) noexcept
  166 + {
  167 + const_iterator tmp = *this;
  168 + --*this;
  169 + return tmp;
  170 + }
  171 + };
  172 +
  173 + data_view() noexcept = default;
  174 +
HITGNC   175 + 271 data_view(
  176 + iterator_type first,
  177 + end_iterator_type last,
  178 + std::size_t front_skip,
  179 + std::size_t back_skip) noexcept
HITGNC   180 + 271 : first_(first)
HITGNC   181 + 271 , last_(last)
HITGNC   182 + 271 , front_skip_(front_skip)
HITGNC   183 + 271 , back_skip_(back_skip)
  184 + {
HITGNC   185 + 271 }
  186 +
HITGNC   187 + 457 const_iterator begin() const noexcept
  188 + {
  189 + return const_iterator(
HITGNC   190 + 457 first_, first_, last_, front_skip_, back_skip_);
  191 + }
  192 +
HITGNC   193 + 485 const_iterator end() const noexcept
  194 + {
  195 + return const_iterator(
HITGNC   196 + 485 last_, first_, last_, front_skip_, back_skip_);
  197 + }
  198 + };
  199 +
  200 + slice_impl() noexcept = default;
  201 +
HITGNC   202 + 10 explicit slice_impl(BufferSequence const& bs) noexcept
HITGNC   203 + 10 : first_(capy::begin(bs))
HITGNC   204 + 10 , last_(capy::end(bs))
  205 + {
HITGNC   206 + 10 }
  207 +
HITGNC   208 + 213 slice_impl(
  209 + BufferSequence const& bs,
  210 + std::size_t offset,
  211 + std::size_t length) noexcept
HITGNC   212 + 213 {
HITGNC   213 + 213 auto it_begin = capy::begin(bs);
HITGNC   214 + 213 auto it_end = capy::end(bs);
  215 +
HITGNC   216 + 213 std::size_t total = 0;
HITGNC   217 + 508 for (auto it = it_begin; it != it_end; ++it)
HITGNC   218 + 295 total += (*it).size();
  219 +
HITGNC   220 + 213 if (offset > total)
HITGNC   221 + 1 offset = total;
HITGNC   222 + 213 std::size_t const remaining = total - offset;
HITGNC   223 + 213 if (length > remaining)
HITGNC   224 + 205 length = remaining;
  225 +
HITGNC   226 + 213 first_ = it_begin;
HITGNC   227 + 213 last_ = it_end;
  228 +
HITGNC   229 + 213 std::size_t skip = offset;
HITGNC   230 + 235 while (first_ != last_)
  231 + {
HITGNC   232 + 228 std::size_t const buf_size = (*first_).size();
HITGNC   233 + 228 if (skip < buf_size)
  234 + {
HITGNC   235 + 206 front_skip_ = skip;
HITGNC   236 + 206 break;
  237 + }
HITGNC   238 + 22 skip -= buf_size;
HITGNC   239 + 22 ++first_;
  240 + }
  241 +
HITGNC   242 + 213 std::size_t left = length;
HITGNC   243 + 213 auto cursor = first_;
HITGNC   244 + 213 std::size_t cursor_front = front_skip_;
HITGNC   245 + 278 while (cursor != last_ && left > 0)
  246 + {
HITGNC   247 + 270 std::size_t const buf_size = (*cursor).size();
HITGNC   248 + 270 std::size_t const avail = buf_size - cursor_front;
HITGNC   249 + 270 if (left <= avail)
  250 + {
HITGNC   251 + 205 back_skip_ = avail - left;
HITGNC   252 + 205 ++cursor;
HITGNC   253 + 205 last_ = cursor;
HITGNC   254 + 205 return;
  255 + }
HITGNC   256 + 65 left -= avail;
HITGNC   257 + 65 ++cursor;
HITGNC   258 + 65 cursor_front = 0;
  259 + }
  260 +
HITGNC   261 + 8 last_ = cursor;
  262 + }
  263 +
HITGNC   264 + 271 data_view data() const noexcept
  265 + {
HITGNC   266 + 271 return data_view(first_, last_, front_skip_, back_skip_);
  267 + }
  268 +
HITGNC   269 + 172 void remove_prefix(std::size_t n) noexcept
  270 + {
HITGNC   271 + 192 while (n > 0 && first_ != last_)
  272 + {
HITGNC   273 + 122 std::size_t const buf_total = (*first_).size();
HITGNC   274 + 122 std::size_t live = buf_total - front_skip_;
HITGNC   275 + 122 auto next = first_;
HITGNC   276 + 122 ++next;
HITGNC   277 + 122 bool const is_last = (next == last_);
HITGNC   278 + 122 if (is_last)
HITGNC   279 + 92 live -= back_skip_;
  280 +
HITGNC   281 + 122 if (n < live)
  282 + {
HITGNC   283 + 35 front_skip_ += n;
HITGNC   284 + 35 return;
  285 + }
  286 +
HITGNC   287 + 87 n -= live;
HITGNC   288 + 87 if (is_last)
  289 + {
HITGNC   290 + 67 first_ = last_;
HITGNC   291 + 67 front_skip_ = 0;
HITGNC   292 + 67 back_skip_ = 0;
HITGNC   293 + 67 return;
  294 + }
HITGNC   295 + 20 ++first_;
HITGNC   296 + 20 front_skip_ = 0;
  297 + }
  298 + }
  299 + };
  300 +
  301 + } // namespace detail
  302 + } // namespace capy
  303 + } // namespace boost
  304 +
  305 + #endif