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