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