| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) | ||
| 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/http_proto | ||
| 8 | // | ||
| 9 | |||
| 10 | #include <boost/http_proto/fields_base.hpp> | ||
| 11 | |||
| 12 | #include <boost/http_proto/error.hpp> | ||
| 13 | #include <boost/http_proto/field.hpp> | ||
| 14 | #include <boost/http_proto/header_limits.hpp> | ||
| 15 | #include <boost/http_proto/rfc/detail/rules.hpp> | ||
| 16 | #include <boost/http_proto/rfc/token_rule.hpp> | ||
| 17 | |||
| 18 | #include <boost/http_proto/detail/config.hpp> | ||
| 19 | #include <boost/http_proto/detail/except.hpp> | ||
| 20 | #include <boost/http_proto/detail/header.hpp> | ||
| 21 | |||
| 22 | #include <boost/assert.hpp> | ||
| 23 | #include <boost/assert/source_location.hpp> | ||
| 24 | |||
| 25 | #include <boost/core/detail/string_view.hpp> | ||
| 26 | |||
| 27 | #include <boost/system/result.hpp> | ||
| 28 | |||
| 29 | #include <boost/url/grammar/ci_string.hpp> | ||
| 30 | #include <boost/url/grammar/error.hpp> | ||
| 31 | #include <boost/url/grammar/parse.hpp> | ||
| 32 | #include <boost/url/grammar/token_rule.hpp> | ||
| 33 | |||
| 34 | #include "detail/align_up.hpp" | ||
| 35 | #include "detail/move_chars.hpp" | ||
| 36 | #include "rfc/detail/rules.hpp" | ||
| 37 | |||
| 38 | namespace boost { | ||
| 39 | namespace http_proto { | ||
| 40 | |||
| 41 | static | ||
| 42 | system::result<core::string_view> | ||
| 43 | 233 | verify_field_name( | |
| 44 | core::string_view name) | ||
| 45 | { | ||
| 46 | auto rv = | ||
| 47 | 233 | grammar::parse(name, detail::field_name_rule); | |
| 48 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 227 times.
|
233 | if( rv.has_error() ) |
| 49 | { | ||
| 50 | 6 | auto ec = rv.error(); | |
| 51 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
|
6 | if( ec == urls::grammar::error::leftover ) |
| 52 | 3 | return error::bad_field_name; | |
| 53 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
|
3 | if( ec == condition::need_more_input ) |
| 54 | 1 | return error::bad_field_name; | |
| 55 | } | ||
| 56 | 229 | return rv; | |
| 57 | } | ||
| 58 | |||
| 59 | static | ||
| 60 | system::result<typename detail::field_value_rule_t::value_type> | ||
| 61 | 273 | verify_field_value( | |
| 62 | core::string_view value) | ||
| 63 | { | ||
| 64 | 273 | auto it = value.begin(); | |
| 65 | 273 | auto end = value.end(); | |
| 66 | auto rv = | ||
| 67 | 273 | grammar::parse(it, end, detail::field_value_rule); | |
| 68 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 268 times.
|
273 | if( rv.has_error() ) |
| 69 | { | ||
| 70 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | if( rv.error() == condition::need_more_input ) |
| 71 | 5 | return error::bad_field_value; | |
| 72 | ✗ | return rv.error(); | |
| 73 | } | ||
| 74 | |||
| 75 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 261 times.
|
268 | if( rv->has_crlf ) |
| 76 | 7 | return error::bad_field_smuggle; | |
| 77 | |||
| 78 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 254 times.
|
261 | if( it != end ) |
| 79 | 7 | return error::bad_field_value; | |
| 80 | |||
| 81 | 254 | return rv; | |
| 82 | } | ||
| 83 | |||
| 84 | class fields_base:: | ||
| 85 | op_t | ||
| 86 | { | ||
| 87 | fields_base& self_; | ||
| 88 | core::string_view* s0_; | ||
| 89 | core::string_view* s1_; | ||
| 90 | char* buf_ = nullptr; | ||
| 91 | char const* cbuf_ = nullptr; | ||
| 92 | std::size_t cap_ = 0; | ||
| 93 | |||
| 94 | public: | ||
| 95 | explicit | ||
| 96 | 901 | op_t( | |
| 97 | fields_base& self, | ||
| 98 | core::string_view* s0 = nullptr, | ||
| 99 | core::string_view* s1 = nullptr) noexcept | ||
| 100 | 901 | : self_(self) | |
| 101 | , s0_(s0) | ||
| 102 | 901 | , s1_(s1) | |
| 103 | { | ||
| 104 | 901 | } | |
| 105 | |||
| 106 | 901 | ~op_t() | |
| 107 | 901 | { | |
| 108 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 791 times.
|
901 | if(buf_) |
| 109 |
1/2✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
|
110 | delete[] buf_; |
| 110 | 901 | } | |
| 111 | |||
| 112 | char const* | ||
| 113 | 12 | buf() const noexcept | |
| 114 | { | ||
| 115 | 12 | return buf_; | |
| 116 | } | ||
| 117 | |||
| 118 | char const* | ||
| 119 | 240 | cbuf() const noexcept | |
| 120 | { | ||
| 121 | 240 | return cbuf_; | |
| 122 | } | ||
| 123 | |||
| 124 | char* | ||
| 125 | 12 | end() const noexcept | |
| 126 | { | ||
| 127 | 12 | return buf_ + cap_; | |
| 128 | } | ||
| 129 | |||
| 130 | table | ||
| 131 | 6 | tab() const noexcept | |
| 132 | { | ||
| 133 | 6 | return table(end()); | |
| 134 | } | ||
| 135 | |||
| 136 | static | ||
| 137 | std::size_t | ||
| 138 | growth( | ||
| 139 | std::size_t n0, | ||
| 140 | std::size_t m) noexcept; | ||
| 141 | |||
| 142 | bool | ||
| 143 | reserve(std::size_t bytes); | ||
| 144 | |||
| 145 | bool | ||
| 146 | grow( | ||
| 147 | std::size_t extra_char, | ||
| 148 | std::size_t extra_field); | ||
| 149 | |||
| 150 | void | ||
| 151 | copy_prefix( | ||
| 152 | std::size_t n, | ||
| 153 | std::size_t i) noexcept; | ||
| 154 | |||
| 155 | void | ||
| 156 | move_chars( | ||
| 157 | char* dest, | ||
| 158 | char const* src, | ||
| 159 | std::size_t n) const noexcept; | ||
| 160 | }; | ||
| 161 | |||
| 162 | /* Growth functions for containers | ||
| 163 | |||
| 164 | N1 = g( N0, M ); | ||
| 165 | |||
| 166 | g = growth function | ||
| 167 | M = minimum capacity | ||
| 168 | N0 = old size | ||
| 169 | N1 = new size | ||
| 170 | */ | ||
| 171 | std::size_t | ||
| 172 | 1631 | fields_base:: | |
| 173 | op_t:: | ||
| 174 | growth( | ||
| 175 | std::size_t n0, | ||
| 176 | std::size_t m) noexcept | ||
| 177 | { | ||
| 178 | auto const m1 = | ||
| 179 | 1631 | detail::align_up(m, alignof(entry)); | |
| 180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1631 times.
|
1631 | BOOST_ASSERT(m1 >= m); |
| 181 |
2/2✓ Branch 0 taken 1149 times.
✓ Branch 1 taken 482 times.
|
1631 | if(n0 == 0) |
| 182 | { | ||
| 183 | // exact | ||
| 184 | 1149 | return m1; | |
| 185 | } | ||
| 186 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 269 times.
|
482 | if(m1 > n0) |
| 187 | 213 | return m1; | |
| 188 | 269 | return n0; | |
| 189 | } | ||
| 190 | |||
| 191 | bool | ||
| 192 | 884 | fields_base:: | |
| 193 | op_t:: | ||
| 194 | reserve( | ||
| 195 | std::size_t bytes) | ||
| 196 | { | ||
| 197 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 850 times.
|
884 | if(bytes > self_.max_capacity_in_bytes()) |
| 198 | { | ||
| 199 | // max capacity exceeded | ||
| 200 | 34 | detail::throw_length_error(); | |
| 201 | } | ||
| 202 | 850 | auto n = growth( | |
| 203 | 850 | self_.h_.cap, bytes); | |
| 204 |
2/2✓ Branch 0 taken 152 times.
✓ Branch 1 taken 698 times.
|
850 | if(n <= self_.h_.cap) |
| 205 | 152 | return false; | |
| 206 | 698 | auto buf = new char[n]; | |
| 207 | 698 | buf_ = self_.h_.buf; | |
| 208 | 698 | cbuf_ = self_.h_.cbuf; | |
| 209 | 698 | cap_ = self_.h_.cap; | |
| 210 | 698 | self_.h_.buf = buf; | |
| 211 | 698 | self_.h_.cbuf = buf; | |
| 212 | 698 | self_.h_.cap = n; | |
| 213 | 698 | return true; | |
| 214 | } | ||
| 215 | |||
| 216 | bool | ||
| 217 | 783 | fields_base:: | |
| 218 | op_t:: | ||
| 219 | grow( | ||
| 220 | std::size_t extra_char, | ||
| 221 | std::size_t extra_field) | ||
| 222 | { | ||
| 223 | // extra_field is naturally limited | ||
| 224 | // by max_offset, since each field | ||
| 225 | // is at least 4 bytes: "X:\r\n" | ||
| 226 |
2/4✓ Branch 0 taken 783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 783 times.
✗ Branch 3 not taken.
|
783 | BOOST_ASSERT( |
| 227 | extra_field <= max_offset && | ||
| 228 | extra_field <= static_cast< | ||
| 229 | std::size_t>( | ||
| 230 | max_offset - self_.h_.count)); | ||
| 231 |
2/2✓ Branch 0 taken 781 times.
✓ Branch 1 taken 2 times.
|
783 | if( extra_char > max_offset || |
| 232 | 781 | extra_char > static_cast<std::size_t>( | |
| 233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 781 times.
|
781 | max_offset - self_.h_.size)) |
| 234 | 2 | detail::throw_length_error(); | |
| 235 | 1562 | auto n1 = growth( | |
| 236 | 781 | self_.h_.cap, | |
| 237 | detail::header::bytes_needed( | ||
| 238 | 781 | self_.h_.size + extra_char, | |
| 239 | 781 | self_.h_.count + extra_field)); | |
| 240 | 781 | return reserve(n1); | |
| 241 | } | ||
| 242 | |||
| 243 | void | ||
| 244 | ✗ | fields_base:: | |
| 245 | op_t:: | ||
| 246 | copy_prefix( | ||
| 247 | std::size_t n, | ||
| 248 | std::size_t i) noexcept | ||
| 249 | { | ||
| 250 | // copy first n chars | ||
| 251 | ✗ | std::memcpy( | |
| 252 | ✗ | self_.h_.buf, | |
| 253 | ✗ | cbuf_, | |
| 254 | n); | ||
| 255 | // copy first i entries | ||
| 256 | ✗ | if(i > 0) | |
| 257 | ✗ | std::memcpy( | |
| 258 | ✗ | self_.h_.tab_() - i, | |
| 259 | reinterpret_cast<entry*>( | ||
| 260 | ✗ | buf_ + cap_) - i, | |
| 261 | i * sizeof(entry)); | ||
| 262 | ✗ | } | |
| 263 | |||
| 264 | void | ||
| 265 | 133 | fields_base:: | |
| 266 | op_t:: | ||
| 267 | move_chars( | ||
| 268 | char* dest, | ||
| 269 | char const* src, | ||
| 270 | std::size_t n) const noexcept | ||
| 271 | { | ||
| 272 | 133 | detail::move_chars( | |
| 273 | 133 | dest, src, n, s0_, s1_); | |
| 274 | 133 | } | |
| 275 | |||
| 276 | //------------------------------------------------ | ||
| 277 | |||
| 278 | 228 | fields_base:: | |
| 279 | fields_base( | ||
| 280 | ✗ | detail::kind k) noexcept | |
| 281 | 228 | : fields_base(k, 0) | |
| 282 | { | ||
| 283 | 228 | } | |
| 284 | |||
| 285 | 252 | fields_base:: | |
| 286 | fields_base( | ||
| 287 | detail::kind k, | ||
| 288 | ✗ | std::size_t size) | |
| 289 | ✗ | : fields_view_base(&h_) | |
| 290 | 252 | , h_(k) | |
| 291 | { | ||
| 292 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 117 times.
|
252 | if( size > 0 ) |
| 293 | { | ||
| 294 | 18 | h_.max_cap = detail::align_up( | |
| 295 | size, alignof(detail::header::entry)); | ||
| 296 | 18 | reserve_bytes(size); | |
| 297 | } | ||
| 298 | 252 | } | |
| 299 | |||
| 300 | 48 | fields_base:: | |
| 301 | fields_base( | ||
| 302 | detail::kind k, | ||
| 303 | std::size_t size, | ||
| 304 | ✗ | std::size_t max_size) | |
| 305 | ✗ | : fields_view_base(&h_) | |
| 306 | 48 | , h_(k) | |
| 307 | { | ||
| 308 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
|
48 | if( size > max_size ) |
| 309 | 12 | detail::throw_length_error(); | |
| 310 | |||
| 311 | 36 | h_.max_cap = detail::align_up( | |
| 312 | max_size, alignof(detail::header::entry)); | ||
| 313 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
36 | if( size > 0 ) |
| 314 | { | ||
| 315 | 30 | reserve_bytes(size); | |
| 316 | } | ||
| 317 | 36 | } | |
| 318 | |||
| 319 | // copy s and parse it | ||
| 320 | 1058 | fields_base:: | |
| 321 | fields_base( | ||
| 322 | detail::kind k, | ||
| 323 | ✗ | core::string_view s) | |
| 324 | ✗ | : fields_view_base(&h_) | |
| 325 | 1058 | , h_(detail::empty{k}) | |
| 326 | { | ||
| 327 | 1058 | auto n = detail::header::count_crlf(s); | |
| 328 |
2/2✓ Branch 0 taken 241 times.
✓ Branch 1 taken 288 times.
|
1058 | if(h_.kind == detail::kind::fields) |
| 329 | { | ||
| 330 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 240 times.
|
482 | if(n < 1) |
| 331 | 2 | detail::throw_invalid_argument(); | |
| 332 | 480 | n -= 1; | |
| 333 | } | ||
| 334 | else | ||
| 335 | { | ||
| 336 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 286 times.
|
576 | if(n < 2) |
| 337 | 4 | detail::throw_invalid_argument(); | |
| 338 | 572 | n -= 2; | |
| 339 | } | ||
| 340 | 2104 | op_t op(*this); | |
| 341 |
1/2✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
|
1052 | op.grow(s.size(), n); |
| 342 |
1/2✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
|
1052 | s.copy(h_.buf, s.size()); |
| 343 | 1052 | system::error_code ec; | |
| 344 | // VFALCO This is using defaults? | ||
| 345 | 1052 | header_limits lim; | |
| 346 | 1052 | h_.parse(s.size(), lim, ec); | |
| 347 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 526 times.
|
1052 | if(ec.failed()) |
| 348 | ✗ | detail::throw_system_error(ec); | |
| 349 | 1052 | } | |
| 350 | |||
| 351 | // construct a complete copy of h | ||
| 352 | 52 | fields_base:: | |
| 353 | fields_base( | ||
| 354 | 28 | detail::header const& h) | |
| 355 | 28 | : fields_view_base(&h_) | |
| 356 | 52 | , h_(h.kind) | |
| 357 | { | ||
| 358 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 18 times.
|
52 | if(h.is_default()) |
| 359 | { | ||
| 360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
16 | BOOST_ASSERT(h.cap == 0); |
| 361 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
16 | BOOST_ASSERT(h.buf == nullptr); |
| 362 | 16 | h_ = h; | |
| 363 | 16 | return; | |
| 364 | } | ||
| 365 | |||
| 366 | // allocate and copy the buffer | ||
| 367 | 72 | op_t op(*this); | |
| 368 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | op.grow(h.size, h.count); |
| 369 | 36 | h.assign_to(h_); | |
| 370 | 36 | std::memcpy( | |
| 371 | 36 | h_.buf, h.cbuf, h.size); | |
| 372 | 36 | h.copy_table(h_.buf + h_.cap); | |
| 373 | } | ||
| 374 | |||
| 375 | //------------------------------------------------ | ||
| 376 | |||
| 377 | 1392 | fields_base:: | |
| 378 | 1420 | ~fields_base() | |
| 379 | { | ||
| 380 |
2/2✓ Branch 0 taken 608 times.
✓ Branch 1 taken 88 times.
|
1392 | if(h_.buf) |
| 381 |
1/2✓ Branch 0 taken 608 times.
✗ Branch 1 not taken.
|
1216 | delete[] h_.buf; |
| 382 | 1392 | } | |
| 383 | |||
| 384 | //------------------------------------------------ | ||
| 385 | // | ||
| 386 | // Capacity | ||
| 387 | // | ||
| 388 | //------------------------------------------------ | ||
| 389 | |||
| 390 | void | ||
| 391 | 10 | fields_base:: | |
| 392 | clear() noexcept | ||
| 393 | { | ||
| 394 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if(! h_.buf) |
| 395 | 5 | return; | |
| 396 | using H = | ||
| 397 | detail::header; | ||
| 398 | auto const& h = | ||
| 399 | 5 | *H::get_default( | |
| 400 | 5 | h_.kind); | |
| 401 | 5 | h.assign_to(h_); | |
| 402 | 5 | std::memcpy( | |
| 403 | 5 | h_.buf, | |
| 404 | 5 | h.cbuf, | |
| 405 | 5 | h_.size); | |
| 406 | } | ||
| 407 | |||
| 408 | void | ||
| 409 | 103 | fields_base:: | |
| 410 | reserve_bytes( | ||
| 411 | std::size_t n) | ||
| 412 | { | ||
| 413 | 134 | op_t op(*this); | |
| 414 |
4/4✓ Branch 1 taken 72 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 38 times.
|
103 | if(! op.reserve(n)) |
| 415 | 34 | return; | |
| 416 | 76 | std::memcpy( | |
| 417 | 38 | h_.buf, op.cbuf(), h_.size); | |
| 418 | 38 | auto const nt = | |
| 419 | 38 | sizeof(entry) * h_.count; | |
| 420 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 32 times.
|
38 | if(nt > 0) |
| 421 | 6 | std::memcpy( | |
| 422 | 6 | h_.buf + h_.cap - nt, | |
| 423 | 6 | op.end() - nt, | |
| 424 | nt); | ||
| 425 | } | ||
| 426 | |||
| 427 | void | ||
| 428 | 7 | fields_base:: | |
| 429 | shrink_to_fit() noexcept | ||
| 430 | { | ||
| 431 | 14 | if(detail::header::bytes_needed( | |
| 432 | 7 | h_.size, h_.count) >= | |
| 433 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
|
7 | h_.cap) |
| 434 | 3 | return; | |
| 435 | 8 | fields_base tmp(h_); | |
| 436 | 4 | tmp.h_.swap(h_); | |
| 437 | } | ||
| 438 | |||
| 439 | //------------------------------------------------ | ||
| 440 | // | ||
| 441 | // Modifiers | ||
| 442 | // | ||
| 443 | //------------------------------------------------ | ||
| 444 | |||
| 445 | std::size_t | ||
| 446 | 24 | fields_base:: | |
| 447 | erase( | ||
| 448 | field id) noexcept | ||
| 449 | { | ||
| 450 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | BOOST_ASSERT( |
| 451 | id != field::unknown); | ||
| 452 | #if 1 | ||
| 453 | 24 | auto const end_ = end(); | |
| 454 | 24 | auto it = find_last(end_, id); | |
| 455 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 21 times.
|
24 | if(it == end_) |
| 456 | 3 | return 0; | |
| 457 | 21 | std::size_t n = 1; | |
| 458 | 21 | auto const begin_ = begin(); | |
| 459 | 21 | raw_erase(it.i_); | |
| 460 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 21 times.
|
57 | while(it != begin_) |
| 461 | { | ||
| 462 | 36 | --it; | |
| 463 |
2/2✓ Branch 2 taken 25 times.
✓ Branch 3 taken 11 times.
|
36 | if(it->id == id) |
| 464 | { | ||
| 465 | 25 | raw_erase(it.i_); | |
| 466 | 25 | ++n; | |
| 467 | } | ||
| 468 | } | ||
| 469 | 21 | h_.on_erase_all(id); | |
| 470 | 21 | return n; | |
| 471 | #else | ||
| 472 | std::size_t n = 0; | ||
| 473 | auto it0 = find(id); | ||
| 474 | auto const end_ = end(); | ||
| 475 | if(it0 != end_) | ||
| 476 | { | ||
| 477 | auto it1 = it0; | ||
| 478 | std::size_t total = 0; | ||
| 479 | std::size_t size = 0; | ||
| 480 | // [it0, it1) run of id | ||
| 481 | for(;;) | ||
| 482 | { | ||
| 483 | size += length(it1.i_); | ||
| 484 | ++it1; | ||
| 485 | if(it1 == end_) | ||
| 486 | goto finish; | ||
| 487 | if(it1->id != id) | ||
| 488 | break; | ||
| 489 | } | ||
| 490 | std::memmove( | ||
| 491 | h_.buf + offset(it0.i_), | ||
| 492 | h_.buf + offset(it1.i_), | ||
| 493 | h_.size - offset(it2.i_)); | ||
| 494 | |||
| 495 | finish: | ||
| 496 | h_.size -= size; | ||
| 497 | h_.count -= n; | ||
| 498 | } | ||
| 499 | return n; | ||
| 500 | #endif | ||
| 501 | } | ||
| 502 | |||
| 503 | std::size_t | ||
| 504 | 18 | fields_base:: | |
| 505 | erase( | ||
| 506 | core::string_view name) noexcept | ||
| 507 | { | ||
| 508 | 18 | auto it0 = find(name); | |
| 509 | 18 | auto const end_ = end(); | |
| 510 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
|
18 | if(it0 == end_) |
| 511 | 3 | return 0; | |
| 512 | 15 | auto it = end_; | |
| 513 | 15 | std::size_t n = 1; | |
| 514 | 15 | auto const id = it0->id; | |
| 515 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
|
15 | if(id == field::unknown) |
| 516 | { | ||
| 517 | // fix self-intersection | ||
| 518 | 6 | name = it0->name; | |
| 519 | |||
| 520 | for(;;) | ||
| 521 | { | ||
| 522 | 24 | --it; | |
| 523 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 18 times.
|
24 | if(it == it0) |
| 524 | 6 | break; | |
| 525 | 18 | if(grammar::ci_is_equal( | |
| 526 |
2/2✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
|
36 | it->name, name)) |
| 527 | { | ||
| 528 | 9 | raw_erase(it.i_); | |
| 529 | 9 | ++n; | |
| 530 | } | ||
| 531 | } | ||
| 532 | 6 | raw_erase(it.i_); | |
| 533 | } | ||
| 534 | else | ||
| 535 | { | ||
| 536 | for(;;) | ||
| 537 | { | ||
| 538 | 21 | --it; | |
| 539 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 12 times.
|
21 | if(it == it0) |
| 540 | 9 | break; | |
| 541 |
2/2✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
|
12 | if(it->id == id) |
| 542 | { | ||
| 543 | 6 | raw_erase(it.i_); | |
| 544 | 6 | ++n; | |
| 545 | } | ||
| 546 | } | ||
| 547 | 9 | raw_erase(it.i_); | |
| 548 | 9 | h_.on_erase_all(id); | |
| 549 | } | ||
| 550 | 15 | return n; | |
| 551 | } | ||
| 552 | |||
| 553 | //------------------------------------------------ | ||
| 554 | |||
| 555 | system::result<void> | ||
| 556 | 23 | fields_base:: | |
| 557 | set( | ||
| 558 | iterator it, | ||
| 559 | core::string_view value) | ||
| 560 | { | ||
| 561 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | auto rv = verify_field_value(value); |
| 562 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 21 times.
|
23 | if( rv.has_error() ) |
| 563 | 2 | return rv.error(); | |
| 564 | |||
| 565 | 21 | value = rv->value; | |
| 566 | 21 | bool has_obs_fold = rv->has_obs_fold; | |
| 567 | |||
| 568 | 21 | auto const i = it.i_; | |
| 569 | 21 | auto tab = h_.tab(); | |
| 570 | 21 | auto const& e0 = tab[i]; | |
| 571 | 21 | auto const pos0 = offset(i); | |
| 572 | 21 | auto const pos1 = offset(i + 1); | |
| 573 | std::ptrdiff_t dn = | ||
| 574 | 21 | value.size() - | |
| 575 | 21 | it->value.size(); | |
| 576 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | if( value.empty() && |
| 577 |
1/4✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
|
21 | ! it->value.empty()) |
| 578 | ✗ | --dn; // remove SP | |
| 579 | 21 | else if( | |
| 580 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
|
21 | it->value.empty() && |
| 581 | ✗ | ! value.empty()) | |
| 582 | ✗ | ++dn; // add SP | |
| 583 | |||
| 584 | 42 | op_t op(*this, &value); | |
| 585 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 15 times.
|
27 | if( dn > 0 && |
| 586 |
2/4✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
12 | op.grow(value.size() - |
| 587 |
2/2✓ Branch 3 taken 6 times.
✓ Branch 4 taken 15 times.
|
27 | it->value.size(), 0)) |
| 588 | { | ||
| 589 | // reallocated | ||
| 590 | 6 | auto dest = h_.buf + | |
| 591 | 6 | pos0 + e0.nn + 1; | |
| 592 | 12 | std::memcpy( | |
| 593 | 6 | h_.buf, | |
| 594 | 6 | op.buf(), | |
| 595 | 6 | dest - h_.buf); | |
| 596 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if(! value.empty()) |
| 597 | { | ||
| 598 | 6 | *dest++ = ' '; | |
| 599 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | value.copy( |
| 600 | dest, | ||
| 601 | value.size()); | ||
| 602 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if( has_obs_fold ) |
| 603 | 3 | detail::remove_obs_fold( | |
| 604 | 3 | dest, dest + value.size()); | |
| 605 | 6 | dest += value.size(); | |
| 606 | } | ||
| 607 | 6 | *dest++ = '\r'; | |
| 608 | 6 | *dest++ = '\n'; | |
| 609 | 12 | std::memcpy( | |
| 610 | 6 | h_.buf + pos1 + dn, | |
| 611 | 12 | op.buf() + pos1, | |
| 612 | 6 | h_.size - pos1); | |
| 613 | 12 | std::memcpy( | |
| 614 | 6 | h_.buf + h_.cap - | |
| 615 | 6 | sizeof(entry) * h_.count, | |
| 616 | 6 | &op.tab()[h_.count - 1], | |
| 617 | 6 | sizeof(entry) * h_.count); | |
| 618 | } | ||
| 619 | else | ||
| 620 | { | ||
| 621 | // copy the value first | ||
| 622 | 30 | auto dest = h_.buf + pos0 + | |
| 623 | 15 | it->name.size() + 1; | |
| 624 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | if(! value.empty()) |
| 625 | { | ||
| 626 | 15 | *dest++ = ' '; | |
| 627 |
1/2✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | value.copy( |
| 628 | dest, | ||
| 629 | value.size()); | ||
| 630 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if( has_obs_fold ) |
| 631 | ✗ | detail::remove_obs_fold( | |
| 632 | ✗ | dest, dest + value.size()); | |
| 633 | 15 | dest += value.size(); | |
| 634 | } | ||
| 635 | 15 | op.move_chars( | |
| 636 | 15 | h_.buf + pos1 + dn, | |
| 637 | 15 | h_.buf + pos1, | |
| 638 | 15 | h_.size - pos1); | |
| 639 | 15 | *dest++ = '\r'; | |
| 640 | 15 | *dest++ = '\n'; | |
| 641 | } | ||
| 642 | { | ||
| 643 | // update tab | ||
| 644 | 21 | auto ft = h_.tab(); | |
| 645 | 28 | for(std::size_t j = h_.count - 1; | |
| 646 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 21 times.
|
28 | j > i; --j) |
| 647 | 7 | ft[j] = ft[j] + dn; | |
| 648 | 21 | auto& e = ft[i]; | |
| 649 | 42 | e.vp = e.np + e.nn + | |
| 650 | 21 | 1 + ! value.empty(); | |
| 651 | 21 | e.vn = static_cast< | |
| 652 | 21 | offset_type>(value.size()); | |
| 653 | 21 | h_.size = static_cast< | |
| 654 | 21 | offset_type>(h_.size + dn); | |
| 655 | } | ||
| 656 | 21 | auto const id = it->id; | |
| 657 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 12 times.
|
21 | if(h_.is_special(id)) |
| 658 | { | ||
| 659 | // replace first char of name | ||
| 660 | // with null to hide metadata | ||
| 661 | 9 | char saved = h_.buf[pos0]; | |
| 662 | 9 | auto& e = h_.tab()[i]; | |
| 663 | 9 | e.id = field::unknown; | |
| 664 | 9 | h_.buf[pos0] = '\0'; | |
| 665 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | h_.on_erase(id); |
| 666 | 9 | h_.buf[pos0] = saved; // restore | |
| 667 | 9 | e.id = id; | |
| 668 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | h_.on_insert(id, it->value); |
| 669 | } | ||
| 670 | 21 | return {}; | |
| 671 | } | ||
| 672 | |||
| 673 | // erase existing fields with id | ||
| 674 | // and then add the field with value | ||
| 675 | system::result<void> | ||
| 676 | 23 | fields_base:: | |
| 677 | set( | ||
| 678 | field id, | ||
| 679 | core::string_view value) | ||
| 680 | { | ||
| 681 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | BOOST_ASSERT( |
| 682 | id != field::unknown); | ||
| 683 | |||
| 684 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | auto rv = verify_field_value(value); |
| 685 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 21 times.
|
23 | if( rv.has_error() ) |
| 686 | 2 | return rv.error(); | |
| 687 | |||
| 688 | 21 | value = rv->value; | |
| 689 | 21 | bool has_obs_fold = rv->has_obs_fold; | |
| 690 | |||
| 691 | 21 | auto const i0 = h_.find(id); | |
| 692 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
|
21 | if(i0 != h_.count) |
| 693 | { | ||
| 694 | // field exists | ||
| 695 | 15 | auto const ft = h_.tab(); | |
| 696 | { | ||
| 697 | // provide strong guarantee | ||
| 698 | auto const n0 = | ||
| 699 | 15 | h_.size - length(i0); | |
| 700 | auto const n = | ||
| 701 | 15 | ft[i0].nn + 2 + | |
| 702 | 15 | value.size() + 2; | |
| 703 | // VFALCO missing overflow check | ||
| 704 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | reserve_bytes(n0 + n); |
| 705 | } | ||
| 706 | 15 | erase_all_impl(i0, id); | |
| 707 | } | ||
| 708 | |||
| 709 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | insert_impl_unchecked( |
| 710 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | id, to_string(id), value, h_.count, has_obs_fold); |
| 711 | 21 | return {}; | |
| 712 | } | ||
| 713 | |||
| 714 | // erase existing fields with name | ||
| 715 | // and then add the field with value | ||
| 716 | system::result<void> | ||
| 717 | 24 | fields_base:: | |
| 718 | set( | ||
| 719 | core::string_view name, | ||
| 720 | core::string_view value) | ||
| 721 | { | ||
| 722 | { | ||
| 723 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | auto rv = verify_field_name(name); |
| 724 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 22 times.
|
24 | if( rv.has_error() ) |
| 725 | 2 | return rv.error(); | |
| 726 | } | ||
| 727 | |||
| 728 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | auto rv = verify_field_value(value); |
| 729 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
|
22 | if( rv.has_error() ) |
| 730 | 2 | return rv.error(); | |
| 731 | |||
| 732 | 20 | value = rv->value; | |
| 733 | 20 | bool has_obs_fold = rv->has_obs_fold; | |
| 734 | |||
| 735 | 20 | auto const i0 = h_.find(name); | |
| 736 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5 times.
|
20 | if(i0 != h_.count) |
| 737 | { | ||
| 738 | // field exists | ||
| 739 | 15 | auto const ft = h_.tab(); | |
| 740 | 15 | auto const id = ft[i0].id; | |
| 741 | { | ||
| 742 | // provide strong guarantee | ||
| 743 | auto const n0 = | ||
| 744 | 15 | h_.size - length(i0); | |
| 745 | auto const n = | ||
| 746 | 15 | ft[i0].nn + 2 + | |
| 747 | 15 | value.size() + 2; | |
| 748 | // VFALCO missing overflow check | ||
| 749 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | reserve_bytes(n0 + n); |
| 750 | } | ||
| 751 | // VFALCO simple algorithm but | ||
| 752 | // costs one extra memmove | ||
| 753 | 15 | erase_all_impl(i0, id); | |
| 754 | } | ||
| 755 |
2/2✓ Branch 1 taken 19 times.
✓ Branch 2 taken 1 times.
|
20 | insert_impl_unchecked( |
| 756 | string_to_field(name), | ||
| 757 | 20 | name, value, h_.count, has_obs_fold); | |
| 758 | 19 | return {}; | |
| 759 | } | ||
| 760 | |||
| 761 | //------------------------------------------------ | ||
| 762 | // | ||
| 763 | // (implementation) | ||
| 764 | // | ||
| 765 | //------------------------------------------------ | ||
| 766 | |||
| 767 | // copy start line and fields | ||
| 768 | void | ||
| 769 | 17 | fields_base:: | |
| 770 | copy_impl( | ||
| 771 | detail::header const& h) | ||
| 772 | { | ||
| 773 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | BOOST_ASSERT( |
| 774 | h.kind == ph_->kind); | ||
| 775 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 3 times.
|
17 | if(! h.is_default()) |
| 776 | { | ||
| 777 | auto const n = | ||
| 778 | 14 | detail::header::bytes_needed( | |
| 779 | 14 | h.size, h.count); | |
| 780 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | if(n <= h_.cap) |
| 781 | { | ||
| 782 | // no realloc | ||
| 783 | 7 | h.assign_to(h_); | |
| 784 | 7 | h.copy_table( | |
| 785 | 7 | h_.buf + h_.cap); | |
| 786 | 7 | std::memcpy( | |
| 787 | 7 | h_.buf, | |
| 788 | 7 | h.cbuf, | |
| 789 | 7 | h.size); | |
| 790 | 7 | return; | |
| 791 | } | ||
| 792 | } | ||
| 793 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
20 | fields_base tmp(h); |
| 794 | 10 | tmp.h_.swap(h_); | |
| 795 | } | ||
| 796 | |||
| 797 | void | ||
| 798 | 233 | fields_base:: | |
| 799 | insert_impl_unchecked( | ||
| 800 | field id, | ||
| 801 | core::string_view name, | ||
| 802 | core::string_view value, | ||
| 803 | std::size_t before, | ||
| 804 | bool has_obs_fold) | ||
| 805 | { | ||
| 806 | 233 | auto const tab0 = h_.tab_(); | |
| 807 | 233 | auto const pos = offset(before); | |
| 808 | auto const n = | ||
| 809 | 233 | name.size() + // name | |
| 810 | 233 | 1 + // ':' | |
| 811 | 233 | ! value.empty() + // [SP] | |
| 812 | 233 | value.size() + // value | |
| 813 | 233 | 2; // CRLF | |
| 814 | |||
| 815 | 466 | op_t op(*this, &name, &value); | |
| 816 |
4/4✓ Branch 1 taken 228 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 110 times.
✓ Branch 4 taken 118 times.
|
233 | if(op.grow(n, 1)) |
| 817 | { | ||
| 818 | // reallocated | ||
| 819 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 18 times.
|
110 | if(pos > 0) |
| 820 | 92 | std::memcpy( | |
| 821 | 92 | h_.buf, | |
| 822 | 92 | op.cbuf(), | |
| 823 | pos); | ||
| 824 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 73 times.
|
110 | if(before > 0) |
| 825 | 74 | std::memcpy( | |
| 826 | 37 | h_.tab_() - before, | |
| 827 | 37 | tab0 - before, | |
| 828 | before * sizeof(entry)); | ||
| 829 | 220 | std::memcpy( | |
| 830 | 110 | h_.buf + pos + n, | |
| 831 | 110 | op.cbuf() + pos, | |
| 832 | 110 | h_.size - pos); | |
| 833 | } | ||
| 834 | else | ||
| 835 | { | ||
| 836 | 118 | op.move_chars( | |
| 837 | 118 | h_.buf + pos + n, | |
| 838 | 118 | h_.buf + pos, | |
| 839 | 118 | h_.size - pos); | |
| 840 | } | ||
| 841 | |||
| 842 | // serialize | ||
| 843 | { | ||
| 844 | 228 | auto dest = h_.buf + pos; | |
| 845 |
1/2✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
|
228 | name.copy(dest, name.size()); |
| 846 | 228 | dest += name.size(); | |
| 847 | 228 | *dest++ = ':'; | |
| 848 |
2/2✓ Branch 1 taken 216 times.
✓ Branch 2 taken 12 times.
|
228 | if(! value.empty()) |
| 849 | { | ||
| 850 | 216 | *dest++ = ' '; | |
| 851 |
1/2✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
|
216 | value.copy( |
| 852 | dest, value.size()); | ||
| 853 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 201 times.
|
216 | if( has_obs_fold ) |
| 854 | 15 | detail::remove_obs_fold( | |
| 855 | 15 | dest, dest + value.size()); | |
| 856 | 216 | dest += value.size(); | |
| 857 | } | ||
| 858 | 228 | *dest++ = '\r'; | |
| 859 | 228 | *dest = '\n'; | |
| 860 | } | ||
| 861 | |||
| 862 | // update table | ||
| 863 | 228 | auto const tab = h_.tab_(); | |
| 864 | { | ||
| 865 | 228 | auto i = h_.count - before; | |
| 866 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 174 times.
|
228 | if(i > 0) |
| 867 | { | ||
| 868 | 54 | auto p0 = tab0 - h_.count; | |
| 869 | 54 | auto p = tab - h_.count - 1; | |
| 870 | 54 | do | |
| 871 | { | ||
| 872 | 108 | *p++ = *p0++ + n; | |
| 873 | } | ||
| 874 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
|
108 | while(--i); |
| 875 | } | ||
| 876 | } | ||
| 877 | 228 | auto& e = tab[0 - static_cast<std::ptrdiff_t>(before) - 1]; | |
| 878 | 228 | e.np = static_cast<offset_type>( | |
| 879 | 228 | pos - h_.prefix); | |
| 880 | 228 | e.nn = static_cast< | |
| 881 | 228 | offset_type>(name.size()); | |
| 882 | 228 | e.vp = static_cast<offset_type>( | |
| 883 | 456 | pos - h_.prefix + | |
| 884 | 228 | name.size() + 1 + | |
| 885 | 228 | ! value.empty()); | |
| 886 | 228 | e.vn = static_cast< | |
| 887 | 228 | offset_type>(value.size()); | |
| 888 | 228 | e.id = id; | |
| 889 | |||
| 890 | // update container | ||
| 891 | 228 | h_.count++; | |
| 892 | 228 | h_.size = static_cast< | |
| 893 | 228 | offset_type>(h_.size + n); | |
| 894 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 30 times.
|
228 | if( id != field::unknown) |
| 895 |
1/2✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
|
198 | h_.on_insert(id, value); |
| 896 | 228 | } | |
| 897 | |||
| 898 | system::result<void> | ||
| 899 | 209 | fields_base:: | |
| 900 | insert_impl( | ||
| 901 | field id, | ||
| 902 | core::string_view name, | ||
| 903 | core::string_view value, | ||
| 904 | std::size_t before) | ||
| 905 | { | ||
| 906 | { | ||
| 907 |
1/2✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
|
209 | auto rv = verify_field_name(name); |
| 908 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 205 times.
|
209 | if( rv.has_error() ) |
| 909 | 4 | return rv.error(); | |
| 910 | } | ||
| 911 | |||
| 912 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | auto rv = verify_field_value(value); |
| 913 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 192 times.
|
205 | if( rv.has_error() ) |
| 914 | 13 | return rv.error(); | |
| 915 | |||
| 916 |
2/2✓ Branch 1 taken 188 times.
✓ Branch 2 taken 4 times.
|
192 | insert_impl_unchecked( |
| 917 | 192 | id, name, rv->value, before, rv->has_obs_fold); | |
| 918 | 188 | return {}; | |
| 919 | } | ||
| 920 | |||
| 921 | // erase i and update metadata | ||
| 922 | void | ||
| 923 | 31 | fields_base:: | |
| 924 | erase_impl( | ||
| 925 | std::size_t i, | ||
| 926 | field id) noexcept | ||
| 927 | { | ||
| 928 | 31 | raw_erase(i); | |
| 929 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
31 | if(id != field::unknown) |
| 930 | 31 | h_.on_erase(id); | |
| 931 | 31 | } | |
| 932 | |||
| 933 | //------------------------------------------------ | ||
| 934 | |||
| 935 | void | ||
| 936 | 155 | fields_base:: | |
| 937 | raw_erase( | ||
| 938 | std::size_t i) noexcept | ||
| 939 | { | ||
| 940 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
|
155 | BOOST_ASSERT(i < h_.count); |
| 941 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
|
155 | BOOST_ASSERT(h_.buf != nullptr); |
| 942 | 155 | auto const p0 = offset(i); | |
| 943 | 155 | auto const p1 = offset(i + 1); | |
| 944 | 155 | std::memmove( | |
| 945 | 155 | h_.buf + p0, | |
| 946 | 155 | h_.buf + p1, | |
| 947 | 155 | h_.size - p1); | |
| 948 | 155 | auto const n = p1 - p0; | |
| 949 | 155 | --h_.count; | |
| 950 | 155 | auto ft = h_.tab(); | |
| 951 |
2/2✓ Branch 0 taken 79 times.
✓ Branch 1 taken 155 times.
|
234 | for(;i < h_.count; ++i) |
| 952 | 79 | ft[i] = ft[i + 1] - n; | |
| 953 | 155 | h_.size = static_cast< | |
| 954 | 155 | offset_type>(h_.size - n); | |
| 955 | 155 | } | |
| 956 | |||
| 957 | //------------------------------------------------ | ||
| 958 | |||
| 959 | // erase all fields with id | ||
| 960 | // and update metadata | ||
| 961 | std::size_t | ||
| 962 | 30 | fields_base:: | |
| 963 | erase_all_impl( | ||
| 964 | std::size_t i0, | ||
| 965 | field id) noexcept | ||
| 966 | { | ||
| 967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | BOOST_ASSERT( |
| 968 | id != field::unknown); | ||
| 969 | 30 | std::size_t n = 1; | |
| 970 | 30 | std::size_t i = h_.count - 1; | |
| 971 | 30 | auto const ft = h_.tab(); | |
| 972 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 30 times.
|
58 | while(i > i0) |
| 973 | { | ||
| 974 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 15 times.
|
28 | if(ft[i].id == id) |
| 975 | { | ||
| 976 | 13 | raw_erase(i); | |
| 977 | 13 | ++n; | |
| 978 | } | ||
| 979 | // go backwards to | ||
| 980 | // reduce memmoves | ||
| 981 | 28 | --i; | |
| 982 | } | ||
| 983 | 30 | raw_erase(i0); | |
| 984 | 30 | h_.on_erase_all(id); | |
| 985 | 30 | return n; | |
| 986 | } | ||
| 987 | |||
| 988 | // return i-th field absolute offset | ||
| 989 | std::size_t | ||
| 990 | 645 | fields_base:: | |
| 991 | offset( | ||
| 992 | std::size_t i) const noexcept | ||
| 993 | { | ||
| 994 |
2/2✓ Branch 0 taken 259 times.
✓ Branch 1 taken 386 times.
|
645 | if(i == 0) |
| 995 | 259 | return h_.prefix; | |
| 996 |
2/2✓ Branch 0 taken 191 times.
✓ Branch 1 taken 195 times.
|
386 | if(i < h_.count) |
| 997 | 382 | return h_.prefix + | |
| 998 | 191 | h_.tab_()[0-(static_cast<std::ptrdiff_t>(i) + 1)].np; | |
| 999 | // make final CRLF the last "field" | ||
| 1000 | //BOOST_ASSERT(i == h_.count); | ||
| 1001 | 195 | return h_.size - 2; | |
| 1002 | } | ||
| 1003 | |||
| 1004 | // return i-th field absolute length | ||
| 1005 | std::size_t | ||
| 1006 | 30 | fields_base:: | |
| 1007 | length( | ||
| 1008 | std::size_t i) const noexcept | ||
| 1009 | { | ||
| 1010 | return | ||
| 1011 | 30 | offset(i + 1) - | |
| 1012 | 30 | offset(i); | |
| 1013 | } | ||
| 1014 | |||
| 1015 | //------------------------------------------------ | ||
| 1016 | |||
| 1017 | // erase n fields matching id | ||
| 1018 | // without updating metadata | ||
| 1019 | void | ||
| 1020 | 4 | fields_base:: | |
| 1021 | raw_erase_n( | ||
| 1022 | field id, | ||
| 1023 | std::size_t n) noexcept | ||
| 1024 | { | ||
| 1025 | // iterate in reverse | ||
| 1026 | 4 | auto e = &h_.tab()[h_.count]; | |
| 1027 | 4 | auto const e0 = &h_.tab()[0]; | |
| 1028 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | while(n > 0) |
| 1029 | { | ||
| 1030 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | BOOST_ASSERT(e != e0); |
| 1031 | 6 | ++e; // decrement | |
| 1032 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | if(e->id == id) |
| 1033 | { | ||
| 1034 | 5 | raw_erase(e0 - e); | |
| 1035 | 5 | --n; | |
| 1036 | } | ||
| 1037 | } | ||
| 1038 | 4 | } | |
| 1039 | |||
| 1040 | } // http_proto | ||
| 1041 | } // boost | ||
| 1042 |