100.00% Lines (76/76) 100.00% Functions (16/16)
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 55   static
56   constexpr 56   constexpr
57   kind 57   kind
58   short_string_ = 58   short_string_ =
59   static_cast<kind>( 59   static_cast<kind>(
60   ((unsigned char) 60   ((unsigned char)
61   kind::string) | 0x80); 61   kind::string) | 0x80);
62   62  
63   static 63   static
64   constexpr 64   constexpr
65   kind 65   kind
66   key_string_ = 66   key_string_ =
67   static_cast<kind>( 67   static_cast<kind>(
68   ((unsigned char) 68   ((unsigned char)
69   kind::string) | 0x40); 69   kind::string) | 0x40);
70   70  
71   struct sbo 71   struct sbo
72   { 72   {
73   kind k; // must come first 73   kind k; // must come first
74   char buf[sbo_chars_ + 1]; 74   char buf[sbo_chars_ + 1];
75   }; 75   };
76   76  
77   struct pointer 77   struct pointer
78   { 78   {
79   kind k; // must come first 79   kind k; // must come first
80   table* t; 80   table* t;
81   }; 81   };
82   82  
83   struct key 83   struct key
84   { 84   {
85   kind k; // must come first 85   kind k; // must come first
86   std::uint32_t n; 86   std::uint32_t n;
87   char* s; 87   char* s;
88   }; 88   };
89   89  
90   union 90   union
91   { 91   {
92   sbo s_; 92   sbo s_;
93   pointer p_; 93   pointer p_;
94   key k_; 94   key k_;
95   }; 95   };
96   96  
97   #if BOOST_JSON_ARCH == 64 97   #if BOOST_JSON_ARCH == 64
98   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 ); 98   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
99   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 ); 99   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
100   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 ); 100   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
101   #elif BOOST_JSON_ARCH == 32 101   #elif BOOST_JSON_ARCH == 32
102   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 ); 102   BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
103   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 ); 103   BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
104   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 ); 104   BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
105   #endif 105   #endif
106   106  
107   public: 107   public:
108   static 108   static
109   constexpr 109   constexpr
110   std::size_t 110   std::size_t
HITCBC 111   154065 max_size() noexcept 111   154065 max_size() noexcept
112   { 112   {
113   // max_size depends on the address model 113   // max_size depends on the address model
114   using min = std::integral_constant<std::size_t, 114   using min = std::integral_constant<std::size_t,
115   std::size_t(-1) - sizeof(table)>; 115   std::size_t(-1) - sizeof(table)>;
116   return min::value < BOOST_JSON_MAX_STRING_SIZE ? 116   return min::value < BOOST_JSON_MAX_STRING_SIZE ?
HITCBC 117   154065 min::value : BOOST_JSON_MAX_STRING_SIZE; 117   154065 min::value : BOOST_JSON_MAX_STRING_SIZE;
118   } 118   }
119   119  
120   BOOST_JSON_DECL 120   BOOST_JSON_DECL
121   string_impl() noexcept; 121   string_impl() noexcept;
122   122  
123   BOOST_JSON_DECL 123   BOOST_JSON_DECL
124   string_impl( 124   string_impl(
125   std::size_t new_size, 125   std::size_t new_size,
126   storage_ptr const& sp); 126   storage_ptr const& sp);
127   127  
128   BOOST_JSON_DECL 128   BOOST_JSON_DECL
129   string_impl( 129   string_impl(
130   key_t, 130   key_t,
131   string_view s, 131   string_view s,
132   storage_ptr const& sp); 132   storage_ptr const& sp);
133   133  
134   BOOST_JSON_DECL 134   BOOST_JSON_DECL
135   string_impl( 135   string_impl(
136   key_t, 136   key_t,
137   string_view s1, 137   string_view s1,
138   string_view s2, 138   string_view s2,
139   storage_ptr const& sp); 139   storage_ptr const& sp);
140   140  
141   BOOST_JSON_DECL 141   BOOST_JSON_DECL
142   string_impl( 142   string_impl(
143   char** dest, 143   char** dest,
144   std::size_t len, 144   std::size_t len,
145   storage_ptr const& sp); 145   storage_ptr const& sp);
146   146  
147   template<class InputIt> 147   template<class InputIt>
HITCBC 148   8 string_impl( 148   8 string_impl(
149   InputIt first, 149   InputIt first,
150   InputIt last, 150   InputIt last,
151   storage_ptr const& sp, 151   storage_ptr const& sp,
152   std::random_access_iterator_tag) 152   std::random_access_iterator_tag)
HITCBC 153   8 : string_impl(last - first, sp) 153   8 : string_impl(last - first, sp)
154   { 154   {
HITCBC 155   7 char* out = data(); 155   7 char* out = data();
156   #if defined(_MSC_VER) && _MSC_VER <= 1900 156   #if defined(_MSC_VER) && _MSC_VER <= 1900
157   while( first != last ) 157   while( first != last )
158   *out++ = *first++; 158   *out++ = *first++;
159   #else 159   #else
HITCBC 160   7 std::copy(first, last, out); 160   7 std::copy(first, last, out);
161   #endif 161   #endif
HITCBC 162   7 } 162   7 }
163   163  
164   template<class InputIt> 164   template<class InputIt>
HITCBC 165   38 string_impl( 165   38 string_impl(
166   InputIt first, 166   InputIt first,
167   InputIt last, 167   InputIt last,
168   storage_ptr const& sp, 168   storage_ptr const& sp,
169   std::input_iterator_tag) 169   std::input_iterator_tag)
HITCBC 170   38 : string_impl(0, sp) 170   38 : string_impl(0, sp)
171   { 171   {
172   struct undo 172   struct undo
173   { 173   {
174   string_impl* s; 174   string_impl* s;
175   storage_ptr const& sp; 175   storage_ptr const& sp;
176   176  
HITCBC 177   38 ~undo() 177   38 ~undo()
178   { 178   {
HITCBC 179   38 if(s) 179   38 if(s)
HITCBC 180   3 s->destroy(sp); 180   3 s->destroy(sp);
HITCBC 181   38 } 181   38 }
182   }; 182   };
183   183  
HITCBC 184   38 undo u{this, sp}; 184   38 undo u{this, sp};
HITCBC 185   38 auto dest = data(); 185   38 auto dest = data();
HITCBC 186   313 while(first != last) 186   313 while(first != last)
187   { 187   {
HITCBC 188   278 if(size() < capacity()) 188   278 if(size() < capacity())
HITCBC 189   267 size(size() + 1); 189   267 size(size() + 1);
190   else 190   else
HITCBC 191   11 dest = append(1, sp); 191   11 dest = append(1, sp);
HITCBC 192   275 *dest++ = *first++; 192   275 *dest++ = *first++;
193   } 193   }
HITCBC 194   35 term(size()); 194   35 term(size());
HITCBC 195   35 u.s = nullptr; 195   35 u.s = nullptr;
HITCBC 196   38 } 196   38 }
197   197  
198   std::size_t 198   std::size_t
HITCBC 199   99337 size() const noexcept 199   99337 size() const noexcept
200   { 200   {
HITCBC 201   99337 return s_.k == kind::string ? 201   99337 return s_.k == kind::string ?
HITCBC 202   64676 p_.t->size : 202   64676 p_.t->size :
203   sbo_chars_ - 203   sbo_chars_ -
HITCBC 204   99337 s_.buf[sbo_chars_]; 204   99337 s_.buf[sbo_chars_];
205   } 205   }
206   206  
207   std::size_t 207   std::size_t
HITCBC 208   92068 capacity() const noexcept 208   92068 capacity() const noexcept
209   { 209   {
HITCBC 210   92068 return s_.k == kind::string ? 210   92068 return s_.k == kind::string ?
HITCBC 211   11846 p_.t->capacity : 211   11846 p_.t->capacity :
HITCBC 212   92068 sbo_chars_; 212   92068 sbo_chars_;
213   } 213   }
214   214  
215   void 215   void
HITCBC 216   10018 size(std::size_t n) 216   10018 size(std::size_t n)
217   { 217   {
HITCBC 218   10018 if(s_.k == kind::string) 218   10018 if(s_.k == kind::string)
HITCBC 219   9735 p_.t->size = static_cast< 219   9735 p_.t->size = static_cast<
220   std::uint32_t>(n); 220   std::uint32_t>(n);
221   else 221   else
HITCBC 222   283 s_.buf[sbo_chars_] = 222   283 s_.buf[sbo_chars_] =
223   static_cast<char>( 223   static_cast<char>(
HITCBC 224   283 sbo_chars_ - n); 224   283 sbo_chars_ - n);
HITCBC 225   10018 } 225   10018 }
226   226  
227   BOOST_JSON_DECL 227   BOOST_JSON_DECL
228   static 228   static
229   std::uint32_t 229   std::uint32_t
230   growth( 230   growth(
231   std::size_t new_size, 231   std::size_t new_size,
232   std::size_t capacity); 232   std::size_t capacity);
233   233  
234   char const* 234   char const*
HITCBC 235   38150 release_key( 235   38150 release_key(
236   std::size_t& n) noexcept 236   std::size_t& n) noexcept
237   { 237   {
HITCBC 238   38150 BOOST_ASSERT( 238   38150 BOOST_ASSERT(
239   k_.k == key_string_); 239   k_.k == key_string_);
HITCBC 240   38150 n = k_.n; 240   38150 n = k_.n;
HITCBC 241   38150 auto const s = k_.s; 241   38150 auto const s = k_.s;
242   // prevent deallocate 242   // prevent deallocate
HITCBC 243   38150 k_.k = short_string_; 243   38150 k_.k = short_string_;
HITCBC 244   38150 return s; 244   38150 return s;
245   } 245   }
246   246  
247   void 247   void
HITCBC 248   57706 destroy( 248   57706 destroy(
249   storage_ptr const& sp) noexcept 249   storage_ptr const& sp) noexcept
250   { 250   {
HITCBC 251   57706 if(s_.k == kind::string) 251   57706 if(s_.k == kind::string)
252   { 252   {
HITCBC 253   26694 sp->deallocate(p_.t, 253   26694 sp->deallocate(p_.t,
254   sizeof(table) + 254   sizeof(table) +
HITCBC 255   26694 p_.t->capacity + 1, 255   26694 p_.t->capacity + 1,
256   alignof(table)); 256   alignof(table));
257   } 257   }
HITCBC 258   31012 else if(s_.k != key_string_) 258   31012 else if(s_.k != key_string_)
259   { 259   {
260   // do nothing 260   // do nothing
261   } 261   }
262   else 262   else
263   { 263   {
HITCBC 264   146 BOOST_ASSERT( 264   146 BOOST_ASSERT(
265   s_.k == key_string_); 265   s_.k == key_string_);
266   // VFALCO unfortunately the key string 266   // VFALCO unfortunately the key string
267   // kind increases the cost of the destructor. 267   // kind increases the cost of the destructor.
268   // This function should be skipped when using 268   // This function should be skipped when using
269   // monotonic_resource. 269   // monotonic_resource.
HITCBC 270   146 sp->deallocate(k_.s, k_.n + 1); 270   146 sp->deallocate(k_.s, k_.n + 1);
271   } 271   }
HITCBC 272   57706 } 272   57706 }
273   273  
274   BOOST_JSON_DECL 274   BOOST_JSON_DECL
275   char* 275   char*
276   assign( 276   assign(
277   std::size_t new_size, 277   std::size_t new_size,
278   storage_ptr const& sp); 278   storage_ptr const& sp);
279   279  
280   BOOST_JSON_DECL 280   BOOST_JSON_DECL
281   char* 281   char*
282   append( 282   append(
283   std::size_t n, 283   std::size_t n,
284   storage_ptr const& sp); 284   storage_ptr const& sp);
285   285  
286   BOOST_JSON_DECL 286   BOOST_JSON_DECL
287   void 287   void
288   insert( 288   insert(
289   std::size_t pos, 289   std::size_t pos,
290   const char* s, 290   const char* s,
291   std::size_t n, 291   std::size_t n,
292   storage_ptr const& sp); 292   storage_ptr const& sp);
293   293  
294   BOOST_JSON_DECL 294   BOOST_JSON_DECL
295   char* 295   char*
296   insert_unchecked( 296   insert_unchecked(
297   std::size_t pos, 297   std::size_t pos,
298   std::size_t n, 298   std::size_t n,
299   storage_ptr const& sp); 299   storage_ptr const& sp);
300   300  
301   BOOST_JSON_DECL 301   BOOST_JSON_DECL
302   void 302   void
303   replace( 303   replace(
304   std::size_t pos, 304   std::size_t pos,
305   std::size_t n1, 305   std::size_t n1,
306   const char* s, 306   const char* s,
307   std::size_t n2, 307   std::size_t n2,
308   storage_ptr const& sp); 308   storage_ptr const& sp);
309   309  
310   BOOST_JSON_DECL 310   BOOST_JSON_DECL
311   char* 311   char*
312   replace_unchecked( 312   replace_unchecked(
313   std::size_t pos, 313   std::size_t pos,
314   std::size_t n1, 314   std::size_t n1,
315   std::size_t n2, 315   std::size_t n2,
316   storage_ptr const& sp); 316   storage_ptr const& sp);
317   317  
318   BOOST_JSON_DECL 318   BOOST_JSON_DECL
319   void 319   void
320   shrink_to_fit( 320   shrink_to_fit(
321   storage_ptr const& sp) noexcept; 321   storage_ptr const& sp) noexcept;
322   322  
323   void 323   void
HITCBC 324   33652 term(std::size_t n) noexcept 324   33652 term(std::size_t n) noexcept
325   { 325   {
HITCBC 326   33652 if(s_.k == short_string_) 326   33652 if(s_.k == short_string_)
327   { 327   {
HITCBC 328   5145 s_.buf[sbo_chars_] = 328   5145 s_.buf[sbo_chars_] =
329   static_cast<char>( 329   static_cast<char>(
HITCBC 330   5145 sbo_chars_ - n); 330   5145 sbo_chars_ - n);
HITCBC 331   5145 s_.buf[n] = 0; 331   5145 s_.buf[n] = 0;
332   } 332   }
333   else 333   else
334   { 334   {
HITCBC 335   28507 p_.t->size = static_cast< 335   28507 p_.t->size = static_cast<
336   std::uint32_t>(n); 336   std::uint32_t>(n);
HITCBC 337   28507 data()[n] = 0; 337   28507 data()[n] = 0;
338   } 338   }
HITCBC 339   33652 } 339   33652 }
340   340  
341   char* 341   char*
HITCBC 342   117561 data() noexcept 342   117561 data() noexcept
343   { 343   {
HITCBC 344   117561 if(s_.k == short_string_) 344   117561 if(s_.k == short_string_)
HITCBC 345   15422 return s_.buf; 345   15422 return s_.buf;
346   return reinterpret_cast< 346   return reinterpret_cast<
HITCBC 347   102139 char*>(p_.t + 1); 347   102139 char*>(p_.t + 1);
348   } 348   }
349   349  
350   char const* 350   char const*
HITCBC 351   44029 data() const noexcept 351   44029 data() const noexcept
352   { 352   {
HITCBC 353   44029 if(s_.k == short_string_) 353   44029 if(s_.k == short_string_)
HITCBC 354   4553 return s_.buf; 354   4553 return s_.buf;
355   return reinterpret_cast< 355   return reinterpret_cast<
HITCBC 356   39476 char const*>(p_.t + 1); 356   39476 char const*>(p_.t + 1);
357   } 357   }
358   358  
359   char* 359   char*
HITCBC 360   241 end() noexcept 360   241 end() noexcept
361   { 361   {
HITCBC 362   241 return data() + size(); 362   241 return data() + size();
363   } 363   }
364   364  
365   char const* 365   char const*
HITCBC 366   10 end() const noexcept 366   10 end() const noexcept
367   { 367   {
HITCBC 368   10 return data() + size(); 368   10 return data() + size();
369   } 369   }
370   }; 370   };
371   371  
372   template<class T> 372   template<class T>
373   string_view 373   string_view
HITCBC 374   2486 to_string_view(T const& t) noexcept 374   2486 to_string_view(T const& t) noexcept
375   { 375   {
HITCBC 376   2486 return string_view(t); 376   2486 return string_view(t);
377   } 377   }
378   378  
379   template<class T, class U> 379   template<class T, class U>
380   using string_and_stringlike = std::integral_constant<bool, 380   using string_and_stringlike = std::integral_constant<bool,
381   std::is_same<T, string>::value && 381   std::is_same<T, string>::value &&
382   std::is_convertible<U const&, string_view>::value>; 382   std::is_convertible<U const&, string_view>::value>;
383   383  
384   template<class T, class U> 384   template<class T, class U>
385   using string_comp_op_requirement 385   using string_comp_op_requirement
386   = typename std::enable_if< 386   = typename std::enable_if<
387   string_and_stringlike<T, U>::value || 387   string_and_stringlike<T, U>::value ||
388   string_and_stringlike<U, T>::value, 388   string_and_stringlike<U, T>::value,
389   bool>::type; 389   bool>::type;
390   390  
391   } // detail 391   } // detail
392   } // namespace json 392   } // namespace json
393   } // namespace boost 393   } // namespace boost
394   394  
395   #endif 395   #endif