97.44% Lines (685/703) 98.57% Functions (69/70)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2025 Mohammad Nejati 3   // Copyright (c) 2025 Mohammad Nejati
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 5   // Distributed under the Boost Software License, Version 1.0. (See accompanying
6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/http 8   // Official repository: https://github.com/cppalliance/http
9   // 9   //
10   10  
11   #include <boost/http/detail/config.hpp> 11   #include <boost/http/detail/config.hpp>
12   #include <boost/http/detail/except.hpp> 12   #include <boost/http/detail/except.hpp>
13   #include <boost/http/detail/header.hpp> 13   #include <boost/http/detail/header.hpp>
14   #include <boost/http/error.hpp> 14   #include <boost/http/error.hpp>
15   #include <boost/http/field.hpp> 15   #include <boost/http/field.hpp>
16   #include <boost/http/fields_base.hpp> 16   #include <boost/http/fields_base.hpp>
17   #include <boost/http/header_limits.hpp> 17   #include <boost/http/header_limits.hpp>
18   #include <boost/http/rfc/token_rule.hpp> 18   #include <boost/http/rfc/token_rule.hpp>
19   19  
20   #include "src/detail/move_chars.hpp" 20   #include "src/detail/move_chars.hpp"
21   #include "src/rfc/detail/rules.hpp" 21   #include "src/rfc/detail/rules.hpp"
22   22  
23   #include <boost/assert.hpp> 23   #include <boost/assert.hpp>
24   #include <boost/assert/source_location.hpp> 24   #include <boost/assert/source_location.hpp>
25   #include <boost/core/detail/string_view.hpp> 25   #include <boost/core/detail/string_view.hpp>
26   #include <boost/system/result.hpp> 26   #include <boost/system/result.hpp>
27   #include <boost/url/grammar/ci_string.hpp> 27   #include <boost/url/grammar/ci_string.hpp>
28   #include <boost/url/grammar/error.hpp> 28   #include <boost/url/grammar/error.hpp>
29   #include <boost/url/grammar/parse.hpp> 29   #include <boost/url/grammar/parse.hpp>
30   #include <boost/url/grammar/token_rule.hpp> 30   #include <boost/url/grammar/token_rule.hpp>
31   31  
32   namespace boost { 32   namespace boost {
33   namespace http { 33   namespace http {
34   34  
35   namespace { 35   namespace {
36   36  
37   std::size_t 37   std::size_t
HITCBC 38   2187 align_down( 38   2187 align_down(
39   void * ptr, 39   void * ptr,
40   std::size_t size, 40   std::size_t size,
41   std::size_t alignment) 41   std::size_t alignment)
42   { 42   {
HITCBC 43   2187 auto addr = reinterpret_cast<std::uintptr_t>(ptr); 43   2187 auto addr = reinterpret_cast<std::uintptr_t>(ptr);
HITCBC 44   2187 auto aligned_end = (addr + size) & ~(alignment - 1); 44   2187 auto aligned_end = (addr + size) & ~(alignment - 1);
45   45  
HITCBC 46   2187 if(aligned_end > addr) 46   2187 if(aligned_end > addr)
HITCBC 47   2187 return aligned_end - addr; 47   2187 return aligned_end - addr;
48   48  
MISUBC 49   ✗ return 0; 49   ✗ return 0;
50   } 50   }
51   51  
52   void 52   void
HITCBC 53   241 verify_field_name( 53   241 verify_field_name(
54   core::string_view name, 54   core::string_view name,
55 - std::error_code& ec) 55 + system::error_code& ec)
56   { 56   {
HITCBC 57   241 auto rv = grammar::parse( 57   241 auto rv = grammar::parse(
58   name, detail::field_name_rule); 58   name, detail::field_name_rule);
HITCBC 59   241 if(rv.has_error()) 59   241 if(rv.has_error())
60   { 60   {
HITCBC 61 - 9 ec = error::bad_field_name; 61 + 18 ec = BOOST_HTTP_ERR(
  62 + error::bad_field_name);
62   } 63   }
HITCBC 63   241 } 64   241 }
64   65  
65   system::result<detail::field_value_rule_t::value_type> 66   system::result<detail::field_value_rule_t::value_type>
HITCBC 66   369 verify_field_value( 67   369 verify_field_value(
67   core::string_view value) 68   core::string_view value)
68   { 69   {
HITCBC 69   369 auto it = value.begin(); 70   369 auto it = value.begin();
HITCBC 70   369 auto end = value.end(); 71   369 auto end = value.end();
71   auto rv = 72   auto rv =
HITCBC 72   369 grammar::parse(it, end, detail::field_value_rule); 73   369 grammar::parse(it, end, detail::field_value_rule);
HITCBC 73   369 if( rv.has_error() ) 74   369 if( rv.has_error() )
74   { 75   {
HITCBC 75 - 7 if( rv.error() == grammar::error::need_more ) 76 + 7 if( rv.error() == condition::need_more_input )
HITCBC 76   7 return error::bad_field_value; 77   7 return error::bad_field_value;
MISUBC 77   ✗ return rv.error(); 78   ✗ return rv.error();
78   } 79   }
79   80  
HITCBC 80   362 if( rv->has_crlf ) 81   362 if( rv->has_crlf )
HITCBC 81   16 return error::bad_field_smuggle; 82   16 return error::bad_field_smuggle;
82   83  
HITCBC 83   346 if( it != end ) 84   346 if( it != end )
HITCBC 84   7 return error::bad_field_value; 85   7 return error::bad_field_value;
85   86  
HITCBC 86   339 return rv; 87   339 return rv;
87   } 88   }
88   89  
89   } // namespace 90   } // namespace
90   91  
91   class fields_base:: 92   class fields_base::
92   op_t 93   op_t
93   { 94   {
94   fields_base& self_; 95   fields_base& self_;
95   core::string_view* s0_; 96   core::string_view* s0_;
96   core::string_view* s1_; 97   core::string_view* s1_;
97   char* buf_ = nullptr; 98   char* buf_ = nullptr;
98   char const* cbuf_ = nullptr; 99   char const* cbuf_ = nullptr;
99   std::size_t cap_ = 0; 100   std::size_t cap_ = 0;
100   101  
101   public: 102   public:
102   explicit 103   explicit
HITCBC 103   997 op_t( 104   997 op_t(
104   fields_base& self, 105   fields_base& self,
105   core::string_view* s0 = nullptr, 106   core::string_view* s0 = nullptr,
106   core::string_view* s1 = nullptr) noexcept 107   core::string_view* s1 = nullptr) noexcept
HITCBC 107   997 : self_(self) 108   997 : self_(self)
HITCBC 108   997 , s0_(s0) 109   997 , s0_(s0)
HITCBC 109   997 , s1_(s1) 110   997 , s1_(s1)
110   { 111   {
HITCBC 111   997 } 112   997 }
112   113  
HITCBC 113   997 ~op_t() 114   997 ~op_t()
114   { 115   {
HITCBC 115   997 if(buf_) 116   997 if(buf_)
HITCBC 116   151 delete[] buf_; 117   151 delete[] buf_;
HITCBC 117   997 } 118   997 }
118   119  
119   char const* 120   char const*
HITCBC 120   12 buf() const noexcept 121   12 buf() const noexcept
121   { 122   {
HITCBC 122   12 return buf_; 123   12 return buf_;
123   } 124   }
124   125  
125   char const* 126   char const*
HITCBC 126   460 cbuf() const noexcept 127   460 cbuf() const noexcept
127   { 128   {
HITCBC 128   460 return cbuf_; 129   460 return cbuf_;
129   } 130   }
130   131  
131   char* 132   char*
HITCBC 132   12 end() const noexcept 133   12 end() const noexcept
133   { 134   {
HITCBC 134   12 return buf_ + cap_; 135   12 return buf_ + cap_;
135   } 136   }
136   137  
137   table 138   table
HITCBC 138   6 tab() const noexcept 139   6 tab() const noexcept
139   { 140   {
HITCBC 140   6 return table(end()); 141   6 return table(end());
141   } 142   }
142   143  
143   bool 144   bool
144   reserve(std::size_t n); 145   reserve(std::size_t n);
145   146  
146   bool 147   bool
147   grow( 148   grow(
148   std::size_t extra_char, 149   std::size_t extra_char,
149   std::size_t extra_field); 150   std::size_t extra_field);
150   151  
151   void 152   void
152   move_chars( 153   move_chars(
153   char* dest, 154   char* dest,
154   char const* src, 155   char const* src,
155   std::size_t n) const noexcept; 156   std::size_t n) const noexcept;
156   }; 157   };
157   158  
158   bool 159   bool
HITCBC 159   977 fields_base:: 160   977 fields_base::
160   op_t:: 161   op_t::
161   reserve( 162   reserve(
162   std::size_t n) 163   std::size_t n)
163   { 164   {
164   // TODO: consider using a growth factor 165   // TODO: consider using a growth factor
HITCBC 165   977 if(n > self_.max_cap_) 166   977 if(n > self_.max_cap_)
166   { 167   {
167   // max capacity exceeded 168   // max capacity exceeded
HITCBC 168   18 detail::throw_length_error(); 169   18 detail::throw_length_error();
169   } 170   }
HITCBC 170   959 if(n <= self_.h_.cap) 171   959 if(n <= self_.h_.cap)
HITCBC 171   133 return false; 172   133 return false;
HITCBC 172   826 auto buf = new char[n]; 173   826 auto buf = new char[n];
HITCBC 173   826 buf_ = self_.h_.buf; 174   826 buf_ = self_.h_.buf;
HITCBC 174   826 cbuf_ = self_.h_.cbuf; 175   826 cbuf_ = self_.h_.cbuf;
HITCBC 175   826 cap_ = self_.h_.cap; 176   826 cap_ = self_.h_.cap;
HITCBC 176   826 self_.h_.buf = buf; 177   826 self_.h_.buf = buf;
HITCBC 177   826 self_.h_.cbuf = buf; 178   826 self_.h_.cbuf = buf;
HITCBC 178   826 self_.h_.cap = n; 179   826 self_.h_.cap = n;
HITCBC 179   826 return true; 180   826 return true;
180   } 181   }
181   182  
182   bool 183   bool
HITCBC 183   884 fields_base:: 184   884 fields_base::
184   op_t:: 185   op_t::
185   grow( 186   grow(
186   std::size_t extra_char, 187   std::size_t extra_char,
187   std::size_t extra_field) 188   std::size_t extra_field)
188   { 189   {
HITCBC 189   884 if(extra_field > detail::header::max_offset - self_.h_.count) 190   884 if(extra_field > detail::header::max_offset - self_.h_.count)
MISUBC 190   ✗ detail::throw_length_error(); 191   ✗ detail::throw_length_error();
191   192  
HITCBC 192   884 if(extra_char > detail::header::max_offset - self_.h_.size) 193   884 if(extra_char > detail::header::max_offset - self_.h_.size)
HITCBC 193   2 detail::throw_length_error(); 194   2 detail::throw_length_error();
194   195  
HITCBC 195   882 return reserve( 196   882 return reserve(
196   detail::header::bytes_needed( 197   detail::header::bytes_needed(
HITCBC 197   882 self_.h_.size + extra_char, 198   882 self_.h_.size + extra_char,
HITCBC 198   1759 self_.h_.count + extra_field)); 199   1759 self_.h_.count + extra_field));
199   } 200   }
200   201  
201   void 202   void
HITCBC 202   103 fields_base:: 203   103 fields_base::
203   op_t:: 204   op_t::
204   move_chars( 205   move_chars(
205   char* dest, 206   char* dest,
206   char const* src, 207   char const* src,
207   std::size_t n) const noexcept 208   std::size_t n) const noexcept
208   { 209   {
HITCBC 209   103 detail::move_chars( 210   103 detail::move_chars(
HITCBC 210   103 dest, src, n, s0_, s1_); 211   103 dest, src, n, s0_, s1_);
HITCBC 211   103 } 212   103 }
212   213  
213   //------------------------------------------------ 214   //------------------------------------------------
214   215  
HITCBC 215   71 fields_base:: 216   71 fields_base::
216   prefix_op_t:: 217   prefix_op_t::
217   prefix_op_t( 218   prefix_op_t(
218   fields_base& self, 219   fields_base& self,
219   std::size_t new_prefix, 220   std::size_t new_prefix,
220   core::string_view* s0, 221   core::string_view* s0,
HITCBC 221   71 core::string_view* s1) 222   71 core::string_view* s1)
HITCBC 222   71 : self_(self) 223   71 : self_(self)
HITCBC 223   71 , new_prefix_(static_cast< 224   71 , new_prefix_(static_cast<
HITCBC 224   71 offset_type>(new_prefix)) 225   71 offset_type>(new_prefix))
225   { 226   {
HITCBC 226   71 if(self.h_.size - self.h_.prefix + new_prefix 227   71 if(self.h_.size - self.h_.prefix + new_prefix
227   > detail::header::max_offset) 228   > detail::header::max_offset)
HITCBC 228   2 detail::throw_length_error(); 229   2 detail::throw_length_error();
229   230  
230   // memmove happens in the destructor 231   // memmove happens in the destructor
231   // to avoid overlaping with start line. 232   // to avoid overlaping with start line.
HITCBC 232   138 if(new_prefix_ < self_.h_.prefix 233   138 if(new_prefix_ < self_.h_.prefix
HITCBC 233   69 && !self.h_.is_default()) 234   69 && !self.h_.is_default())
HITCBC 234   6 return; 235   6 return;
235   236  
HITCBC 236   63 auto new_size = static_cast<offset_type>( 237   63 auto new_size = static_cast<offset_type>(
HITCBC 237   63 self.h_.size - self.h_.prefix + new_prefix_); 238   63 self.h_.size - self.h_.prefix + new_prefix_);
238   239  
239   auto bytes_needed = 240   auto bytes_needed =
HITCBC 240   63 detail::header::bytes_needed( 241   63 detail::header::bytes_needed(
241   new_size, 242   new_size,
HITCBC 242   63 self.h_.count); 243   63 self.h_.count);
243   244  
HITCBC 244   63 if(bytes_needed > self.h_.cap) 245   63 if(bytes_needed > self.h_.cap)
245   { 246   {
246   // static storage will always throw which is 247   // static storage will always throw which is
247   // intended since they cannot reallocate. 248   // intended since they cannot reallocate.
HITCBC 248   56 if(self.max_cap_ < bytes_needed) 249   56 if(self.max_cap_ < bytes_needed)
HITCBC 249   1 detail::throw_length_error(); 250   1 detail::throw_length_error();
250   // TODO: consider using a growth factor 251   // TODO: consider using a growth factor
HITCBC 251   55 char* p = new char[bytes_needed]; 252   55 char* p = new char[bytes_needed];
HITCBC 252   55 std::memcpy( 253   55 std::memcpy(
HITCBC 253   55 p + new_prefix_, 254   55 p + new_prefix_,
HITCBC 254   55 self.h_.cbuf + self.h_.prefix, 255   55 self.h_.cbuf + self.h_.prefix,
HITCBC 255   55 self.h_.size - self.h_.prefix); 256   55 self.h_.size - self.h_.prefix);
HITCBC 256   55 self.h_.copy_table(p + bytes_needed); 257   55 self.h_.copy_table(p + bytes_needed);
257   258  
258   // old buffer gets released in the destructor 259   // old buffer gets released in the destructor
259   // to avoid invalidating any string_views 260   // to avoid invalidating any string_views
260   // that may still reference it. 261   // that may still reference it.
HITCBC 261   55 buf_ = self.h_.buf; 262   55 buf_ = self.h_.buf;
HITCBC 262   55 self.h_.buf = p; 263   55 self.h_.buf = p;
HITCBC 263   55 self.h_.cap = bytes_needed; 264   55 self.h_.cap = bytes_needed;
264   } 265   }
265   else 266   else
266   { 267   {
267   // memmove to the right and update any 268   // memmove to the right and update any
268   // string_views that reference that region. 269   // string_views that reference that region.
HITCBC 269   7 detail::move_chars( 270   7 detail::move_chars(
HITCBC 270   7 self.h_.buf + new_prefix_, 271   7 self.h_.buf + new_prefix_,
HITCBC 271   7 self.h_.cbuf + self.h_.prefix, 272   7 self.h_.cbuf + self.h_.prefix,
HITCBC 272   7 self.h_.size - self.h_.prefix, 273   7 self.h_.size - self.h_.prefix,
273   s0, 274   s0,
274   s1); 275   s1);
275   } 276   }
276   277  
HITCBC 277   62 self.h_.cbuf = self.h_.buf; 278   62 self.h_.cbuf = self.h_.buf;
HITCBC 278   62 self.h_.size = new_size; 279   62 self.h_.size = new_size;
HITCBC 279   62 self.h_.prefix = new_prefix_; 280   62 self.h_.prefix = new_prefix_;
280   } 281   }
281   282  
HITCBC 282   68 fields_base:: 283   68 fields_base::
283   prefix_op_t:: 284   prefix_op_t::
284   ~prefix_op_t() 285   ~prefix_op_t()
285   { 286   {
HITCBC 286   68 if(new_prefix_ < self_.h_.prefix) 287   68 if(new_prefix_ < self_.h_.prefix)
287   { 288   {
HITCBC 288   6 std::memmove( 289   6 std::memmove(
HITCBC 289   6 self_.h_.buf + new_prefix_, 290   6 self_.h_.buf + new_prefix_,
HITCBC 290   6 self_.h_.cbuf + self_.h_.prefix, 291   6 self_.h_.cbuf + self_.h_.prefix,
HITCBC 291   6 self_.h_.size - self_.h_.prefix); 292   6 self_.h_.size - self_.h_.prefix);
292   293  
HITCBC 293   6 self_.h_.size = 294   6 self_.h_.size =
HITCBC 294   6 self_.h_.size - self_.h_.prefix + new_prefix_; 295   6 self_.h_.size - self_.h_.prefix + new_prefix_;
HITCBC 295   6 self_.h_.prefix = new_prefix_; 296   6 self_.h_.prefix = new_prefix_;
296   } 297   }
HITCBC 297   62 else if(buf_) 298   62 else if(buf_)
298   { 299   {
HITCBC 299   5 delete[] buf_; 300   5 delete[] buf_;
300   } 301   }
HITCBC 301   68 } 302   68 }
302   303  
303   //------------------------------------------------ 304   //------------------------------------------------
304   305  
HITCBC 305   466 fields_base:: 306   466 fields_base::
306   fields_base( 307   fields_base(
HITCBC 307   466 detail::kind k) noexcept 308   466 detail::kind k) noexcept
HITCBC 308   466 : h_(k) 309   466 : h_(k)
309   { 310   {
HITCBC 310   466 } 311   466 }
311   312  
HITCBC 312   2187 fields_base:: 313   2187 fields_base::
313   fields_base( 314   fields_base(
314   detail::kind k, 315   detail::kind k,
315   void* storage, 316   void* storage,
HITCBC 316   2187 std::size_t cap) noexcept 317   2187 std::size_t cap) noexcept
317   : fields_base( 318   : fields_base(
HITCBC 318   2187 *detail::header::get_default(k), storage, cap) 319   2187 *detail::header::get_default(k), storage, cap)
319   { 320   {
HITCBC 320   2187 } 321   2187 }
321   322  
322   // copy s and parse it 323   // copy s and parse it
HITCBC 323   549 fields_base:: 324   549 fields_base::
324   fields_base( 325   fields_base(
325   detail::kind k, 326   detail::kind k,
HITCBC 326   549 core::string_view s) 327   549 core::string_view s)
HITCBC 327   549 : h_(detail::empty{k}) 328   549 : h_(detail::empty{k})
328   { 329   {
HITCBC 329   549 auto n = detail::header::count_crlf(s); 330   549 auto n = detail::header::count_crlf(s);
HITCBC 330   549 if(h_.kind == detail::kind::fields) 331   549 if(h_.kind == detail::kind::fields)
331   { 332   {
HITCBC 332   235 if(n < 1) 333   235 if(n < 1)
HITCBC 333   1 detail::throw_invalid_argument(); 334   1 detail::throw_invalid_argument();
HITCBC 334   234 n -= 1; 335   234 n -= 1;
335   } 336   }
336   else 337   else
337   { 338   {
HITCBC 338   314 if(n < 2) 339   314 if(n < 2)
HITCBC 339   2 detail::throw_invalid_argument(); 340   2 detail::throw_invalid_argument();
HITCBC 340   312 n -= 2; 341   312 n -= 2;
341   } 342   }
HITCBC 342   546 op_t op(*this); 343   546 op_t op(*this);
HITCBC 343   546 op.grow(s.size(), n); 344   546 op.grow(s.size(), n);
HITCBC 344   546 s.copy(h_.buf, s.size()); 345   546 s.copy(h_.buf, s.size());
HITCBC 345 - 546 std::error_code ec; 346 + 546 system::error_code ec;
346   // VFALCO This is using defaults? 347   // VFALCO This is using defaults?
HITCBC 347   546 header_limits lim; 348   546 header_limits lim;
HITCBC 348   546 h_.parse(s.size(), lim, ec); 349   546 h_.parse(s.size(), lim, ec);
HITCBC 349   546 if(ec) 350   546 if(ec)
MISUBC 350   ✗ detail::throw_system_error(ec); 351   ✗ detail::throw_system_error(ec);
HITCBC 351   546 } 352   546 }
352   353  
353   // construct a complete copy of h 354   // construct a complete copy of h
HITCBC 354   26 fields_base:: 355   26 fields_base::
355   fields_base( 356   fields_base(
HITCBC 356   26 detail::header const& h) 357   26 detail::header const& h)
HITCBC 357   26 : h_(h.kind) 358   26 : h_(h.kind)
358   { 359   {
HITCBC 359   26 if(h.is_default()) 360   26 if(h.is_default())
HITCBC 360   9 return; 361   9 return;
361   362  
362   // allocate and copy the buffer 363   // allocate and copy the buffer
HITCBC 363   17 op_t op(*this); 364   17 op_t op(*this);
HITCBC 364   17 op.grow(h.size, h.count); 365   17 op.grow(h.size, h.count);
HITCBC 365   17 h.assign_to(h_); 366   17 h.assign_to(h_);
HITCBC 366   17 std::memcpy( 367   17 std::memcpy(
HITCBC 367   17 h_.buf, h.cbuf, h.size); 368   17 h_.buf, h.cbuf, h.size);
HITCBC 368   17 h.copy_table(h_.buf + h_.cap); 369   17 h.copy_table(h_.buf + h_.cap);
HITCBC 369   17 } 370   17 }
370   371  
371   // construct a complete copy of h 372   // construct a complete copy of h
HITCBC 372   2187 fields_base:: 373   2187 fields_base::
373   fields_base( 374   fields_base(
374   detail::header const& h, 375   detail::header const& h,
375   void* storage, 376   void* storage,
HITCBC 376   2187 std::size_t cap) 377   2187 std::size_t cap)
HITCBC 377   2187 : h_(h.kind) 378   2187 : h_(h.kind)
HITCBC 378   2187 , external_storage_(true) 379   2187 , external_storage_(true)
379   { 380   {
HITCBC 380   2187 h_.cbuf = static_cast<char*>(storage); 381   2187 h_.cbuf = static_cast<char*>(storage);
HITCBC 381   2187 h_.buf = static_cast<char*>(storage); 382   2187 h_.buf = static_cast<char*>(storage);
HITCBC 382   2187 h_.cap = align_down( 383   2187 h_.cap = align_down(
383   storage, 384   storage,
384   cap, 385   cap,
385   alignof(detail::header::entry)); 386   alignof(detail::header::entry));
HITCBC 386   2187 max_cap_ = h_.cap; 387   2187 max_cap_ = h_.cap;
387   388  
HITCBC 388   4374 if(detail::header::bytes_needed( 389   4374 if(detail::header::bytes_needed(
HITCBC 389   2187 h.size, h.count) 390   2187 h.size, h.count)
HITCBC 390   2187 >= h_.cap) 391   2187 >= h_.cap)
MISUBC 391   ✗ detail::throw_length_error(); 392   ✗ detail::throw_length_error();
392   393  
HITCBC 393   2187 h.assign_to(h_); 394   2187 h.assign_to(h_);
HITCBC 394   2187 std::memcpy( 395   2187 std::memcpy(
HITCBC 395   2187 h_.buf, h.cbuf, h.size); 396   2187 h_.buf, h.cbuf, h.size);
HITCBC 396   2187 h.copy_table(h_.buf + h_.cap); 397   2187 h.copy_table(h_.buf + h_.cap);
HITCBC 397   2187 } 398   2187 }
398   399  
399   //------------------------------------------------ 400   //------------------------------------------------
400   401  
HITCBC 401   13 fields_base:: 402   13 fields_base::
HITCBC 402   13 fields_base(fields_base const& other) 403   13 fields_base(fields_base const& other)
HITCBC 403   13 : fields_base(other.h_) 404   13 : fields_base(other.h_)
404   { 405   {
HITCBC 405   13 } 406   13 }
406   407  
HITCBC 407   3225 fields_base:: 408   3225 fields_base::
408   ~fields_base() 409   ~fields_base()
409   { 410   {
HITCBC 410   3225 if(h_.buf && !external_storage_) 411   3225 if(h_.buf && !external_storage_)
HITCBC 411   725 delete[] h_.buf; 412   725 delete[] h_.buf;
HITCBC 412   3225 } 413   3225 }
413   414  
414   //------------------------------------------------ 415   //------------------------------------------------
415   // 416   //
416   // Capacity 417   // Capacity
417   // 418   //
418   //------------------------------------------------ 419   //------------------------------------------------
419   420  
420   void 421   void
HITCBC 421   10 fields_base:: 422   10 fields_base::
422   clear() noexcept 423   clear() noexcept
423   { 424   {
HITCBC 424   10 if(! h_.buf) 425   10 if(! h_.buf)
HITCBC 425   5 return; 426   5 return;
426   using H = 427   using H =
427   detail::header; 428   detail::header;
428   auto const& h = 429   auto const& h =
HITCBC 429   5 *H::get_default( 430   5 *H::get_default(
HITCBC 430   5 h_.kind); 431   5 h_.kind);
HITCBC 431   5 h.assign_to(h_); 432   5 h.assign_to(h_);
HITCBC 432   5 std::memcpy( 433   5 std::memcpy(
HITCBC 433   5 h_.buf, 434   5 h_.buf,
HITCBC 434   5 h.cbuf, 435   5 h.cbuf,
HITCBC 435   5 h_.size); 436   5 h_.size);
436   } 437   }
437   438  
438   void 439   void
HITCBC 439   95 fields_base:: 440   95 fields_base::
440   reserve_bytes( 441   reserve_bytes(
441   std::size_t n) 442   std::size_t n)
442   { 443   {
HITCBC 443   95 op_t op(*this); 444   95 op_t op(*this);
HITCBC 444   95 if(! op.reserve(n)) 445   95 if(! op.reserve(n))
HITCBC 445   48 return; 446   48 return;
HITCBC 446   68 std::memcpy( 447   68 std::memcpy(
HITCBC 447   34 h_.buf, op.cbuf(), h_.size); 448   34 h_.buf, op.cbuf(), h_.size);
HITCBC 448   34 auto const nt = 449   34 auto const nt =
HITCBC 449   34 sizeof(entry) * h_.count; 450   34 sizeof(entry) * h_.count;
HITCBC 450   34 if(nt > 0) 451   34 if(nt > 0)
HITCBC 451   6 std::memcpy( 452   6 std::memcpy(
HITCBC 452   6 h_.buf + h_.cap - nt, 453   6 h_.buf + h_.cap - nt,
HITCBC 453   6 op.end() - nt, 454   6 op.end() - nt,
454   nt); 455   nt);
HITCBC 455   95 } 456   95 }
456   457  
457   void 458   void
HITCBC 458   7 fields_base:: 459   7 fields_base::
459   shrink_to_fit() 460   shrink_to_fit()
460   { 461   {
HITCBC 461   14 if(detail::header::bytes_needed( 462   14 if(detail::header::bytes_needed(
HITCBC 462   7 h_.size, h_.count) >= 463   7 h_.size, h_.count) >=
HITCBC 463   7 h_.cap) 464   7 h_.cap)
HITCBC 464   3 return; 465   3 return;
465   466  
HITCBC 466   4 if(external_storage_) 467   4 if(external_storage_)
MISUBC 467   ✗ return; 468   ✗ return;
468   469  
HITCBC 469   4 fields_base tmp(h_); 470   4 fields_base tmp(h_);
HITCBC 470   4 tmp.h_.swap(h_); 471   4 tmp.h_.swap(h_);
HITCBC 471   4 } 472   4 }
472   473  
473   474  
474   void 475   void
HITCBC 475   30 fields_base:: 476   30 fields_base::
476   set_max_capacity_in_bytes(std::size_t n) 477   set_max_capacity_in_bytes(std::size_t n)
477   { 478   {
HITCBC 478   30 if(n < h_.cap) 479   30 if(n < h_.cap)
HITCBC 479   6 detail::throw_invalid_argument(); 480   6 detail::throw_invalid_argument();
HITCBC 480   24 max_cap_ = n; 481   24 max_cap_ = n;
HITCBC 481   24 } 482   24 }
482   483  
483   //-------------------------------------------- 484   //--------------------------------------------
484   // 485   //
485   // Observers 486   // Observers
486   // 487   //
487   //-------------------------------------------- 488   //--------------------------------------------
488   489  
489   490  
MISUBC 490   ✗ fields_base:: 491   ✗ fields_base::
491   value_type:: 492   value_type::
492   value_type( 493   value_type(
MISUBC 493   ✗ reference const& other) 494   ✗ reference const& other)
MISUBC 494   ✗ : id(other.id) 495   ✗ : id(other.id)
MISUBC 495   ✗ , name(other.name) 496   ✗ , name(other.name)
MISUBC 496   ✗ , value(other.value) 497   ✗ , value(other.value)
497   { 498   {
MISUBC 498   ✗ } 499   ✗ }
499   500  
500   //------------------------------------------------ 501   //------------------------------------------------
501   502  
502   auto 503   auto
HITCBC 503   1890 fields_base:: 504   1890 fields_base::
504   iterator:: 505   iterator::
505   operator*() const noexcept -> 506   operator*() const noexcept ->
506   reference 507   reference
507   { 508   {
HITCBC 508   1890 BOOST_ASSERT(i_ < ph_->count); 509   1890 BOOST_ASSERT(i_ < ph_->count);
509   auto tab = 510   auto tab =
HITCBC 510   1890 ph_->tab(); 511   1890 ph_->tab();
511   auto const& e = 512   auto const& e =
HITCBC 512   1890 tab[i_]; 513   1890 tab[i_];
HITCBC 513   1890 auto const* p = 514   1890 auto const* p =
HITCBC 514   1890 ph_->cbuf + ph_->prefix; 515   1890 ph_->cbuf + ph_->prefix;
515   return { 516   return {
HITCBC 516   1890 (e.id == detail::header::unknown_field) 517   1890 (e.id == detail::header::unknown_field)
HITCBC 517   1890 ? optional<field>{} : e.id, 518   1890 ? optional<field>{} : e.id,
518   core::string_view( 519   core::string_view(
HITCBC 519   1890 p + e.np, e.nn), 520   1890 p + e.np, e.nn),
520   core::string_view( 521   core::string_view(
HITCBC 521   1890 p + e.vp, e.vn) }; 522   1890 p + e.vp, e.vn) };
522   } 523   }
523   524  
524   //------------------------------------------------ 525   //------------------------------------------------
525   526  
526   auto 527   auto
HITCBC 527   24 fields_base:: 528   24 fields_base::
528   reverse_iterator:: 529   reverse_iterator::
529   operator*() const noexcept -> 530   operator*() const noexcept ->
530   reference 531   reference
531   { 532   {
HITCBC 532   24 BOOST_ASSERT(i_ > 0); 533   24 BOOST_ASSERT(i_ > 0);
533   auto tab = 534   auto tab =
HITCBC 534   24 ph_->tab(); 535   24 ph_->tab();
535   auto const& e = 536   auto const& e =
HITCBC 536   24 tab[i_-1]; 537   24 tab[i_-1];
HITCBC 537   24 auto const* p = 538   24 auto const* p =
HITCBC 538   24 ph_->cbuf + ph_->prefix; 539   24 ph_->cbuf + ph_->prefix;
539   return { 540   return {
HITCBC 540   24 (e.id == detail::header::unknown_field) 541   24 (e.id == detail::header::unknown_field)
HITCBC 541   24 ? optional<field>{} : e.id, 542   24 ? optional<field>{} : e.id,
542   core::string_view( 543   core::string_view(
HITCBC 543   24 p + e.np, e.nn), 544   24 p + e.np, e.nn),
544   core::string_view( 545   core::string_view(
HITCBC 545   24 p + e.vp, e.vn) }; 546   24 p + e.vp, e.vn) };
546   } 547   }
547   548  
548   //------------------------------------------------ 549   //------------------------------------------------
549   550  
HITCBC 550   21 fields_base:: 551   21 fields_base::
551   subrange:: 552   subrange::
552   iterator:: 553   iterator::
553   iterator( 554   iterator(
554   detail::header const* ph, 555   detail::header const* ph,
HITCBC 555   21 std::size_t i) noexcept 556   21 std::size_t i) noexcept
HITCBC 556   21 : ph_(ph) 557   21 : ph_(ph)
HITCBC 557   21 , i_(i) 558   21 , i_(i)
558   { 559   {
HITCBC 559   21 BOOST_ASSERT(i <= ph_->count); 560   21 BOOST_ASSERT(i <= ph_->count);
HITCBC 560   21 } 561   21 }
561   562  
HITCBC 562   21 fields_base:: 563   21 fields_base::
563   subrange:: 564   subrange::
564   iterator:: 565   iterator::
565   iterator( 566   iterator(
HITCBC 566   21 detail::header const* ph) noexcept 567   21 detail::header const* ph) noexcept
HITCBC 567   21 : ph_(ph) 568   21 : ph_(ph)
HITCBC 568   21 , i_(ph->count) 569   21 , i_(ph->count)
569   { 570   {
HITCBC 570   21 } 571   21 }
571   572  
572   auto 573   auto
HITCBC 573   11 fields_base:: 574   11 fields_base::
574   subrange:: 575   subrange::
575   iterator:: 576   iterator::
576   operator*() const noexcept -> 577   operator*() const noexcept ->
577   reference const 578   reference const
578   { 579   {
579   auto tab = 580   auto tab =
HITCBC 580   11 ph_->tab(); 581   11 ph_->tab();
581   auto const& e = 582   auto const& e =
HITCBC 582   11 tab[i_]; 583   11 tab[i_];
HITCBC 583   11 auto const p = 584   11 auto const p =
HITCBC 584   11 ph_->cbuf + ph_->prefix; 585   11 ph_->cbuf + ph_->prefix;
HITCBC 585   22 return core::string_view( 586   22 return core::string_view(
HITCBC 586   11 p + e.vp, e.vn); 587   11 p + e.vp, e.vn);
587   } 588   }
588   589  
589   auto 590   auto
HITCBC 590   27 fields_base:: 591   27 fields_base::
591   subrange:: 592   subrange::
592   iterator:: 593   iterator::
593   operator++() noexcept -> 594   operator++() noexcept ->
594   iterator& 595   iterator&
595   { 596   {
HITCBC 596   27 BOOST_ASSERT(i_ < ph_->count); 597   27 BOOST_ASSERT(i_ < ph_->count);
HITCBC 597   27 auto const* e = &ph_->tab()[i_]; 598   27 auto const* e = &ph_->tab()[i_];
HITCBC 598   27 auto const id = e->id; 599   27 auto const id = e->id;
HITCBC 599   27 if(id != detail::header::unknown_field) 600   27 if(id != detail::header::unknown_field)
600   { 601   {
HITCBC 601   20 ++i_; 602   20 ++i_;
HITCBC 602   20 --e; 603   20 --e;
HITCBC 603   38 while(i_ != ph_->count) 604   38 while(i_ != ph_->count)
604   { 605   {
HITCBC 605   26 if(e->id == id) 606   26 if(e->id == id)
HITCBC 606   8 break; 607   8 break;
HITCBC 607   18 ++i_; 608   18 ++i_;
HITCBC 608   18 --e; 609   18 --e;
609   } 610   }
HITCBC 610   20 return *this; 611   20 return *this;
611   } 612   }
HITCBC 612   7 auto const p = 613   7 auto const p =
HITCBC 613   7 ph_->cbuf + ph_->prefix; 614   7 ph_->cbuf + ph_->prefix;
614   auto name = core::string_view( 615   auto name = core::string_view(
HITCBC 615   7 p + e->np, e->nn); 616   7 p + e->np, e->nn);
HITCBC 616   7 ++i_; 617   7 ++i_;
HITCBC 617   7 --e; 618   7 --e;
HITCBC 618   24 while(i_ != ph_->count) 619   24 while(i_ != ph_->count)
619   { 620   {
HITCBC 620   20 if(grammar::ci_is_equal( 621   20 if(grammar::ci_is_equal(
621   name, core::string_view( 622   name, core::string_view(
HITCBC 622   20 p + e->np, e->nn))) 623   20 p + e->np, e->nn)))
HITCBC 623   3 break; 624   3 break;
HITCBC 624   17 ++i_; 625   17 ++i_;
HITCBC 625   17 --e; 626   17 --e;
626   } 627   }
HITCBC 627   7 return *this; 628   7 return *this;
628   } 629   }
629   630  
630   //------------------------------------------------ 631   //------------------------------------------------
631   // 632   //
632   // fields_base 633   // fields_base
633   // 634   //
634   //------------------------------------------------ 635   //------------------------------------------------
635   636  
636   core::string_view 637   core::string_view
HITCBC 637   2 fields_base:: 638   2 fields_base::
638   at( 639   at(
639   field id) const 640   field id) const
640   { 641   {
HITCBC 641   2 auto const it = find(id); 642   2 auto const it = find(id);
HITCBC 642   2 if(it == end()) 643   2 if(it == end())
HITCBC 643   2 BOOST_THROW_EXCEPTION( 644   2 BOOST_THROW_EXCEPTION(
644   std::out_of_range{ "field not found" }); 645   std::out_of_range{ "field not found" });
HITCBC 645   1 return it->value; 646   1 return it->value;
646   } 647   }
647   648  
648   core::string_view 649   core::string_view
HITCBC 649   2 fields_base:: 650   2 fields_base::
650   at( 651   at(
651   core::string_view name) const 652   core::string_view name) const
652   { 653   {
HITCBC 653   2 auto const it = find(name); 654   2 auto const it = find(name);
HITCBC 654   2 if(it == end()) 655   2 if(it == end())
HITCBC 655   2 BOOST_THROW_EXCEPTION( 656   2 BOOST_THROW_EXCEPTION(
656   std::out_of_range{ "field not found" }); 657   std::out_of_range{ "field not found" });
HITCBC 657   1 return it->value; 658   1 return it->value;
658   } 659   }
659   660  
660   bool 661   bool
HITCBC 661   7 fields_base:: 662   7 fields_base::
662   exists( 663   exists(
663   field id) const noexcept 664   field id) const noexcept
664   { 665   {
HITCBC 665   7 return find(id) != end(); 666   7 return find(id) != end();
666   } 667   }
667   668  
668   bool 669   bool
HITCBC 669   7 fields_base:: 670   7 fields_base::
670   exists( 671   exists(
671   core::string_view name) const noexcept 672   core::string_view name) const noexcept
672   { 673   {
HITCBC 673   7 return find(name) != end(); 674   7 return find(name) != end();
674   } 675   }
675   676  
676   std::size_t 677   std::size_t
HITCBC 677   12 fields_base:: 678   12 fields_base::
678   count(field id) const noexcept 679   count(field id) const noexcept
679   { 680   {
HITCBC 680   12 std::size_t n = 0; 681   12 std::size_t n = 0;
HITCBC 681   57 for(auto v : *this) 682   57 for(auto v : *this)
HITCBC 682   45 if(v.id == id) 683   45 if(v.id == id)
HITCBC 683   11 ++n; 684   11 ++n;
HITCBC 684   12 return n; 685   12 return n;
685   } 686   }
686   687  
687   std::size_t 688   std::size_t
HITCBC 688   14 fields_base:: 689   14 fields_base::
689   count( 690   count(
690   core::string_view name) const noexcept 691   core::string_view name) const noexcept
691   { 692   {
HITCBC 692   14 std::size_t n = 0; 693   14 std::size_t n = 0;
HITCBC 693   76 for(auto v : *this) 694   76 for(auto v : *this)
HITCBC 694   62 if(grammar::ci_is_equal( 695   62 if(grammar::ci_is_equal(
695   v.name, name)) 696   v.name, name))
HITCBC 696   19 ++n; 697   19 ++n;
HITCBC 697   14 return n; 698   14 return n;
698   } 699   }
699   700  
700   auto 701   auto
HITCBC 701   134 fields_base:: 702   134 fields_base::
702   find(field id) const noexcept -> 703   find(field id) const noexcept ->
703   iterator 704   iterator
704   { 705   {
HITCBC 705   134 auto it = begin(); 706   134 auto it = begin();
HITCBC 706   134 auto const last = end(); 707   134 auto const last = end();
HITCBC 707   266 while(it != last) 708   266 while(it != last)
708   { 709   {
HITCBC 709   245 if(it->id == id) 710   245 if(it->id == id)
HITCBC 710   113 break; 711   113 break;
HITCBC 711   132 ++it; 712   132 ++it;
712   } 713   }
HITCBC 713   134 return it; 714   134 return it;
714   } 715   }
715   716  
716   auto 717   auto
HITCBC 717   93 fields_base:: 718   93 fields_base::
718   find( 719   find(
719   core::string_view name) const noexcept -> 720   core::string_view name) const noexcept ->
720   iterator 721   iterator
721   { 722   {
HITCBC 722   93 auto it = begin(); 723   93 auto it = begin();
HITCBC 723   93 auto const last = end(); 724   93 auto const last = end();
HITCBC 724   206 while(it != last) 725   206 while(it != last)
725   { 726   {
HITCBC 726   200 if(grammar::ci_is_equal( 727   200 if(grammar::ci_is_equal(
HITCBC 727   400 it->name, name)) 728   400 it->name, name))
HITCBC 728   87 break; 729   87 break;
HITCBC 729   113 ++it; 730   113 ++it;
730   } 731   }
HITCBC 731   93 return it; 732   93 return it;
732   } 733   }
733   734  
734   auto 735   auto
HITCBC 735   2 fields_base:: 736   2 fields_base::
736   find( 737   find(
737   iterator from, 738   iterator from,
738   field id) const noexcept -> 739   field id) const noexcept ->
739   iterator 740   iterator
740   { 741   {
HITCBC 741   2 auto const last = end(); 742   2 auto const last = end();
HITCBC 742   11 while(from != last) 743   11 while(from != last)
743   { 744   {
HITCBC 744   10 if(from->id == id) 745   10 if(from->id == id)
HITCBC 745   1 break; 746   1 break;
HITCBC 746   9 ++from; 747   9 ++from;
747   } 748   }
HITCBC 748   2 return from; 749   2 return from;
749   } 750   }
750   751  
751   auto 752   auto
HITCBC 752   2 fields_base:: 753   2 fields_base::
753   find( 754   find(
754   iterator from, 755   iterator from,
755   core::string_view name) const noexcept -> 756   core::string_view name) const noexcept ->
756   iterator 757   iterator
757   { 758   {
HITCBC 758   2 auto const last = end(); 759   2 auto const last = end();
HITCBC 759   12 while(from != last) 760   12 while(from != last)
760   { 761   {
HITCBC 761   11 if(grammar::ci_is_equal( 762   11 if(grammar::ci_is_equal(
HITCBC 762   22 name, from->name)) 763   22 name, from->name))
HITCBC 763   1 break; 764   1 break;
HITCBC 764   10 ++from; 765   10 ++from;
765   } 766   }
HITCBC 766   2 return from; 767   2 return from;
767   } 768   }
768   769  
769   auto 770   auto
HITCBC 770   3 fields_base:: 771   3 fields_base::
771   find_last( 772   find_last(
772   iterator it, 773   iterator it,
773   field id) const noexcept -> 774   field id) const noexcept ->
774   iterator 775   iterator
775   { 776   {
HITCBC 776   3 auto const it0 = begin(); 777   3 auto const it0 = begin();
777   for(;;) 778   for(;;)
778   { 779   {
HITCBC 779   10 if(it == it0) 780   10 if(it == it0)
HITCBC 780   1 return end(); 781   1 return end();
HITCBC 781   9 --it; 782   9 --it;
HITCBC 782   9 if(it->id == id) 783   9 if(it->id == id)
HITCBC 783   2 return it; 784   2 return it;
784   } 785   }
785   } 786   }
786   787  
787   auto 788   auto
HITCBC 788   3 fields_base:: 789   3 fields_base::
789   find_last( 790   find_last(
790   iterator it, 791   iterator it,
791   core::string_view name) const noexcept -> 792   core::string_view name) const noexcept ->
792   iterator 793   iterator
793   { 794   {
HITCBC 794   3 auto const it0 = begin(); 795   3 auto const it0 = begin();
795   for(;;) 796   for(;;)
796   { 797   {
HITCBC 797   14 if(it == it0) 798   14 if(it == it0)
HITCBC 798   1 return end(); 799   1 return end();
HITCBC 799   13 --it; 800   13 --it;
HITCBC 800   13 if(grammar::ci_is_equal( 801   13 if(grammar::ci_is_equal(
HITCBC 801   26 it->name, name)) 802   26 it->name, name))
HITCBC 802   2 return it; 803   2 return it;
803   } 804   }
804   } 805   }
805   806  
806   core::string_view 807   core::string_view
HITCBC 807   39 fields_base:: 808   39 fields_base::
808   value_or( 809   value_or(
809   field id, 810   field id,
810   core::string_view s) const noexcept 811   core::string_view s) const noexcept
811   { 812   {
HITCBC 812   39 auto it = find(id); 813   39 auto it = find(id);
HITCBC 813   39 if(it != end()) 814   39 if(it != end())
HITCBC 814   29 return it->value; 815   29 return it->value;
HITCBC 815   10 return s; 816   10 return s;
816   } 817   }
817   818  
818   core::string_view 819   core::string_view
HITCBC 819   2 fields_base:: 820   2 fields_base::
820   value_or( 821   value_or(
821   core::string_view name, 822   core::string_view name,
822   core::string_view s) const noexcept 823   core::string_view s) const noexcept
823   { 824   {
HITCBC 824   2 auto it = find(name); 825   2 auto it = find(name);
HITCBC 825   2 if(it != end()) 826   2 if(it != end())
HITCBC 826   1 return it->value; 827   1 return it->value;
HITCBC 827   1 return s; 828   1 return s;
828   } 829   }
829   830  
830   //------------------------------------------------ 831   //------------------------------------------------
831   832  
832   auto 833   auto
HITCBC 833   16 fields_base:: 834   16 fields_base::
834   find_all( 835   find_all(
835   field id) const noexcept -> 836   field id) const noexcept ->
836   subrange 837   subrange
837   { 838   {
HITCBC 838   16 return subrange( 839   16 return subrange(
HITCBC 839   32 &h_, find(id).i_); 840   32 &h_, find(id).i_);
840   } 841   }
841   842  
842   auto 843   auto
HITCBC 843   5 fields_base:: 844   5 fields_base::
844   find_all( 845   find_all(
845   core::string_view name) const noexcept -> 846   core::string_view name) const noexcept ->
846   subrange 847   subrange
847   { 848   {
HITCBC 848   5 return subrange( 849   5 return subrange(
HITCBC 849   10 &h_, find(name).i_); 850   10 &h_, find(name).i_);
850   } 851   }
851   852  
852   std::ostream& 853   std::ostream&
HITCBC 853   1 operator<<( 854   1 operator<<(
854   std::ostream& os, 855   std::ostream& os,
855   const fields_base& f) 856   const fields_base& f)
856   { 857   {
HITCBC 857   1 if(f.h_.prefix != 0) 858   1 if(f.h_.prefix != 0)
HITCBC 858   1 os << core::string_view(f.h_.cbuf, f.h_.prefix - 2) << '\n'; 859   1 os << core::string_view(f.h_.cbuf, f.h_.prefix - 2) << '\n';
859   860  
HITCBC 860   3 for(auto ref : f) 861   3 for(auto ref : f)
HITCBC 861   2 os << ref.name << ": " << ref.value << '\n'; 862   2 os << ref.name << ": " << ref.value << '\n';
862   863  
HITCBC 863   1 return os; 864   1 return os;
864   } 865   }
865   866  
866   //------------------------------------------------ 867   //------------------------------------------------
867   // 868   //
868   // Modifiers 869   // Modifiers
869   // 870   //
870   //------------------------------------------------ 871   //------------------------------------------------
871   872  
872   auto 873   auto
HITCBC 873   30 fields_base:: 874   30 fields_base::
874   erase( 875   erase(
875   iterator it) noexcept -> iterator 876   iterator it) noexcept -> iterator
876   { 877   {
HITCBC 877   30 auto const id = it->id.value_or( 878   30 auto const id = it->id.value_or(
878   detail::header::unknown_field); 879   detail::header::unknown_field);
HITCBC 879   30 raw_erase(it.i_); 880   30 raw_erase(it.i_);
HITCBC 880   30 h_.on_erase(id); 881   30 h_.on_erase(id);
HITCBC 881   30 return it; 882   30 return it;
882   } 883   }
883   884  
884   std::size_t 885   std::size_t
HITCBC 885   30 fields_base:: 886   30 fields_base::
886   erase( 887   erase(
887   field id) noexcept 888   field id) noexcept
888   { 889   {
HITCBC 889   30 auto const i0 = h_.find(id); 890   30 auto const i0 = h_.find(id);
HITCBC 890   30 if(i0 == h_.count) 891   30 if(i0 == h_.count)
HITCBC 891   3 return 0; 892   3 return 0;
HITCBC 892   27 return erase_all(i0, id); 893   27 return erase_all(i0, id);
893   } 894   }
894   895  
895   std::size_t 896   std::size_t
HITCBC 896   18 fields_base:: 897   18 fields_base::
897   erase( 898   erase(
898   core::string_view name) noexcept 899   core::string_view name) noexcept
899   { 900   {
HITCBC 900   18 auto const i0 = h_.find(name); 901   18 auto const i0 = h_.find(name);
HITCBC 901   18 if(i0 == h_.count) 902   18 if(i0 == h_.count)
HITCBC 902   3 return 0; 903   3 return 0;
HITCBC 903   15 auto const ft = h_.tab(); 904   15 auto const ft = h_.tab();
HITCBC 904   15 auto const id = ft[i0].id; 905   15 auto const id = ft[i0].id;
HITCBC 905   15 if(id == detail::header::unknown_field) 906   15 if(id == detail::header::unknown_field)
HITCBC 906   6 return erase_all(i0, name); 907   6 return erase_all(i0, name);
HITCBC 907   9 return erase_all(i0, id); 908   9 return erase_all(i0, id);
908   } 909   }
909   910  
910   //------------------------------------------------ 911   //------------------------------------------------
911   912  
912   void 913   void
HITCBC 913   28 fields_base:: 914   28 fields_base::
914   set( 915   set(
915   iterator it, 916   iterator it,
916   core::string_view value, 917   core::string_view value,
917 - std::error_code& ec) 918 + system::error_code& ec)
918   { 919   {
HITCBC 919   28 auto rv = verify_field_value(value); 920   28 auto rv = verify_field_value(value);
HITCBC 920   28 if(rv.has_error()) 921   28 if(rv.has_error())
921   { 922   {
HITCBC 922   4 ec = rv.error(); 923   4 ec = rv.error();
HITCBC 923   4 return; 924   4 return;
924   } 925   }
925   926  
HITCBC 926   24 value = rv->value; 927   24 value = rv->value;
HITCBC 927   24 bool has_obs_fold = rv->has_obs_fold; 928   24 bool has_obs_fold = rv->has_obs_fold;
928   929  
HITCBC 929   24 auto const i = it.i_; 930   24 auto const i = it.i_;
HITCBC 930   24 auto tab = h_.tab(); 931   24 auto tab = h_.tab();
HITCBC 931   24 auto const& e0 = tab[i]; 932   24 auto const& e0 = tab[i];
HITCBC 932   24 auto const pos0 = offset(i); 933   24 auto const pos0 = offset(i);
HITCBC 933   24 auto const pos1 = offset(i + 1); 934   24 auto const pos1 = offset(i + 1);
934   std::ptrdiff_t dn = 935   std::ptrdiff_t dn =
HITCBC 935   24 value.size() - 936   24 value.size() -
HITCBC 936   24 it->value.size(); 937   24 it->value.size();
HITCBC 937   24 if( value.empty() && 938   24 if( value.empty() &&
HITCBC 938   24 ! it->value.empty()) 939   24 ! it->value.empty())
MISUBC 939   ✗ --dn; // remove SP 940   ✗ --dn; // remove SP
HITCBC 940   24 else if( 941   24 else if(
HITCBC 941   24 it->value.empty() && 942   24 it->value.empty() &&
MISUBC 942   ✗ ! value.empty()) 943   ✗ ! value.empty())
MISUBC 943   ✗ ++dn; // add SP 944   ✗ ++dn; // add SP
944   945  
HITCBC 945   24 op_t op(*this, &value); 946   24 op_t op(*this, &value);
HITCBC 946   30 if( dn > 0 && 947   30 if( dn > 0 &&
HITCBC 947   12 op.grow(value.size() - 948   12 op.grow(value.size() -
HITCBC 948   30 it->value.size(), 0)) 949   30 it->value.size(), 0))
949   { 950   {
950   // reallocated 951   // reallocated
HITCBC 951   6 auto dest = h_.buf + 952   6 auto dest = h_.buf +
HITCBC 952   6 pos0 + e0.nn + 1; 953   6 pos0 + e0.nn + 1;
HITCBC 953   12 std::memcpy( 954   12 std::memcpy(
HITCBC 954   6 h_.buf, 955   6 h_.buf,
HITCBC 955   6 op.buf(), 956   6 op.buf(),
HITCBC 956   6 dest - h_.buf); 957   6 dest - h_.buf);
HITCBC 957   6 if(! value.empty()) 958   6 if(! value.empty())
958   { 959   {
HITCBC 959   6 *dest++ = ' '; 960   6 *dest++ = ' ';
HITCBC 960   6 value.copy( 961   6 value.copy(
961   dest, 962   dest,
962   value.size()); 963   value.size());
HITCBC 963   6 if( has_obs_fold ) 964   6 if( has_obs_fold )
HITCBC 964   3 detail::remove_obs_fold( 965   3 detail::remove_obs_fold(
HITCBC 965   3 dest, dest + value.size()); 966   3 dest, dest + value.size());
HITCBC 966   6 dest += value.size(); 967   6 dest += value.size();
967   } 968   }
HITCBC 968   6 *dest++ = '\r'; 969   6 *dest++ = '\r';
HITCBC 969   6 *dest++ = '\n'; 970   6 *dest++ = '\n';
HITCBC 970   12 std::memcpy( 971   12 std::memcpy(
HITCBC 971   6 h_.buf + pos1 + dn, 972   6 h_.buf + pos1 + dn,
HITCBC 972   12 op.buf() + pos1, 973   12 op.buf() + pos1,
HITCBC 973   6 h_.size - pos1); 974   6 h_.size - pos1);
HITCBC 974   12 std::memcpy( 975   12 std::memcpy(
HITCBC 975   6 h_.buf + h_.cap - 976   6 h_.buf + h_.cap -
HITCBC 976   6 sizeof(entry) * h_.count, 977   6 sizeof(entry) * h_.count,
HITCBC 977   6 &op.tab()[h_.count - 1], 978   6 &op.tab()[h_.count - 1],
HITCBC 978   6 sizeof(entry) * h_.count); 979   6 sizeof(entry) * h_.count);
979   } 980   }
980   else 981   else
981   { 982   {
982   // copy the value first 983   // copy the value first
HITCBC 983   36 auto dest = h_.buf + pos0 + 984   36 auto dest = h_.buf + pos0 +
HITCBC 984   18 it->name.size() + 1; 985   18 it->name.size() + 1;
HITCBC 985   18 if(! value.empty()) 986   18 if(! value.empty())
986   { 987   {
HITCBC 987   18 *dest++ = ' '; 988   18 *dest++ = ' ';
HITCBC 988   18 value.copy( 989   18 value.copy(
989   dest, 990   dest,
990   value.size()); 991   value.size());
HITCBC 991   18 if( has_obs_fold ) 992   18 if( has_obs_fold )
MISUBC 992   ✗ detail::remove_obs_fold( 993   ✗ detail::remove_obs_fold(
MISUBC 993   ✗ dest, dest + value.size()); 994   ✗ dest, dest + value.size());
HITCBC 994   18 dest += value.size(); 995   18 dest += value.size();
995   } 996   }
HITCBC 996   18 op.move_chars( 997   18 op.move_chars(
HITCBC 997   18 h_.buf + pos1 + dn, 998   18 h_.buf + pos1 + dn,
HITCBC 998   18 h_.buf + pos1, 999   18 h_.buf + pos1,
HITCBC 999   18 h_.size - pos1); 1000   18 h_.size - pos1);
HITCBC 1000   18 *dest++ = '\r'; 1001   18 *dest++ = '\r';
HITCBC 1001   18 *dest++ = '\n'; 1002   18 *dest++ = '\n';
1002   } 1003   }
1003   { 1004   {
1004   // update tab 1005   // update tab
HITCBC 1005   24 auto ft = h_.tab(); 1006   24 auto ft = h_.tab();
HITCBC 1006   24 for(std::size_t j = h_.count - 1; 1007   24 for(std::size_t j = h_.count - 1;
HITCBC 1007   31 j > i; --j) 1008   31 j > i; --j)
HITCBC 1008   7 ft[j] = ft[j] + dn; 1009   7 ft[j] = ft[j] + dn;
HITCBC 1009   24 auto& e = ft[i]; 1010   24 auto& e = ft[i];
HITCBC 1010   48 e.vp = e.np + e.nn + 1011   48 e.vp = e.np + e.nn +
HITCBC 1011   24 1 + ! value.empty(); 1012   24 1 + ! value.empty();
HITCBC 1012   24 e.vn = static_cast< 1013   24 e.vn = static_cast<
HITCBC 1013   24 offset_type>(value.size()); 1014   24 offset_type>(value.size());
HITCBC 1014   24 h_.size = static_cast< 1015   24 h_.size = static_cast<
HITCBC 1015   24 offset_type>(h_.size + dn); 1016   24 offset_type>(h_.size + dn);
1016   } 1017   }
HITCBC 1017   24 auto const id = it->id.value_or( 1018   24 auto const id = it->id.value_or(
1018   detail::header::unknown_field); 1019   detail::header::unknown_field);
HITCBC 1019   24 if(h_.is_special(id)) 1020   24 if(h_.is_special(id))
1020   { 1021   {
1021   // replace first char of name 1022   // replace first char of name
1022   // with null to hide metadata 1023   // with null to hide metadata
HITCBC 1023   9 char saved = h_.buf[pos0]; 1024   9 char saved = h_.buf[pos0];
HITCBC 1024   9 auto& e = h_.tab()[i]; 1025   9 auto& e = h_.tab()[i];
HITCBC 1025   9 e.id = detail::header::unknown_field; 1026   9 e.id = detail::header::unknown_field;
HITCBC 1026   9 h_.buf[pos0] = '\0'; 1027   9 h_.buf[pos0] = '\0';
HITCBC 1027   9 h_.on_erase(id); 1028   9 h_.on_erase(id);
HITCBC 1028   9 h_.buf[pos0] = saved; // restore 1029   9 h_.buf[pos0] = saved; // restore
HITCBC 1029   9 e.id = id; 1030   9 e.id = id;
HITCBC 1030   9 h_.on_insert(id, it->value); 1031   9 h_.on_insert(id, it->value);
1031   } 1032   }
HITCBC 1032   24 } 1033   24 }
1033   1034  
1034   // erase existing fields with id 1035   // erase existing fields with id
1035   // and then add the field with value 1036   // and then add the field with value
1036   void 1037   void
HITCBC 1037   109 fields_base:: 1038   109 fields_base::
1038   set( 1039   set(
1039   field id, 1040   field id,
1040   core::string_view value, 1041   core::string_view value,
1041 - std::error_code& ec) 1042 + system::error_code& ec)
1042   { 1043   {
HITCBC 1043   109 auto rv = verify_field_value(value); 1044   109 auto rv = verify_field_value(value);
HITCBC 1044   109 if(rv.has_error()) 1045   109 if(rv.has_error())
1045   { 1046   {
HITCBC 1046   4 ec = rv.error(); 1047   4 ec = rv.error();
HITCBC 1047   4 return; 1048   4 return;
1048   } 1049   }
1049   1050  
HITCBC 1050   105 auto const i0 = h_.find(id); 1051   105 auto const i0 = h_.find(id);
HITCBC 1051   105 if(i0 != h_.count) 1052   105 if(i0 != h_.count)
1052   { 1053   {
1053   // field exists 1054   // field exists
HITCBC 1054   21 auto const ft = h_.tab(); 1055   21 auto const ft = h_.tab();
1055   { 1056   {
1056   // provide strong guarantee 1057   // provide strong guarantee
1057   auto const n0 = 1058   auto const n0 =
HITCBC 1058   21 h_.size - length(i0); 1059   21 h_.size - length(i0);
1059   auto const n = 1060   auto const n =
HITCBC 1060   21 ft[i0].nn + 2 + 1061   21 ft[i0].nn + 2 +
HITCBC 1061   21 rv->value.size() + 2; 1062   21 rv->value.size() + 2;
1062   // VFALCO missing overflow check 1063   // VFALCO missing overflow check
HITCBC 1063   21 reserve_bytes(n0 + n); 1064   21 reserve_bytes(n0 + n);
1064   } 1065   }
HITCBC 1065   21 erase_all(i0, id); 1066   21 erase_all(i0, id);
1066   } 1067   }
1067   1068  
HITCBC 1068   105 insert_unchecked( 1069   105 insert_unchecked(
1069   id, 1070   id,
1070   to_string(id), 1071   to_string(id),
HITCBC 1071   105 rv->value, 1072   105 rv->value,
HITCBC 1072   105 h_.count, 1073   105 h_.count,
HITCBC 1073   105 rv->has_obs_fold); 1074   105 rv->has_obs_fold);
1074   } 1075   }
1075   1076  
1076   // erase existing fields with name 1077   // erase existing fields with name
1077   // and then add the field with value 1078   // and then add the field with value
1078   void 1079   void
HITCBC 1079   32 fields_base:: 1080   32 fields_base::
1080   set( 1081   set(
1081   core::string_view name, 1082   core::string_view name,
1082   core::string_view value, 1083   core::string_view value,
1083 - std::error_code& ec) 1084 + system::error_code& ec)
1084   { 1085   {
HITCBC 1085   32 verify_field_name(name , ec); 1086   32 verify_field_name(name , ec);
HITCBC 1086   32 if(ec) 1087   32 if(ec)
HITCBC 1087   8 return; 1088   8 return;
1088   1089  
HITCBC 1089   28 auto rv = verify_field_value(value); 1090   28 auto rv = verify_field_value(value);
HITCBC 1090   28 if(rv.has_error()) 1091   28 if(rv.has_error())
1091   { 1092   {
HITCBC 1092   4 ec = rv.error(); 1093   4 ec = rv.error();
HITCBC 1093   4 return; 1094   4 return;
1094   } 1095   }
1095   1096  
HITCBC 1096   24 auto const i0 = h_.find(name); 1097   24 auto const i0 = h_.find(name);
HITCBC 1097   24 if(i0 != h_.count) 1098   24 if(i0 != h_.count)
1098   { 1099   {
1099   // field exists 1100   // field exists
HITCBC 1100   18 auto const ft = h_.tab(); 1101   18 auto const ft = h_.tab();
HITCBC 1101   18 auto const id = ft[i0].id; 1102   18 auto const id = ft[i0].id;
1102   { 1103   {
1103   // provide strong guarantee 1104   // provide strong guarantee
1104   auto const n0 = 1105   auto const n0 =
HITCBC 1105   18 h_.size - length(i0); 1106   18 h_.size - length(i0);
1106   auto const n = 1107   auto const n =
HITCBC 1107   18 ft[i0].nn + 2 + 1108   18 ft[i0].nn + 2 +
HITCBC 1108   18 rv->value.size() + 2; 1109   18 rv->value.size() + 2;
1109   // VFALCO missing overflow check 1110   // VFALCO missing overflow check
HITCBC 1110   18 reserve_bytes(n0 + n); 1111   18 reserve_bytes(n0 + n);
1111   } 1112   }
1112   // VFALCO simple algorithm but 1113   // VFALCO simple algorithm but
1113   // costs one extra memmove 1114   // costs one extra memmove
HITCBC 1114   18 if(id != detail::header::unknown_field) 1115   18 if(id != detail::header::unknown_field)
HITCBC 1115   15 erase_all(i0, id); 1116   15 erase_all(i0, id);
1116   else 1117   else
HITCBC 1117   3 erase_all(i0, name); 1118   3 erase_all(i0, name);
1118   } 1119   }
HITCBC 1119   24 insert_unchecked( 1120   24 insert_unchecked(
HITCBC 1120   24 string_to_field(name), 1121   24 string_to_field(name),
1121   name, 1122   name,
HITCBC 1122   24 rv->value, 1123   24 rv->value,
HITCBC 1123   24 h_.count, 1124   24 h_.count,
HITCBC 1124   24 rv->has_obs_fold); 1125   24 rv->has_obs_fold);
1125   } 1126   }
1126   1127  
1127   auto 1128   auto
HITCBC 1128   26 fields_base:: 1129   26 fields_base::
1129   insert( 1130   insert(
1130   iterator before, 1131   iterator before,
1131   field id, 1132   field id,
1132   core::string_view value) 1133   core::string_view value)
1133   -> iterator 1134   -> iterator
1134   { 1135   {
HITCBC 1135 - 26 std::error_code ec; 1136 + 26 system::error_code ec;
HITCBC 1136   26 auto const it = insert(before, id, value, ec); 1137   26 auto const it = insert(before, id, value, ec);
HITCBC 1137   26 if(ec) 1138   26 if(ec)
HITCBC 1138   1 detail::throw_system_error(ec); 1139   1 detail::throw_system_error(ec);
HITCBC 1139   25 return it; 1140   25 return it;
1140   } 1141   }
1141   1142  
1142   auto 1143   auto
HITCBC 1143   33 fields_base:: 1144   33 fields_base::
1144   insert( 1145   insert(
1145   iterator before, 1146   iterator before,
1146   field id, 1147   field id,
1147   core::string_view value, 1148   core::string_view value,
1148 - std::error_code& ec) 1149 + system::error_code& ec)
1149   -> iterator 1150   -> iterator
1150   { 1151   {
HITCBC 1151   33 insert_impl( 1152   33 insert_impl(
1152   id, 1153   id,
1153   to_string(id), 1154   to_string(id),
1154   value, 1155   value,
1155   before.i_, ec); 1156   before.i_, ec);
HITCBC 1156   33 return before; 1157   33 return before;
1157   } 1158   }
1158   1159  
1159   auto 1160   auto
HITCBC 1160   13 fields_base:: 1161   13 fields_base::
1161   insert( 1162   insert(
1162   iterator before, 1163   iterator before,
1163   core::string_view name, 1164   core::string_view name,
1164   core::string_view value) 1165   core::string_view value)
1165   -> iterator 1166   -> iterator
1166   { 1167   {
HITCBC 1167 - 13 std::error_code ec; 1168 + 13 system::error_code ec;
HITCBC 1168   13 insert(before, name, value, ec); 1169   13 insert(before, name, value, ec);
HITCBC 1169   13 if(ec) 1170   13 if(ec)
HITCBC 1170   1 detail::throw_system_error(ec); 1171   1 detail::throw_system_error(ec);
HITCBC 1171   12 return before; 1172   12 return before;
1172   } 1173   }
1173   1174  
1174   auto 1175   auto
HITCBC 1175   16 fields_base:: 1176   16 fields_base::
1176   insert( 1177   insert(
1177   iterator before, 1178   iterator before,
1178   core::string_view name, 1179   core::string_view name,
1179   core::string_view value, 1180   core::string_view value,
1180 - std::error_code& ec) 1181 + system::error_code& ec)
1181   -> iterator 1182   -> iterator
1182   { 1183   {
HITCBC 1183   16 insert_impl( 1184   16 insert_impl(
HITCBC 1184   16 string_to_field(name), 1185   16 string_to_field(name),
1185   name, 1186   name,
1186   value, 1187   value,
1187   before.i_, 1188   before.i_,
1188   ec); 1189   ec);
HITCBC 1189   16 return before; 1190   16 return before;
1190   } 1191   }
1191   1192  
1192   void 1193   void
HITCBC 1193   23 fields_base:: 1194   23 fields_base::
1194   set( 1195   set(
1195   iterator it, 1196   iterator it,
1196   core::string_view value) 1197   core::string_view value)
1197   { 1198   {
HITCBC 1198 - 23 std::error_code ec; 1199 + 23 system::error_code ec;
HITCBC 1199   23 set(it, value, ec); 1200   23 set(it, value, ec);
HITCBC 1200   23 if(ec) 1201   23 if(ec)
HITCBC 1201   2 detail::throw_system_error(ec); 1202   2 detail::throw_system_error(ec);
HITCBC 1202   21 } 1203   21 }
1203   1204  
1204   //------------------------------------------------ 1205   //------------------------------------------------
1205   // 1206   //
1206   // (implementation) 1207   // (implementation)
1207   // 1208   //
1208   //------------------------------------------------ 1209   //------------------------------------------------
1209   1210  
1210   // copy start line and fields 1211   // copy start line and fields
1211   void 1212   void
HITCBC 1212   17 fields_base:: 1213   17 fields_base::
1213   copy_impl( 1214   copy_impl(
1214   detail::header const& h) 1215   detail::header const& h)
1215   { 1216   {
HITCBC 1216   17 BOOST_ASSERT( 1217   17 BOOST_ASSERT(
1217   h.kind == h_.kind); 1218   h.kind == h_.kind);
1218   1219  
1219   auto const n = 1220   auto const n =
HITCBC 1220   17 detail::header::bytes_needed( 1221   17 detail::header::bytes_needed(
HITCBC 1221   17 h.size, h.count); 1222   17 h.size, h.count);
HITCBC 1222   17 if(n <= h_.cap && (!h.is_default() || external_storage_)) 1223   17 if(n <= h_.cap && (!h.is_default() || external_storage_))
1223   { 1224   {
1224   // no realloc 1225   // no realloc
HITCBC 1225   8 h.assign_to(h_); 1226   8 h.assign_to(h_);
HITCBC 1226   8 h.copy_table( 1227   8 h.copy_table(
HITCBC 1227   8 h_.buf + h_.cap); 1228   8 h_.buf + h_.cap);
HITCBC 1228   8 std::memcpy( 1229   8 std::memcpy(
HITCBC 1229   8 h_.buf, 1230   8 h_.buf,
HITCBC 1230   8 h.cbuf, 1231   8 h.cbuf,
HITCBC 1231   8 h.size); 1232   8 h.size);
HITCBC 1232   8 return; 1233   8 return;
1233   } 1234   }
1234   1235  
1235   // static storages cannot reallocate 1236   // static storages cannot reallocate
HITCBC 1236   9 if(external_storage_) 1237   9 if(external_storage_)
MISUBC 1237   ✗ detail::throw_length_error(); 1238   ✗ detail::throw_length_error();
1238   1239  
HITCBC 1239   9 fields_base tmp(h); 1240   9 fields_base tmp(h);
HITCBC 1240   9 tmp.h_.swap(h_); 1241   9 tmp.h_.swap(h_);
HITCBC 1241   9 } 1242   9 }
1242   1243  
1243   void 1244   void
HITCBC 1244   209 fields_base:: 1245   209 fields_base::
1245   insert_impl( 1246   insert_impl(
1246   optional<field> id, 1247   optional<field> id,
1247   core::string_view name, 1248   core::string_view name,
1248   core::string_view value, 1249   core::string_view value,
1249   std::size_t before, 1250   std::size_t before,
1250 - std::error_code& ec) 1251 + system::error_code& ec)
1251   { 1252   {
HITCBC 1252   209 verify_field_name(name, ec); 1253   209 verify_field_name(name, ec);
HITCBC 1253   209 if(ec) 1254   209 if(ec)
HITCBC 1254   23 return; 1255   23 return;
1255   1256  
HITCBC 1256   204 auto rv = verify_field_value(value); 1257   204 auto rv = verify_field_value(value);
HITCBC 1257   204 if(rv.has_error()) 1258   204 if(rv.has_error())
1258   { 1259   {
HITCBC 1259   18 ec = rv.error(); 1260   18 ec = rv.error();
HITCBC 1260   18 return; 1261   18 return;
1261   } 1262   }
1262   1263  
HITCBC 1263   186 insert_unchecked( 1264   186 insert_unchecked(
1264   id, 1265   id,
1265   name, 1266   name,
HITCBC 1266   186 rv->value, 1267   186 rv->value,
1267   before, 1268   before,
HITCBC 1268   186 rv->has_obs_fold); 1269   186 rv->has_obs_fold);
1269   } 1270   }
1270   1271  
1271   void 1272   void
HITCBC 1272   315 fields_base:: 1273   315 fields_base::
1273   insert_unchecked( 1274   insert_unchecked(
1274   optional<field> id, 1275   optional<field> id,
1275   core::string_view name, 1276   core::string_view name,
1276   core::string_view value, 1277   core::string_view value,
1277   std::size_t before, 1278   std::size_t before,
1278   bool has_obs_fold) 1279   bool has_obs_fold)
1279   { 1280   {
HITCBC 1280   315 auto const tab0 = h_.tab_(); 1281   315 auto const tab0 = h_.tab_();
HITCBC 1281   315 auto const pos = offset(before); 1282   315 auto const pos = offset(before);
1282   auto const n = 1283   auto const n =
HITCBC 1283   315 name.size() + // name 1284   315 name.size() + // name
HITCBC 1284   315 1 + // ':' 1285   315 1 + // ':'
HITCBC 1285   315 ! value.empty() + // [SP] 1286   315 ! value.empty() + // [SP]
HITCBC 1286   315 value.size() + // value 1287   315 value.size() + // value
HITCBC 1287   315 2; // CRLF 1288   315 2; // CRLF
1288   1289  
HITCBC 1289   315 op_t op(*this, &name, &value); 1290   315 op_t op(*this, &name, &value);
HITCBC 1290   315 if(op.grow(n, 1)) 1291   315 if(op.grow(n, 1))
1291   { 1292   {
1292   // reallocated 1293   // reallocated
HITCBC 1293   223 if(pos > 0) 1294   223 if(pos > 0)
HITCBC 1294   203 std::memcpy( 1295   203 std::memcpy(
HITCBC 1295   203 h_.buf, 1296   203 h_.buf,
HITCBC 1296   203 op.cbuf(), 1297   203 op.cbuf(),
1297   pos); 1298   pos);
HITCBC 1298   223 if(before > 0) 1299   223 if(before > 0)
HITCBC 1299   114 std::memcpy( 1300   114 std::memcpy(
HITCBC 1300   57 h_.tab_() - before, 1301   57 h_.tab_() - before,
HITCBC 1301   57 tab0 - before, 1302   57 tab0 - before,
1302   before * sizeof(entry)); 1303   before * sizeof(entry));
HITCBC 1303   446 std::memcpy( 1304   446 std::memcpy(
HITCBC 1304   223 h_.buf + pos + n, 1305   223 h_.buf + pos + n,
HITCBC 1305   223 op.cbuf() + pos, 1306   223 op.cbuf() + pos,
HITCBC 1306   223 h_.size - pos); 1307   223 h_.size - pos);
1307   } 1308   }
1308   else 1309   else
1309   { 1310   {
HITCBC 1310   85 op.move_chars( 1311   85 op.move_chars(
HITCBC 1311   85 h_.buf + pos + n, 1312   85 h_.buf + pos + n,
HITCBC 1312   85 h_.buf + pos, 1313   85 h_.buf + pos,
HITCBC 1313   85 h_.size - pos); 1314   85 h_.size - pos);
1314   } 1315   }
1315   1316  
1316   // serialize 1317   // serialize
1317   { 1318   {
HITCBC 1318   308 auto dest = h_.buf + pos; 1319   308 auto dest = h_.buf + pos;
HITCBC 1319   308 name.copy(dest, name.size()); 1320   308 name.copy(dest, name.size());
HITCBC 1320   308 dest += name.size(); 1321   308 dest += name.size();
HITCBC 1321   308 *dest++ = ':'; 1322   308 *dest++ = ':';
HITCBC 1322   308 if(! value.empty()) 1323   308 if(! value.empty())
1323   { 1324   {
HITCBC 1324   296 *dest++ = ' '; 1325   296 *dest++ = ' ';
HITCBC 1325   296 value.copy( 1326   296 value.copy(
1326   dest, value.size()); 1327   dest, value.size());
HITCBC 1327   296 if( has_obs_fold ) 1328   296 if( has_obs_fold )
HITCBC 1328   18 detail::remove_obs_fold( 1329   18 detail::remove_obs_fold(
HITCBC 1329   18 dest, dest + value.size()); 1330   18 dest, dest + value.size());
HITCBC 1330   296 dest += value.size(); 1331   296 dest += value.size();
1331   } 1332   }
HITCBC 1332   308 *dest++ = '\r'; 1333   308 *dest++ = '\r';
HITCBC 1333   308 *dest = '\n'; 1334   308 *dest = '\n';
1334   } 1335   }
1335   1336  
1336   // update table 1337   // update table
HITCBC 1337   308 auto const tab = h_.tab_(); 1338   308 auto const tab = h_.tab_();
1338   { 1339   {
HITCBC 1339   308 auto i = h_.count - before; 1340   308 auto i = h_.count - before;
HITCBC 1340   308 if(i > 0) 1341   308 if(i > 0)
1341   { 1342   {
HITCBC 1342   43 auto p0 = tab0 - h_.count; 1343   43 auto p0 = tab0 - h_.count;
HITCBC 1343   43 auto p = tab - h_.count - 1; 1344   43 auto p = tab - h_.count - 1;
1344   do 1345   do
1345   { 1346   {
HITCBC 1346   80 *p++ = *p0++ + n; 1347   80 *p++ = *p0++ + n;
1347   } 1348   }
HITCBC 1348   80 while(--i); 1349   80 while(--i);
1349   } 1350   }
1350   } 1351   }
HITCBC 1351   308 auto& e = tab[0 - static_cast<std::ptrdiff_t>(before) - 1]; 1352   308 auto& e = tab[0 - static_cast<std::ptrdiff_t>(before) - 1];
HITCBC 1352   308 e.np = static_cast<offset_type>( 1353   308 e.np = static_cast<offset_type>(
HITCBC 1353   308 pos - h_.prefix); 1354   308 pos - h_.prefix);
HITCBC 1354   308 e.nn = static_cast< 1355   308 e.nn = static_cast<
HITCBC 1355   308 offset_type>(name.size()); 1356   308 offset_type>(name.size());
HITCBC 1356   308 e.vp = static_cast<offset_type>( 1357   308 e.vp = static_cast<offset_type>(
HITCBC 1357   616 pos - h_.prefix + 1358   616 pos - h_.prefix +
HITCBC 1358   308 name.size() + 1 + 1359   308 name.size() + 1 +
HITCBC 1359   308 ! value.empty()); 1360   308 ! value.empty());
HITCBC 1360   308 e.vn = static_cast< 1361   308 e.vn = static_cast<
HITCBC 1361   308 offset_type>(value.size()); 1362   308 offset_type>(value.size());
HITCBC 1362   308 e.id = id.value_or( 1363   308 e.id = id.value_or(
1363   detail::header::unknown_field); 1364   detail::header::unknown_field);
1364   1365  
1365   // update container 1366   // update container
HITCBC 1366   308 h_.count++; 1367   308 h_.count++;
HITCBC 1367   308 h_.size = static_cast< 1368   308 h_.size = static_cast<
HITCBC 1368   308 offset_type>(h_.size + n); 1369   308 offset_type>(h_.size + n);
HITCBC 1369   308 h_.on_insert(e.id, value); 1370   308 h_.on_insert(e.id, value);
HITCBC 1370   315 } 1371   315 }
1371   1372  
1372   void 1373   void
HITCBC 1373   169 fields_base:: 1374   169 fields_base::
1374   raw_erase( 1375   raw_erase(
1375   std::size_t i) noexcept 1376   std::size_t i) noexcept
1376   { 1377   {
HITCBC 1377   169 BOOST_ASSERT(i < h_.count); 1378   169 BOOST_ASSERT(i < h_.count);
HITCBC 1378   169 BOOST_ASSERT(h_.buf != nullptr); 1379   169 BOOST_ASSERT(h_.buf != nullptr);
HITCBC 1379   169 auto const p0 = offset(i); 1380   169 auto const p0 = offset(i);
HITCBC 1380   169 auto const p1 = offset(i + 1); 1381   169 auto const p1 = offset(i + 1);
HITCBC 1381   169 std::memmove( 1382   169 std::memmove(
HITCBC 1382   169 h_.buf + p0, 1383   169 h_.buf + p0,
HITCBC 1383   169 h_.buf + p1, 1384   169 h_.buf + p1,
HITCBC 1384   169 h_.size - p1); 1385   169 h_.size - p1);
HITCBC 1385   169 auto const n = p1 - p0; 1386   169 auto const n = p1 - p0;
HITCBC 1386   169 --h_.count; 1387   169 --h_.count;
HITCBC 1387   169 auto ft = h_.tab(); 1388   169 auto ft = h_.tab();
HITCBC 1388   270 for(;i < h_.count; ++i) 1389   270 for(;i < h_.count; ++i)
HITCBC 1389   101 ft[i] = ft[i + 1] - n; 1390   101 ft[i] = ft[i + 1] - n;
HITCBC 1390   169 h_.size = static_cast< 1391   169 h_.size = static_cast<
HITCBC 1391   169 offset_type>(h_.size - n); 1392   169 offset_type>(h_.size - n);
HITCBC 1392   169 } 1393   169 }
1393   1394  
1394   // erase n fields matching id 1395   // erase n fields matching id
1395   // without updating metadata 1396   // without updating metadata
1396   void 1397   void
HITCBC 1397   4 fields_base:: 1398   4 fields_base::
1398   raw_erase_n( 1399   raw_erase_n(
1399   field id, 1400   field id,
1400   std::size_t n) noexcept 1401   std::size_t n) noexcept
1401   { 1402   {
1402   // iterate in reverse 1403   // iterate in reverse
HITCBC 1403   4 auto e = &h_.tab()[h_.count]; 1404   4 auto e = &h_.tab()[h_.count];
HITCBC 1404   4 auto const e0 = &h_.tab()[0]; 1405   4 auto const e0 = &h_.tab()[0];
HITCBC 1405   10 while(n > 0) 1406   10 while(n > 0)
1406   { 1407   {
HITCBC 1407   6 BOOST_ASSERT(e != e0); 1408   6 BOOST_ASSERT(e != e0);
HITCBC 1408   6 ++e; // decrement 1409   6 ++e; // decrement
HITCBC 1409   6 if(e->id == id) 1410   6 if(e->id == id)
1410   { 1411   {
HITCBC 1411   5 raw_erase(e0 - e); 1412   5 raw_erase(e0 - e);
HITCBC 1412   5 --n; 1413   5 --n;
1413   } 1414   }
1414   } 1415   }
HITCBC 1415   4 } 1416   4 }
1416   1417  
1417   // erase all fields with id 1418   // erase all fields with id
1418   // and update metadata 1419   // and update metadata
1419   std::size_t 1420   std::size_t
HITCBC 1420   72 fields_base:: 1421   72 fields_base::
1421   erase_all( 1422   erase_all(
1422   std::size_t i0, 1423   std::size_t i0,
1423   field id) noexcept 1424   field id) noexcept
1424   { 1425   {
HITCBC 1425   72 BOOST_ASSERT( 1426   72 BOOST_ASSERT(
1426   id != detail::header::unknown_field); 1427   id != detail::header::unknown_field);
HITCBC 1427   72 std::size_t n = 1; 1428   72 std::size_t n = 1;
HITCBC 1428   72 std::size_t i = h_.count - 1; 1429   72 std::size_t i = h_.count - 1;
HITCBC 1429   72 auto const ft = h_.tab(); 1430   72 auto const ft = h_.tab();
HITCBC 1430   149 while(i > i0) 1431   149 while(i > i0)
1431   { 1432   {
HITCBC 1432   77 if(ft[i].id == id) 1433   77 if(ft[i].id == id)
1433   { 1434   {
HITCBC 1434   44 raw_erase(i); 1435   44 raw_erase(i);
HITCBC 1435   44 ++n; 1436   44 ++n;
1436   } 1437   }
1437   // go backwards to 1438   // go backwards to
1438   // reduce memmoves 1439   // reduce memmoves
HITCBC 1439   77 --i; 1440   77 --i;
1440   } 1441   }
HITCBC 1441   72 raw_erase(i0); 1442   72 raw_erase(i0);
HITCBC 1442   72 h_.on_erase_all(id); 1443   72 h_.on_erase_all(id);
HITCBC 1443   72 return n; 1444   72 return n;
1444   } 1445   }
1445   1446  
1446   // erase all fields with name 1447   // erase all fields with name
1447   // when id == detail::header::unknown_field 1448   // when id == detail::header::unknown_field
1448   std::size_t 1449   std::size_t
HITCBC 1449   9 fields_base:: 1450   9 fields_base::
1450   erase_all( 1451   erase_all(
1451   std::size_t i0, 1452   std::size_t i0,
1452   core::string_view name) noexcept 1453   core::string_view name) noexcept
1453   { 1454   {
HITCBC 1454   9 std::size_t n = 1; 1455   9 std::size_t n = 1;
HITCBC 1455   9 std::size_t i = h_.count - 1; 1456   9 std::size_t i = h_.count - 1;
HITCBC 1456   9 auto const ft = h_.tab(); 1457   9 auto const ft = h_.tab();
HITCBC 1457   9 auto const* p = h_.cbuf + h_.prefix; 1458   9 auto const* p = h_.cbuf + h_.prefix;
HITCBC 1458   36 while(i > i0) 1459   36 while(i > i0)
1459   { 1460   {
1460   core::string_view s( 1461   core::string_view s(
HITCBC 1461   27 p + ft[i].np, ft[i].nn); 1462   27 p + ft[i].np, ft[i].nn);
HITCBC 1462   27 if(s == name) 1463   27 if(s == name)
1463   { 1464   {
HITCBC 1464   9 raw_erase(i); 1465   9 raw_erase(i);
HITCBC 1465   9 ++n; 1466   9 ++n;
1466   } 1467   }
1467   // go backwards to 1468   // go backwards to
1468   // reduce memmoves 1469   // reduce memmoves
HITCBC 1469   27 --i; 1470   27 --i;
1470   } 1471   }
HITCBC 1471   9 raw_erase(i0); 1472   9 raw_erase(i0);
HITCBC 1472   9 return n; 1473   9 return n;
1473   } 1474   }
1474   1475  
1475   // return i-th field absolute offset 1476   // return i-th field absolute offset
1476   std::size_t 1477   std::size_t
HITCBC 1477   779 fields_base:: 1478   779 fields_base::
1478   offset( 1479   offset(
1479   std::size_t i) const noexcept 1480   std::size_t i) const noexcept
1480   { 1481   {
HITCBC 1481   779 if(i == 0) 1482   779 if(i == 0)
HITCBC 1482   347 return h_.prefix; 1483   347 return h_.prefix;
HITCBC 1483   432 if(i < h_.count) 1484   432 if(i < h_.count)
HITCBC 1484   219 return h_.prefix + h_.tab()[i].np; 1485   219 return h_.prefix + h_.tab()[i].np;
1485   // make final CRLF the last "field" 1486   // make final CRLF the last "field"
HITCBC 1486   213 return h_.size - 2; 1487   213 return h_.size - 2;
1487   } 1488   }
1488   1489  
1489   // return i-th field absolute length 1490   // return i-th field absolute length
1490   std::size_t 1491   std::size_t
HITCBC 1491   39 fields_base:: 1492   39 fields_base::
1492   length( 1493   length(
1493   std::size_t i) const noexcept 1494   std::size_t i) const noexcept
1494   { 1495   {
1495   return 1496   return
HITCBC 1496   39 offset(i + 1) - 1497   39 offset(i + 1) -
HITCBC 1497   39 offset(i); 1498   39 offset(i);
1498   } 1499   }
1499   1500  
1500   } // http 1501   } // http
1501   } // boost 1502   } // boost