100.00% Lines (173/173) 100.00% Functions (36/36)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/boostorg/json 7   // Official repository: https://github.com/boostorg/json
8   // 8   //
9   9  
10   #ifndef BOOST_JSON_IMPL_STRING_IPP 10   #ifndef BOOST_JSON_IMPL_STRING_IPP
11   #define BOOST_JSON_IMPL_STRING_IPP 11   #define BOOST_JSON_IMPL_STRING_IPP
12   12  
13   #include <boost/json/detail/except.hpp> 13   #include <boost/json/detail/except.hpp>
14   #include <algorithm> 14   #include <algorithm>
15   #include <new> 15   #include <new>
16   #include <ostream> 16   #include <ostream>
17   #include <stdexcept> 17   #include <stdexcept>
18   #include <string> 18   #include <string>
19   #include <utility> 19   #include <utility>
20   20  
21   namespace boost { 21   namespace boost {
22   namespace json { 22   namespace json {
23   23  
24   //---------------------------------------------------------- 24   //----------------------------------------------------------
25   // 25   //
26   // Construction 26   // Construction
27   // 27   //
28   //---------------------------------------------------------- 28   //----------------------------------------------------------
29   29  
HITCBC 30   78 string:: 30   78 string::
31   string( 31   string(
32   std::size_t count, 32   std::size_t count,
33   char ch, 33   char ch,
HITCBC 34   78 storage_ptr sp) 34   78 storage_ptr sp)
HITCBC 35   78 : sp_(std::move(sp)) 35   78 : sp_(std::move(sp))
36   { 36   {
HITCBC 37   78 assign(count, ch); 37   78 assign(count, ch);
HITCBC 38   78 } 38   78 }
39   39  
HITCBC 40   175 string:: 40   175 string::
41   string( 41   string(
42   char const* s, 42   char const* s,
HITCBC 43   175 storage_ptr sp) 43   175 storage_ptr sp)
HITCBC 44   175 : sp_(std::move(sp)) 44   175 : sp_(std::move(sp))
45   { 45   {
HITCBC 46   175 assign(s); 46   175 assign(s);
HITCBC 47   175 } 47   175 }
48   48  
HITCBC 49   4 string:: 49   4 string::
50   string( 50   string(
51   char const* s, 51   char const* s,
52   std::size_t count, 52   std::size_t count,
HITCBC 53   4 storage_ptr sp) 53   4 storage_ptr sp)
HITCBC 54   4 : sp_(std::move(sp)) 54   4 : sp_(std::move(sp))
55   { 55   {
HITCBC 56   4 assign(s, count); 56   4 assign(s, count);
HITCBC 57   4 } 57   4 }
58   58  
HITCBC 59   8 string:: 59   8 string::
HITCBC 60   8 string(string const& other) 60   8 string(string const& other)
HITCBC 61   8 : sp_(other.sp_) 61   8 : sp_(other.sp_)
62   { 62   {
HITCBC 63   8 assign(other); 63   8 assign(other);
HITCBC 64   8 } 64   8 }
65   65  
HITCBC 66   145 string:: 66   145 string::
67   string( 67   string(
68   string const& other, 68   string const& other,
HITCBC 69   145 storage_ptr sp) 69   145 storage_ptr sp)
HITCBC 70   145 : sp_(std::move(sp)) 70   145 : sp_(std::move(sp))
71   { 71   {
HITCBC 72   145 assign(other); 72   145 assign(other);
HITCBC 73   145 } 73   145 }
74   74  
HITCBC 75   351 string:: 75   351 string::
76   string( 76   string(
77   string&& other, 77   string&& other,
HITCBC 78   351 storage_ptr sp) 78   351 storage_ptr sp)
HITCBC 79   351 : sp_(std::move(sp)) 79   351 : sp_(std::move(sp))
80   { 80   {
HITCBC 81   351 assign(std::move(other)); 81   351 assign(std::move(other));
HITCBC 82   351 } 82   351 }
83   83  
HITCBC 84   17890 string:: 84   17890 string::
85   string( 85   string(
86   string_view s, 86   string_view s,
HITCBC 87   17890 storage_ptr sp) 87   17890 storage_ptr sp)
HITCBC 88   17890 : sp_(std::move(sp)) 88   17890 : sp_(std::move(sp))
89   { 89   {
HITCBC 90   17890 assign(s); 90   17890 assign(s);
HITCBC 91   17890 } 91   17890 }
92   92  
93   //---------------------------------------------------------- 93   //----------------------------------------------------------
94   // 94   //
95   // Assignment 95   // Assignment
96   // 96   //
97   //---------------------------------------------------------- 97   //----------------------------------------------------------
98   98  
99   string& 99   string&
HITCBC 100   6 string:: 100   6 string::
101   operator=(string const& other) 101   operator=(string const& other)
102   { 102   {
HITCBC 103   6 return assign(other); 103   6 return assign(other);
104   } 104   }
105   105  
106   string& 106   string&
HITCBC 107   10 string:: 107   10 string::
108   operator=(string&& other) 108   operator=(string&& other)
109   { 109   {
HITCBC 110   10 return assign(std::move(other)); 110   10 return assign(std::move(other));
111   } 111   }
112   112  
113   string& 113   string&
HITCBC 114   9 string:: 114   9 string::
115   operator=(char const* s) 115   operator=(char const* s)
116   { 116   {
HITCBC 117   9 return assign(s); 117   9 return assign(s);
118   } 118   }
119   119  
120   string& 120   string&
HITCBC 121   8 string:: 121   8 string::
122   operator=(string_view s) 122   operator=(string_view s)
123   { 123   {
HITCBC 124   8 return assign(s); 124   8 return assign(s);
125   } 125   }
126   126  
127   127  
128   128  
129   string& 129   string&
HITCBC 130   83 string:: 130   83 string::
131   assign( 131   assign(
132   size_type count, 132   size_type count,
133   char ch) 133   char ch)
134   { 134   {
HITCBC 135   64 std::char_traits<char>::assign( 135   64 std::char_traits<char>::assign(
HITCBC 136   83 impl_.assign(count, sp_), 136   83 impl_.assign(count, sp_),
137   count, 137   count,
138   ch); 138   ch);
HITCBC 139   64 return *this; 139   64 return *this;
140   } 140   }
141   141  
142   string& 142   string&
HITCBC 143   193 string:: 143   193 string::
144   assign( 144   assign(
145   string const& other) 145   string const& other)
146   { 146   {
HITCBC 147   193 if(this == &other) 147   193 if(this == &other)
HITCBC 148   1 return *this; 148   1 return *this;
HITCBC 149   192 return assign( 149   192 return assign(
150   other.data(), 150   other.data(),
HITCBC 151   165 other.size()); 151   165 other.size());
152   } 152   }
153   153  
154   string& 154   string&
HITCBC 155   375 string:: 155   375 string::
156   assign(string&& other) 156   assign(string&& other)
157   { 157   {
HITCBC 158   375 if( &other == this ) 158   375 if( &other == this )
HITCBC 159   1 return *this; 159   1 return *this;
160   160  
HITCBC 161   374 if(*sp_ == *other.sp_) 161   374 if(*sp_ == *other.sp_)
162   { 162   {
HITCBC 163   340 impl_.destroy(sp_); 163   340 impl_.destroy(sp_);
HITCBC 164   340 impl_ = other.impl_; 164   340 impl_ = other.impl_;
HITCBC 165   340 ::new(&other.impl_) detail::string_impl(); 165   340 ::new(&other.impl_) detail::string_impl();
HITCBC 166   340 return *this; 166   340 return *this;
167   } 167   }
168   168  
169   // copy 169   // copy
HITCBC 170   34 return assign(other); 170   34 return assign(other);
171   } 171   }
172   172  
173   string& 173   string&
HITCBC 174   18367 string:: 174   18367 string::
175   assign( 175   assign(
176   char const* s, 176   char const* s,
177   size_type count) 177   size_type count)
178   { 178   {
HITCBC 179   18244 std::char_traits<char>::copy( 179   18244 std::char_traits<char>::copy(
HITCBC 180   18367 impl_.assign(count, sp_), 180   18367 impl_.assign(count, sp_),
181   s, count); 181   s, count);
HITCBC 182   18244 return *this; 182   18244 return *this;
183   } 183   }
184   184  
185   string& 185   string&
HITCBC 186   189 string:: 186   189 string::
187   assign( 187   assign(
188   char const* s) 188   char const* s)
189   { 189   {
HITCBC 190   189 return assign(s, std::char_traits< 190   189 return assign(s, std::char_traits<
HITCBC 191   186 char>::length(s)); 191   186 char>::length(s));
192   } 192   }
193   193  
194   //---------------------------------------------------------- 194   //----------------------------------------------------------
195   // 195   //
196   // Capacity 196   // Capacity
197   // 197   //
198   //---------------------------------------------------------- 198   //----------------------------------------------------------
199   199  
200   void 200   void
HITCBC 201   7 string:: 201   7 string::
202   shrink_to_fit() 202   shrink_to_fit()
203   { 203   {
HITCBC 204   7 impl_.shrink_to_fit(sp_); 204   7 impl_.shrink_to_fit(sp_);
HITCBC 205   7 } 205   7 }
206   206  
207   //---------------------------------------------------------- 207   //----------------------------------------------------------
208   // 208   //
209   // Access 209   // Access
210   // 210   //
211   //---------------------------------------------------------- 211   //----------------------------------------------------------
212   212  
213   system::result<char&> 213   system::result<char&>
HITCBC 214   12 string::try_at(std::size_t pos) noexcept 214   12 string::try_at(std::size_t pos) noexcept
215   { 215   {
HITCBC 216   12 if( pos < size() ) 216   12 if( pos < size() )
HITCBC 217   10 return impl_.data()[pos]; 217   10 return impl_.data()[pos];
218   218  
HITCBC 219   2 system::error_code ec; 219   2 system::error_code ec;
HITCBC 220   2 BOOST_JSON_FAIL(ec, error::out_of_range); 220   2 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 221   2 return ec; 221   2 return ec;
222   } 222   }
223   223  
224   system::result<char const&> 224   system::result<char const&>
HITCBC 225   20 string::try_at(std::size_t pos) const noexcept 225   20 string::try_at(std::size_t pos) const noexcept
226   { 226   {
HITCBC 227   20 if( pos < size() ) 227   20 if( pos < size() )
HITCBC 228   18 return impl_.data()[pos]; 228   18 return impl_.data()[pos];
229   229  
HITCBC 230   2 system::error_code ec; 230   2 system::error_code ec;
HITCBC 231   2 BOOST_JSON_FAIL(ec, error::out_of_range); 231   2 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 232   2 return ec; 232   2 return ec;
233   } 233   }
234   234  
235   char const& 235   char const&
HITCBC 236   18 string::at(std::size_t pos, source_location const& loc) const 236   18 string::at(std::size_t pos, source_location const& loc) const
237   { 237   {
HITCBC 238   18 return try_at(pos).value(loc); 238   18 return try_at(pos).value(loc);
239   } 239   }
240   240  
241   //---------------------------------------------------------- 241   //----------------------------------------------------------
242   // 242   //
243   // Operations 243   // Operations
244   // 244   //
245   //---------------------------------------------------------- 245   //----------------------------------------------------------
246   246  
247   void 247   void
HITCBC 248   2 string:: 248   2 string::
249   clear() noexcept 249   clear() noexcept
250   { 250   {
HITCBC 251   2 impl_.term(0); 251   2 impl_.term(0);
HITCBC 252   2 } 252   2 }
253   253  
254   //---------------------------------------------------------- 254   //----------------------------------------------------------
255   255  
256   void 256   void
HITCBC 257   88 string:: 257   148 string::
258   push_back(char ch) 258   push_back(char ch)
259   { 259   {
HITCBC 260   88 *impl_.append(1, sp_) = ch; 260   148 *impl_.append(1, sp_) = ch;
HITCBC 261   86 } 261   146 }
262   262  
263   void 263   void
HITCBC 264   29 string:: 264   29 string::
265   pop_back() 265   pop_back()
266   { 266   {
HITCBC 267   29 back() = 0; 267   29 back() = 0;
HITCBC 268   29 impl_.size(impl_.size() - 1); 268   29 impl_.size(impl_.size() - 1);
HITCBC 269   29 } 269   29 }
270   270  
271   //---------------------------------------------------------- 271   //----------------------------------------------------------
272   272  
273   string& 273   string&
HITCBC 274   4 string:: 274   4 string::
275   append(size_type count, char ch) 275   append(size_type count, char ch)
276   { 276   {
HITCBC 277   2 std::char_traits<char>::assign( 277   2 std::char_traits<char>::assign(
HITCBC 278   4 impl_.append(count, sp_), 278   4 impl_.append(count, sp_),
279   count, ch); 279   count, ch);
HITCBC 280   2 return *this; 280   2 return *this;
281   } 281   }
282   282  
283   string& 283   string&
HITCBC 284   45 string:: 284   55 string::
285   append(string_view sv) 285   append(string_view sv)
286   { 286   {
HITCBC 287 - 90 std::char_traits<char>::copy( 287 + 55 auto const p = impl_.data();
HITCBC 288 - 45 impl_.append(sv.size(), sp_), 288 + 55 if(detail::ptr_in_range(p, p + impl_.size(), sv.data()))
289 - sv.data(), sv.size()); 289 + {
  290 + // sv aliases our own storage; appending may reallocate and free the
  291 + // buffer sv points into, so copy from the relocated offset afterwards
HITGNC   292 + 10 auto const offset = sv.data() - p;
HITGNC   293 + 10 auto const dest = impl_.append(sv.size(), sp_);
HITGNC   294 + 8 std::char_traits<char>::copy(
HITGNC   295 + 8 dest, impl_.data() + offset, sv.size());
  296 + }
  297 + else
  298 + {
HITGNC   299 + 90 std::char_traits<char>::copy(
HITGNC   300 + 45 impl_.append(sv.size(), sp_),
  301 + sv.data(), sv.size());
  302 + }
HITCBC 290   34 return *this; 303   40 return *this;
291   } 304   }
292   305  
293   //---------------------------------------------------------- 306   //----------------------------------------------------------
294   307  
295   string& 308   string&
HITCBC 296   27 string:: 309   27 string::
297   insert( 310   insert(
298   size_type pos, 311   size_type pos,
299   string_view sv) 312   string_view sv)
300   { 313   {
HITCBC 301   27 impl_.insert(pos, sv.data(), sv.size(), sp_); 314   27 impl_.insert(pos, sv.data(), sv.size(), sp_);
HITCBC 302   17 return *this; 315   17 return *this;
303   } 316   }
304   317  
305   string& 318   string&
HITCBC 306   11 string:: 319   11 string::
307   insert( 320   insert(
308   std::size_t pos, 321   std::size_t pos,
309   std::size_t count, 322   std::size_t count,
310   char ch) 323   char ch)
311   { 324   {
HITCBC 312   6 std::char_traits<char>::assign( 325   6 std::char_traits<char>::assign(
HITCBC 313   11 impl_.insert_unchecked(pos, count, sp_), 326   11 impl_.insert_unchecked(pos, count, sp_),
314   count, ch); 327   count, ch);
HITCBC 315   6 return *this; 328   6 return *this;
316   } 329   }
317   330  
318   //---------------------------------------------------------- 331   //----------------------------------------------------------
319   332  
320   string& 333   string&
HITCBC 321   19 string:: 334   19 string::
322   replace( 335   replace(
323   std::size_t pos, 336   std::size_t pos,
324   std::size_t count, 337   std::size_t count,
325   string_view sv) 338   string_view sv)
326   { 339   {
HITCBC 327   19 impl_.replace(pos, count, sv.data(), sv.size(), sp_); 340   19 impl_.replace(pos, count, sv.data(), sv.size(), sp_);
HITCBC 328   15 return *this; 341   15 return *this;
329   } 342   }
330   343  
331   string& 344   string&
HITCBC 332   11 string:: 345   11 string::
333   replace( 346   replace(
334   std::size_t pos, 347   std::size_t pos,
335   std::size_t count, 348   std::size_t count,
336   std::size_t count2, 349   std::size_t count2,
337   char ch) 350   char ch)
338   { 351   {
HITCBC 339   7 std::char_traits<char>::assign( 352   7 std::char_traits<char>::assign(
HITCBC 340   11 impl_.replace_unchecked(pos, count, count2, sp_), 353   11 impl_.replace_unchecked(pos, count, count2, sp_),
341   count2, ch); 354   count2, ch);
HITCBC 342   7 return *this; 355   7 return *this;
343   } 356   }
344   357  
345   //---------------------------------------------------------- 358   //----------------------------------------------------------
346   359  
347   string& 360   string&
HITCBC 348   10 string:: 361   10 string::
349   erase( 362   erase(
350   size_type pos, 363   size_type pos,
351   size_type count) 364   size_type count)
352   { 365   {
HITCBC 353   10 if(pos > impl_.size()) 366   10 if(pos > impl_.size())
354   { 367   {
355   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; 368   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
HITCBC 356   1 detail::throw_system_error( error::out_of_range, &loc ); 369   1 detail::throw_system_error( error::out_of_range, &loc );
357   } 370   }
HITCBC 358   9 if( count > impl_.size() - pos) 371   9 if( count > impl_.size() - pos)
HITCBC 359   4 count = impl_.size() - pos; 372   4 count = impl_.size() - pos;
HITCBC 360   9 std::char_traits<char>::move( 373   9 std::char_traits<char>::move(
HITCBC 361   9 impl_.data() + pos, 374   9 impl_.data() + pos,
HITCBC 362   9 impl_.data() + pos + count, 375   9 impl_.data() + pos + count,
HITCBC 363   9 impl_.size() - pos - count + 1); 376   9 impl_.size() - pos - count + 1);
HITCBC 364   9 impl_.term(impl_.size() - count); 377   9 impl_.term(impl_.size() - count);
HITCBC 365   9 return *this; 378   9 return *this;
366   } 379   }
367   380  
368   auto 381   auto
HITCBC 369   2 string:: 382   2 string::
370   erase(const_iterator pos) -> 383   erase(const_iterator pos) ->
371   iterator 384   iterator
372   { 385   {
HITCBC 373   2 return erase(pos, pos+1); 386   2 return erase(pos, pos+1);
374   } 387   }
375   388  
376   auto 389   auto
HITCBC 377   3 string:: 390   3 string::
378   erase( 391   erase(
379   const_iterator first, 392   const_iterator first,
380   const_iterator last) -> 393   const_iterator last) ->
381   iterator 394   iterator
382   { 395   {
HITCBC 383   3 auto const pos = first - begin(); 396   3 auto const pos = first - begin();
HITCBC 384   3 auto const count = last - first; 397   3 auto const count = last - first;
HITCBC 385   3 erase(pos, count); 398   3 erase(pos, count);
HITCBC 386   3 return data() + pos; 399   3 return data() + pos;
387   } 400   }
388   401  
389   //---------------------------------------------------------- 402   //----------------------------------------------------------
390   403  
391   void 404   void
HITCBC 392   66 string:: 405   66 string::
393   resize(size_type count, char ch) 406   resize(size_type count, char ch)
394   { 407   {
HITCBC 395   66 if(count <= impl_.size()) 408   66 if(count <= impl_.size())
396   { 409   {
HITCBC 397   25 impl_.term(count); 410   25 impl_.term(count);
HITCBC 398   25 return; 411   25 return;
399   } 412   }
400   413  
HITCBC 401   41 reserve(count); 414   41 reserve(count);
HITCBC 402   35 std::char_traits<char>::assign( 415   35 std::char_traits<char>::assign(
403   impl_.end(), 416   impl_.end(),
HITCBC 404   35 count - impl_.size(), 417   35 count - impl_.size(),
405   ch); 418   ch);
HITCBC 406   35 grow(count - size()); 419   35 grow(count - size());
407   } 420   }
408   421  
409   //---------------------------------------------------------- 422   //----------------------------------------------------------
410   423  
411   void 424   void
HITCBC 412   4 string:: 425   4 string::
413   swap(string& other) 426   swap(string& other)
414   { 427   {
HITCBC 415   4 if(*sp_ == *other.sp_) 428   4 if(*sp_ == *other.sp_)
416   { 429   {
HITCBC 417   3 std::swap(impl_, other.impl_); 430   3 std::swap(impl_, other.impl_);
HITCBC 418   3 return; 431   3 return;
419   } 432   }
420   string temp1( 433   string temp1(
HITCBC 421   1 std::move(*this), other.sp_); 434   1 std::move(*this), other.sp_);
422   string temp2( 435   string temp2(
HITCBC 423   1 std::move(other), sp_); 436   1 std::move(other), sp_);
HITCBC 424   1 this->~string(); 437   1 this->~string();
HITCBC 425   1 ::new(this) string(pilfer(temp2)); 438   1 ::new(this) string(pilfer(temp2));
HITCBC 426   1 other.~string(); 439   1 other.~string();
HITCBC 427   1 ::new(&other) string(pilfer(temp1)); 440   1 ::new(&other) string(pilfer(temp1));
HITCBC 428   1 } 441   1 }
429   442  
430   //---------------------------------------------------------- 443   //----------------------------------------------------------
431   444  
432   void 445   void
HITCBC 433   9686 string:: 446   9686 string::
434   reserve_impl(size_type new_cap) 447   reserve_impl(size_type new_cap)
435   { 448   {
HITCBC 436   9686 BOOST_ASSERT( 449   9686 BOOST_ASSERT(
437   new_cap >= impl_.capacity()); 450   new_cap >= impl_.capacity());
HITCBC 438   9686 if(new_cap > impl_.capacity()) 451   9686 if(new_cap > impl_.capacity())
439   { 452   {
440   // grow 453   // grow
HITCBC 441   9686 new_cap = detail::string_impl::growth( 454   9686 new_cap = detail::string_impl::growth(
442   new_cap, impl_.capacity()); 455   new_cap, impl_.capacity());
HITCBC 443   9685 detail::string_impl tmp(new_cap, sp_); 456   9685 detail::string_impl tmp(new_cap, sp_);
HITCBC 444   9675 std::char_traits<char>::copy(tmp.data(), 457   9675 std::char_traits<char>::copy(tmp.data(),
HITCBC 445   9675 impl_.data(), impl_.size() + 1); 458   9675 impl_.data(), impl_.size() + 1);
HITCBC 446   9675 tmp.size(impl_.size()); 459   9675 tmp.size(impl_.size());
HITCBC 447   9675 impl_.destroy(sp_); 460   9675 impl_.destroy(sp_);
HITCBC 448   9675 impl_ = tmp; 461   9675 impl_ = tmp;
HITCBC 449   9675 return; 462   9675 return;
450   } 463   }
451   } 464   }
452   465  
453   } // namespace json 466   } // namespace json
454   } // namespace boost 467   } // namespace boost
455   468  
456   //---------------------------------------------------------- 469   //----------------------------------------------------------
457   470  
458   std::size_t 471   std::size_t
HITCBC 459   3 std::hash< ::boost::json::string >::operator()( 472   3 std::hash< ::boost::json::string >::operator()(
460   ::boost::json::string const& js ) const noexcept 473   ::boost::json::string const& js ) const noexcept
461   { 474   {
HITCBC 462   3 return ::boost::hash< ::boost::json::string >()( js ); 475   3 return ::boost::hash< ::boost::json::string >()( js );
463   } 476   }
464   477  
465   #endif 478   #endif