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