100.00% Lines (92/92) 100.00% Functions (21/21)
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   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) 3   // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
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/boostorg/json 8   // Official repository: https://github.com/boostorg/json
9   // 9   //
10   10  
11   #ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP 11   #ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
12   #define BOOST_JSON_DETAIL_STRING_IMPL_HPP 12   #define BOOST_JSON_DETAIL_STRING_IMPL_HPP
13   13  
14   #include <boost/core/detail/static_assert.hpp> 14   #include <boost/core/detail/static_assert.hpp>
15   #include <boost/json/detail/config.hpp> 15   #include <boost/json/detail/config.hpp>
16   #include <boost/json/kind.hpp> 16   #include <boost/json/kind.hpp>
17   #include <boost/json/storage_ptr.hpp> 17   #include <boost/json/storage_ptr.hpp>
18   #include <boost/json/detail/value.hpp> 18   #include <boost/json/detail/value.hpp>
19   #include <algorithm> 19   #include <algorithm>
20   #include <iterator> 20   #include <iterator>
21   21  
22   namespace boost { 22   namespace boost {
23   namespace json { 23   namespace json {
24   24  
25   class value; 25   class value;
26   class string; 26   class string;
27   27  
28   namespace detail { 28   namespace detail {
29   29  
30   inline 30   inline
31   bool 31   bool
HITCBC 32   78 ptr_in_range(char const* first, char const* last, char const* ptr) noexcept 32   78 ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33   { 33   {
HITCBC 34   113 return std::less<char const*>()(ptr, last) && 34   113 return std::less<char const*>()(ptr, last) &&
HITCBC 35   113 std::greater_equal<char const*>()(ptr, first); 35   113 std::greater_equal<char const*>()(ptr, first);
36   } 36   }
37   37  
38   38  
39   class string_impl 39   class string_impl
40   { 40   {
41   struct table 41   struct table
42   { 42   {
43   std::uint32_t size; 43   std::uint32_t size;
44   std::uint32_t capacity; 44   std::uint32_t capacity;
45   }; 45   };
46   46  
47   #if BOOST_JSON_ARCH == 64 47   #if BOOST_JSON_ARCH == 64
48   static constexpr std::size_t sbo_chars_ = 14; 48   static constexpr std::size_t sbo_chars_ = 14;
49   #elif BOOST_JSON_ARCH == 32 49   #elif BOOST_JSON_ARCH == 32
50   static constexpr std::size_t sbo_chars_ = 10; 50   static constexpr std::size_t sbo_chars_ = 10;
51   #else 51   #else
52   # error Unknown architecture 52   # error Unknown architecture
53   #endif 53   #endif
54   54  
  55 + static constexpr
  56 + unsigned char
  57 + short_flag = 0x80;
  58 +
  59 + static constexpr
  60 + unsigned char
  61 + key_flag = 0x40;
  62 +
  63 + static constexpr
  64 + unsigned char
  65 + seamless_flag = 0x20;
  66 +
  67 + void
HITGNC   68 + 2 set_storage_kind(unsigned char storage_kind)
  69 + {
HITGNC   70 + 2 unsigned char current = static_cast<unsigned char>(s_.k);
HITGNC   71 + 2 current = current & 0x2F;
HITGNC   72 + 2 s_.k = static_cast<kind>(current | storage_kind);
HITGNC   73 + 2 }
  74 +
55   static 75   static
56   constexpr 76   constexpr
57   kind 77   kind
58   short_string_ = 78   short_string_ =
59   static_cast<kind>( 79   static_cast<kind>(
60   ((unsigned char) 80   ((unsigned char)
61 - kind::string) | 0x80); 81 + kind::string) | short_flag);
62   82  
63   static 83   static
64   constexpr 84   constexpr
65   kind 85   kind
66   key_string_ = 86   key_string_ =
67   static_cast<kind>( 87   static_cast<kind>(
68   ((unsigned char) 88   ((unsigned char)
69 - kind::string) | 0x40); 89 + kind::string) | key_flag);
70   90  
71   struct sbo 91   struct sbo
72   { 92   {
73   kind k; // must come first 93   kind k; // must come first
74   char buf[sbo_chars_ + 1]; 94   char buf[sbo_chars_ + 1];
75   }; 95   };
76   96  
77   struct pointer 97   struct pointer
78   { 98   {
79   kind k; // must come first 99   kind k; // must come first
80   table* t; 100   table* t;
81   }; 101   };
82   102  
83   struct key 103   struct key
84   { 104   {
85   kind k; // must come first 105   kind k; // must come first
86   std::uint32_t n; 106   std::uint32_t n;
87   char* s; 107   char* s;
88   }; 108   };
89   109  
90   union 110   union
91   { 111   {
92   sbo s_; 112   sbo s_;
93   pointer p_; 113   pointer p_;
94   key k_; 114   key k_;
95   }; 115   };
96   116  
97   #if BOOST_JSON_ARCH == 64 117   #if BOOST_JSON_ARCH == 64
98   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 ); 118   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
99   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 ); 119   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
100   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 ); 120   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
101   #elif BOOST_JSON_ARCH == 32 121   #elif BOOST_JSON_ARCH == 32
102   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 ); 122   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
103   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 ); 123   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
104   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 ); 124   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
105   #endif 125   #endif
106   126  
107   public: 127   public:
108   static 128   static
109   constexpr 129   constexpr
110   std::size_t 130   std::size_t
HITCBC 111   154089 max_size() noexcept 131   154259 max_size() noexcept
112   { 132   {
113   // max_size depends on the address model 133   // max_size depends on the address model
114   using min = std::integral_constant<std::size_t, 134   using min = std::integral_constant<std::size_t,
115   std::size_t(-1) - sizeof(table)>; 135   std::size_t(-1) - sizeof(table)>;
116   return min::value < BOOST_JSON_MAX_STRING_SIZE ? 136   return min::value < BOOST_JSON_MAX_STRING_SIZE ?
HITCBC 117   154089 min::value : BOOST_JSON_MAX_STRING_SIZE; 137   154259 min::value : BOOST_JSON_MAX_STRING_SIZE;
118   } 138   }
119   139  
120   BOOST_JSON_DECL 140   BOOST_JSON_DECL
121   string_impl() noexcept; 141   string_impl() noexcept;
122   142  
123   BOOST_JSON_DECL 143   BOOST_JSON_DECL
124   string_impl( 144   string_impl(
125   std::size_t new_size, 145   std::size_t new_size,
126   storage_ptr const& sp); 146   storage_ptr const& sp);
127   147  
128   BOOST_JSON_DECL 148   BOOST_JSON_DECL
129   string_impl( 149   string_impl(
130   key_t, 150   key_t,
131   string_view s, 151   string_view s,
132   storage_ptr const& sp); 152   storage_ptr const& sp);
133   153  
134   BOOST_JSON_DECL 154   BOOST_JSON_DECL
135   string_impl( 155   string_impl(
136   key_t, 156   key_t,
137   string_view s1, 157   string_view s1,
138   string_view s2, 158   string_view s2,
139   storage_ptr const& sp); 159   storage_ptr const& sp);
140   160  
141   BOOST_JSON_DECL 161   BOOST_JSON_DECL
142   string_impl( 162   string_impl(
143   char** dest, 163   char** dest,
144   std::size_t len, 164   std::size_t len,
145   storage_ptr const& sp); 165   storage_ptr const& sp);
146   166  
147   template<class InputIt> 167   template<class InputIt>
HITCBC 148   8 string_impl( 168   8 string_impl(
149   InputIt first, 169   InputIt first,
150   InputIt last, 170   InputIt last,
151   storage_ptr const& sp, 171   storage_ptr const& sp,
152   std::random_access_iterator_tag) 172   std::random_access_iterator_tag)
HITCBC 153   8 : string_impl(last - first, sp) 173   8 : string_impl(last - first, sp)
154   { 174   {
HITCBC 155   7 char* out = data(); 175   7 char* out = data();
156   #if defined(_MSC_VER) && _MSC_VER <= 1900 176   #if defined(_MSC_VER) && _MSC_VER <= 1900
157   while( first != last ) 177   while( first != last )
158   *out++ = *first++; 178   *out++ = *first++;
159   #else 179   #else
HITCBC 160   7 std::copy(first, last, out); 180   7 std::copy(first, last, out);
161   #endif 181   #endif
HITCBC 162   7 } 182   7 }
163   183  
164   template<class InputIt> 184   template<class InputIt>
HITCBC 165   38 string_impl( 185   38 string_impl(
166   InputIt first, 186   InputIt first,
167   InputIt last, 187   InputIt last,
168   storage_ptr const& sp, 188   storage_ptr const& sp,
169   std::input_iterator_tag) 189   std::input_iterator_tag)
HITCBC 170   38 : string_impl(0, sp) 190   38 : string_impl(0, sp)
171   { 191   {
172   struct undo 192   struct undo
173   { 193   {
174   string_impl* s; 194   string_impl* s;
175   storage_ptr const& sp; 195   storage_ptr const& sp;
176   196  
HITCBC 177   38 ~undo() 197   38 ~undo()
178   { 198   {
HITCBC 179   38 if(s) 199   38 if(s)
HITCBC 180   3 s->destroy(sp); 200   3 s->destroy(sp);
HITCBC 181   38 } 201   38 }
182   }; 202   };
183   203  
HITCBC 184   38 undo u{this, sp}; 204   38 undo u{this, sp};
HITCBC 185   38 auto dest = data(); 205   38 auto dest = data();
HITCBC 186   313 while(first != last) 206   313 while(first != last)
187   { 207   {
HITCBC 188   278 if(size() < capacity()) 208   278 if(size() < capacity())
HITCBC 189   267 size(size() + 1); 209   267 size(size() + 1);
190   else 210   else
HITCBC 191   11 dest = append(1, sp); 211   11 dest = append(1, sp);
HITCBC 192   275 *dest++ = *first++; 212   275 *dest++ = *first++;
193   } 213   }
HITCBC 194   35 term(size()); 214   35 term(size());
HITCBC 195   35 u.s = nullptr; 215   35 u.s = nullptr;
HITCBC 196   38 } 216   38 }
197   217  
198   std::size_t 218   std::size_t
HITCBC 199   99341 size() const noexcept 219   99932 size() const noexcept
200   { 220   {
HITCBC 201   99341 return s_.k == kind::string ? 221   99932 return s_.k == kind::string ?
HITCBC 202   64680 p_.t->size : 222   65016 p_.t->size :
203   sbo_chars_ - 223   sbo_chars_ -
HITCBC 204   99341 s_.buf[sbo_chars_]; 224   99932 s_.buf[sbo_chars_];
205   } 225   }
206   226  
207   std::size_t 227   std::size_t
HITCBC 208   92080 capacity() const noexcept 228   92398 capacity() const noexcept
209   { 229   {
HITCBC 210   92080 return s_.k == kind::string ? 230   92398 return s_.k == kind::string ?
HITCBC 211   11846 p_.t->capacity : 231   11962 p_.t->capacity :
HITCBC 212   92080 sbo_chars_; 232   92398 sbo_chars_;
213   } 233   }
214   234  
215   void 235   void
HITCBC 216   10018 size(std::size_t n) 236   10059 size(std::size_t n)
217   { 237   {
HITCBC 218   10018 if(s_.k == kind::string) 238   10059 if(s_.k == kind::string)
HITCBC 219   9735 p_.t->size = static_cast< 239   9776 p_.t->size = static_cast<
220   std::uint32_t>(n); 240   std::uint32_t>(n);
221   else 241   else
HITCBC 222   283 s_.buf[sbo_chars_] = 242   283 s_.buf[sbo_chars_] =
223   static_cast<char>( 243   static_cast<char>(
HITCBC 224   283 sbo_chars_ - n); 244   283 sbo_chars_ - n);
HITCBC 225   10018 } 245   10059 }
226   246  
227   BOOST_JSON_DECL 247   BOOST_JSON_DECL
228   static 248   static
229   std::uint32_t 249   std::uint32_t
230   growth( 250   growth(
231   std::size_t new_size, 251   std::size_t new_size,
232   std::size_t capacity); 252   std::size_t capacity);
233   253  
234   char const* 254   char const*
HITCBC 235   38150 release_key( 255   38154 release_key(
236   std::size_t& n) noexcept 256   std::size_t& n) noexcept
237   { 257   {
HITCBC 238 - 38150 BOOST_ASSERT( 258 + 38154 BOOST_ASSERT( is_key() );
HITGIC 239 - k_.k == key_string_); 259 + 38154 BOOST_ASSERT( ! is_seamless() );
HITCBC 240   38150 n = k_.n; 260   38154 n = k_.n;
HITCBC 241   38150 auto const s = k_.s; 261   38154 auto const s = k_.s;
242   // prevent deallocate 262   // prevent deallocate
HITCBC 243   38150 k_.k = short_string_; 263   38154 k_.k = short_string_;
HITCBC 244   38150 return s; 264   38154 return s;
245   } 265   }
246   266  
247   void 267   void
HITCBC 248 - 57716 destroy( 268 + 57834 destroy(storage_ptr const& sp) noexcept
249 - storage_ptr const& sp) noexcept  
250   { 269   {
HITCBC 251 - 57716 if(s_.k == kind::string) 270 + 57834 if( is_short() )
252 - {  
DCB 253 - 26698 sp->deallocate(p_.t,  
254 - sizeof(table) +  
DCB 255 - 26698 p_.t->capacity + 1,  
256 - alignof(table));  
257 - }  
DCB 258 - 31018 else if(s_.k != key_string_)  
259   { 271   {
260   // do nothing 272   // do nothing
261   } 273   }
HITGIC 262 - else 274 + 26885 else if( is_key() )
263 - BOOST_ASSERT(  
DCB 264 - 146 s_.k == key_string_);  
265   { 275   {
266   // VFALCO unfortunately the key string 276   // VFALCO unfortunately the key string
267   // kind increases the cost of the destructor. 277   // kind increases the cost of the destructor.
268   // This function should be skipped when using 278   // This function should be skipped when using
269   // monotonic_resource. 279   // monotonic_resource.
HITCBC 270   146 sp->deallocate(k_.s, k_.n + 1); 280   146 sp->deallocate(k_.s, k_.n + 1);
271   } 281   }
  282 + else
  283 + {
HITGNC   284 + 26739 sp->deallocate(
HITGNC   285 + 26739 p_.t, sizeof(table) + p_.t->capacity + 1, alignof(table));
  286 + }
HITCBC 272   57716 } 287   57834 }
273   288  
274   BOOST_JSON_DECL 289   BOOST_JSON_DECL
275   char* 290   char*
276   assign( 291   assign(
277   std::size_t new_size, 292   std::size_t new_size,
278   storage_ptr const& sp); 293   storage_ptr const& sp);
279   294  
280   BOOST_JSON_DECL 295   BOOST_JSON_DECL
281   char* 296   char*
282   append( 297   append(
283   std::size_t n, 298   std::size_t n,
284   storage_ptr const& sp); 299   storage_ptr const& sp);
285   300  
286   BOOST_JSON_DECL 301   BOOST_JSON_DECL
287   void 302   void
288   insert( 303   insert(
289   std::size_t pos, 304   std::size_t pos,
290   const char* s, 305   const char* s,
291   std::size_t n, 306   std::size_t n,
292   storage_ptr const& sp); 307   storage_ptr const& sp);
293   308  
294   BOOST_JSON_DECL 309   BOOST_JSON_DECL
295   char* 310   char*
296   insert_unchecked( 311   insert_unchecked(
297   std::size_t pos, 312   std::size_t pos,
298   std::size_t n, 313   std::size_t n,
299   storage_ptr const& sp); 314   storage_ptr const& sp);
300   315  
301   BOOST_JSON_DECL 316   BOOST_JSON_DECL
302   void 317   void
303   replace( 318   replace(
304   std::size_t pos, 319   std::size_t pos,
305   std::size_t n1, 320   std::size_t n1,
306   const char* s, 321   const char* s,
307   std::size_t n2, 322   std::size_t n2,
308   storage_ptr const& sp); 323   storage_ptr const& sp);
309   324  
310   BOOST_JSON_DECL 325   BOOST_JSON_DECL
311   char* 326   char*
312   replace_unchecked( 327   replace_unchecked(
313   std::size_t pos, 328   std::size_t pos,
314   std::size_t n1, 329   std::size_t n1,
315   std::size_t n2, 330   std::size_t n2,
316   storage_ptr const& sp); 331   storage_ptr const& sp);
317   332  
318   BOOST_JSON_DECL 333   BOOST_JSON_DECL
319   void 334   void
320   shrink_to_fit( 335   shrink_to_fit(
321   storage_ptr const& sp) noexcept; 336   storage_ptr const& sp) noexcept;
322   337  
323   void 338   void
HITCBC 324   33656 term(std::size_t n) noexcept 339   33801 term(std::size_t n) noexcept
325   { 340   {
HITCBC 326 - 33656 if(s_.k == short_string_) 341 + 33801 if( is_short() )
327   { 342   {
HITCBC 328 - 5145 s_.buf[sbo_chars_] = 343 + 5177 s_.buf[sbo_chars_] = static_cast<char>(sbo_chars_ - n);
329 - static_cast<char>(  
DCB 330 - 5145 sbo_chars_ - n);  
HITCBC 331   5145 s_.buf[n] = 0; 344   5177 s_.buf[n] = 0;
332   } 345   }
333   else 346   else
334   { 347   {
HITCBC 335 - 28511 p_.t->size = static_cast< 348 + 28624 p_.t->size = static_cast<std::uint32_t>(n);
336 - std::uint32_t>(n);  
HITCBC 337   28511 data()[n] = 0; 349   28624 data()[n] = 0;
338   } 350   }
HITCBC 339   33656 } 351   33801 }
340   352  
341   char* 353   char*
HITCBC 342   117573 data() noexcept 354   117954 data() noexcept
343   { 355   {
HITCBC 344 - 117573 if(s_.k == short_string_) 356 + 117954 if( is_short() )
HITCBC 345   15422 return s_.buf; 357   15495 return s_.buf;
HITGIC 346 - return reinterpret_cast< 358 + 102459 return reinterpret_cast<char*>(p_.t + 1);
DCB 347 - 102151 char*>(p_.t + 1);  
348   } 359   }
349   360  
350   char const* 361   char const*
HITCBC 351   44033 data() const noexcept 362   44202 data() const noexcept
352   { 363   {
HITCBC 353 - 44033 if(s_.k == short_string_) 364 + 44202 if( is_short() )
HITCBC 354   4553 return s_.buf; 365   4684 return s_.buf;
HITGIC 355 - return reinterpret_cast< 366 + 39518 return reinterpret_cast<char const*>(p_.t + 1);
DCB 356 - 39480 char const*>(p_.t + 1);  
357   } 367   }
358   368  
359   char* 369   char*
HITCBC 360   241 end() noexcept 370   241 end() noexcept
361   { 371   {
HITCBC 362   241 return data() + size(); 372   241 return data() + size();
363   } 373   }
364   374  
365   char const* 375   char const*
HITCBC 366   10 end() const noexcept 376   10 end() const noexcept
367   { 377   {
HITCBC 368   10 return data() + size(); 378   10 return data() + size();
  379 + }
  380 +
  381 + inline
  382 + constexpr
  383 + bool
HITGNC   384 + 253798 is_short() const noexcept
  385 + {
HITGNC   386 + 253798 return static_cast<unsigned char>(s_.k) & short_flag;
  387 + }
  388 +
  389 + inline
  390 + constexpr
  391 + bool
HITGNC   392 + 65039 is_key() const noexcept
  393 + {
HITGNC   394 + 65039 return static_cast<unsigned char>(s_.k) & key_flag;
  395 + }
  396 +
  397 + inline
  398 + constexpr
  399 + bool
HITGNC   400 + 52905 is_seamless() const noexcept
  401 + {
HITGNC   402 + 52905 return static_cast<unsigned char>(s_.k) & seamless_flag;
  403 + }
  404 +
  405 + void
HITGNC   406 + 4 set_seamless(bool on) noexcept
  407 + {
HITGNC   408 + 4 unsigned char const seamless = on ? seamless_flag : 0;
HITGNC   409 + 4 unsigned char current = static_cast<unsigned char>(s_.k);
HITGNC   410 + 4 current = current & 0xCF;
HITGNC   411 + 4 s_.k = static_cast<kind>(current | seamless);
HITGIC 369   } 412   4 }
370   }; 413   };
371   414  
372   template<class T> 415   template<class T>
373   string_view 416   string_view
HITCBC 374   2486 to_string_view(T const& t) noexcept 417   2530 to_string_view(T const& t) noexcept
375   { 418   {
HITCBC 376   2486 return string_view(t); 419   2530 return string_view(t);
377   } 420   }
378   421  
379   template<class T, class U> 422   template<class T, class U>
380   using string_and_stringlike = std::integral_constant<bool, 423   using string_and_stringlike = std::integral_constant<bool,
381   std::is_same<T, string>::value && 424   std::is_same<T, string>::value &&
382   std::is_convertible<U const&, string_view>::value>; 425   std::is_convertible<U const&, string_view>::value>;
383   426  
384   template<class T, class U> 427   template<class T, class U>
385   using string_comp_op_requirement 428   using string_comp_op_requirement
386   = typename std::enable_if< 429   = typename std::enable_if<
387   string_and_stringlike<T, U>::value || 430   string_and_stringlike<T, U>::value ||
388   string_and_stringlike<U, T>::value, 431   string_and_stringlike<U, T>::value,
389   bool>::type; 432   bool>::type;
390   433  
391   } // detail 434   } // detail
392   } // namespace json 435   } // namespace json
393   } // namespace boost 436   } // namespace boost
394   437  
395   #endif 438   #endif