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