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