100.00% Lines (177/177) 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   178 string::
41   string( 41   string(
42   char const* s, 42   char const* s,
HITCBC 43   175 storage_ptr sp) 43   178 storage_ptr sp)
HITCBC 44   175 : sp_(std::move(sp)) 44   178 : sp_(std::move(sp))
45   { 45   {
HITCBC 46   175 assign(s); 46   178 assign(s);
HITCBC 47   175 } 47   178 }
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   158 string:: 66   158 string::
67   string( 67   string(
68   string const& other, 68   string const& other,
HITCBC 69   158 storage_ptr sp) 69   158 storage_ptr sp)
HITCBC 70   158 : sp_(std::move(sp)) 70   158 : sp_(std::move(sp))
71   { 71   {
HITCBC 72   158 assign(other); 72   158 assign(other);
HITCBC 73   158 } 73   158 }
74   74  
HITCBC 75   355 string:: 75   355 string::
76   string( 76   string(
77   string&& other, 77   string&& other,
HITCBC 78   355 storage_ptr sp) 78   355 storage_ptr sp)
HITCBC 79   355 : sp_(std::move(sp)) 79   355 : sp_(std::move(sp))
80   { 80   {
HITCBC 81   355 assign(std::move(other)); 81   355 assign(std::move(other));
HITCBC 82   355 } 82   355 }
83   83  
HITCBC 84   17893 string:: 84   17893 string::
85   string( 85   string(
86   string_view s, 86   string_view s,
HITCBC 87   17893 storage_ptr sp) 87   17893 storage_ptr sp)
HITCBC 88   17893 : sp_(std::move(sp)) 88   17893 : sp_(std::move(sp))
89   { 89   {
HITCBC 90   17893 assign(s); 90   17893 assign(s);
HITCBC 91   17893 } 91   17893 }
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   210 string:: 143   210 string::
144   assign( 144   assign(
145   string const& other) 145   string const& other)
146   { 146   {
HITCBC 147   210 if(this == &other) 147   210 if(this == &other)
HITCBC 148   1 return *this; 148   1 return *this;
HITCBC 149   209 return assign( 149   209 return assign(
150   other.data(), 150   other.data(),
HITCBC 151   179 other.size()); 151   179 other.size());
152   } 152   }
153   153  
154   string& 154   string&
HITCBC 155   379 string:: 155   379 string::
156   assign(string&& other) 156   assign(string&& other)
157   { 157   {
HITCBC 158   379 if( &other == this ) 158   379 if( &other == this )
HITCBC 159   1 return *this; 159   1 return *this;
160   160  
HITCBC 161   378 if(*sp_ == *other.sp_) 161   378 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   38 return assign(other); 170   38 return assign(other);
171   } 171   }
172   172  
173   string& 173   string&
HITCBC 174   18387 string:: 174   18393 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 - 18261 std::char_traits<char>::copy( 179 + 18393 auto const p = impl_.data();
HITCBC 180 - 18387 impl_.assign(count, sp_), 180 + 18393 if(detail::ptr_in_range(p, p + impl_.size(), s))
181 - s, count); 181 + {
HITGNC   182 + 3 std::char_traits<char>::move(p, s, count);
HITGNC   183 + 3 impl_.term(count);
  184 + }
  185 + else
  186 + {
HITGNC   187 + 18264 std::char_traits<char>::copy(
HITGNC   188 + 18390 impl_.assign(count, sp_),
  189 + s, count);
  190 + }
HITCBC 182   18261 return *this; 191   18267 return *this;
183   } 192   }
184   193  
185   string& 194   string&
HITCBC 186   189 string:: 195   192 string::
187   assign( 196   assign(
188   char const* s) 197   char const* s)
189   { 198   {
HITCBC 190   189 return assign(s, std::char_traits< 199   192 return assign(s, std::char_traits<
HITCBC 191   186 char>::length(s)); 200   189 char>::length(s));
192   } 201   }
193   202  
194   //---------------------------------------------------------- 203   //----------------------------------------------------------
195   // 204   //
196   // Capacity 205   // Capacity
197   // 206   //
198   //---------------------------------------------------------- 207   //----------------------------------------------------------
199   208  
200   void 209   void
HITCBC 201   7 string:: 210   7 string::
202   shrink_to_fit() 211   shrink_to_fit()
203   { 212   {
HITCBC 204   7 impl_.shrink_to_fit(sp_); 213   7 impl_.shrink_to_fit(sp_);
HITCBC 205   7 } 214   7 }
206   215  
207   //---------------------------------------------------------- 216   //----------------------------------------------------------
208   // 217   //
209   // Access 218   // Access
210   // 219   //
211   //---------------------------------------------------------- 220   //----------------------------------------------------------
212   221  
213   system::result<char&> 222   system::result<char&>
HITCBC 214   12 string::try_at(std::size_t pos) noexcept 223   12 string::try_at(std::size_t pos) noexcept
215   { 224   {
HITCBC 216   12 if( pos < size() ) 225   12 if( pos < size() )
HITCBC 217   10 return impl_.data()[pos]; 226   10 return impl_.data()[pos];
218   227  
HITCBC 219   2 system::error_code ec; 228   2 system::error_code ec;
HITCBC 220   2 BOOST_JSON_FAIL(ec, error::out_of_range); 229   2 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 221   2 return ec; 230   2 return ec;
222   } 231   }
223   232  
224   system::result<char const&> 233   system::result<char const&>
HITCBC 225   20 string::try_at(std::size_t pos) const noexcept 234   20 string::try_at(std::size_t pos) const noexcept
226   { 235   {
HITCBC 227   20 if( pos < size() ) 236   20 if( pos < size() )
HITCBC 228   18 return impl_.data()[pos]; 237   18 return impl_.data()[pos];
229   238  
HITCBC 230   2 system::error_code ec; 239   2 system::error_code ec;
HITCBC 231   2 BOOST_JSON_FAIL(ec, error::out_of_range); 240   2 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 232   2 return ec; 241   2 return ec;
233   } 242   }
234   243  
235   char const& 244   char const&
HITCBC 236   18 string::at(std::size_t pos, source_location const& loc) const 245   18 string::at(std::size_t pos, source_location const& loc) const
237   { 246   {
HITCBC 238   18 return try_at(pos).value(loc); 247   18 return try_at(pos).value(loc);
239   } 248   }
240   249  
241   //---------------------------------------------------------- 250   //----------------------------------------------------------
242   // 251   //
243   // Operations 252   // Operations
244   // 253   //
245   //---------------------------------------------------------- 254   //----------------------------------------------------------
246   255  
247   void 256   void
HITCBC 248   2 string:: 257   2 string::
249   clear() noexcept 258   clear() noexcept
250   { 259   {
HITCBC 251   2 impl_.term(0); 260   2 impl_.term(0);
HITCBC 252   2 } 261   2 }
253   262  
254   //---------------------------------------------------------- 263   //----------------------------------------------------------
255   264  
256   void 265   void
HITCBC 257   148 string:: 266   148 string::
258   push_back(char ch) 267   push_back(char ch)
259   { 268   {
HITCBC 260   148 *impl_.append(1, sp_) = ch; 269   148 *impl_.append(1, sp_) = ch;
HITCBC 261   146 } 270   146 }
262   271  
263   void 272   void
HITCBC 264   29 string:: 273   29 string::
265   pop_back() 274   pop_back()
266   { 275   {
HITCBC 267   29 back() = 0; 276   29 back() = 0;
HITCBC 268   29 impl_.size(impl_.size() - 1); 277   29 impl_.size(impl_.size() - 1);
HITCBC 269   29 } 278   29 }
270   279  
271   //---------------------------------------------------------- 280   //----------------------------------------------------------
272   281  
273   string& 282   string&
HITCBC 274   4 string:: 283   4 string::
275   append(size_type count, char ch) 284   append(size_type count, char ch)
276   { 285   {
HITCBC 277   2 std::char_traits<char>::assign( 286   2 std::char_traits<char>::assign(
HITCBC 278   4 impl_.append(count, sp_), 287   4 impl_.append(count, sp_),
279   count, ch); 288   count, ch);
HITCBC 280   2 return *this; 289   2 return *this;
281   } 290   }
282   291  
283   string& 292   string&
HITCBC 284   55 string:: 293   55 string::
285   append(string_view sv) 294   append(string_view sv)
286   { 295   {
HITCBC 287   55 auto const p = impl_.data(); 296   55 auto const p = impl_.data();
HITCBC 288   55 if(detail::ptr_in_range(p, p + impl_.size(), sv.data())) 297   55 if(detail::ptr_in_range(p, p + impl_.size(), sv.data()))
289   { 298   {
290   // sv aliases our own storage; appending may reallocate and free the 299   // sv aliases our own storage; appending may reallocate and free the
291   // buffer sv points into, so copy from the relocated offset afterwards 300   // buffer sv points into, so copy from the relocated offset afterwards
HITCBC 292   10 auto const offset = sv.data() - p; 301   10 auto const offset = sv.data() - p;
HITCBC 293   10 auto const dest = impl_.append(sv.size(), sp_); 302   10 auto const dest = impl_.append(sv.size(), sp_);
HITCBC 294   8 std::char_traits<char>::copy( 303   8 std::char_traits<char>::copy(
HITCBC 295   8 dest, impl_.data() + offset, sv.size()); 304   8 dest, impl_.data() + offset, sv.size());
296   } 305   }
297   else 306   else
298   { 307   {
HITCBC 299   90 std::char_traits<char>::copy( 308   90 std::char_traits<char>::copy(
HITCBC 300   45 impl_.append(sv.size(), sp_), 309   45 impl_.append(sv.size(), sp_),
301   sv.data(), sv.size()); 310   sv.data(), sv.size());
302   } 311   }
HITCBC 303   40 return *this; 312   40 return *this;
304   } 313   }
305   314  
306   //---------------------------------------------------------- 315   //----------------------------------------------------------
307   316  
308   string& 317   string&
HITCBC 309   27 string:: 318   27 string::
310   insert( 319   insert(
311   size_type pos, 320   size_type pos,
312   string_view sv) 321   string_view sv)
313   { 322   {
HITCBC 314   27 impl_.insert(pos, sv.data(), sv.size(), sp_); 323   27 impl_.insert(pos, sv.data(), sv.size(), sp_);
HITCBC 315   17 return *this; 324   17 return *this;
316   } 325   }
317   326  
318   string& 327   string&
HITCBC 319   11 string:: 328   11 string::
320   insert( 329   insert(
321   std::size_t pos, 330   std::size_t pos,
322   std::size_t count, 331   std::size_t count,
323   char ch) 332   char ch)
324   { 333   {
HITCBC 325   6 std::char_traits<char>::assign( 334   6 std::char_traits<char>::assign(
HITCBC 326   11 impl_.insert_unchecked(pos, count, sp_), 335   11 impl_.insert_unchecked(pos, count, sp_),
327   count, ch); 336   count, ch);
HITCBC 328   6 return *this; 337   6 return *this;
329   } 338   }
330   339  
331   //---------------------------------------------------------- 340   //----------------------------------------------------------
332   341  
333   string& 342   string&
HITCBC 334   19 string:: 343   19 string::
335   replace( 344   replace(
336   std::size_t pos, 345   std::size_t pos,
337   std::size_t count, 346   std::size_t count,
338   string_view sv) 347   string_view sv)
339   { 348   {
HITCBC 340   19 impl_.replace(pos, count, sv.data(), sv.size(), sp_); 349   19 impl_.replace(pos, count, sv.data(), sv.size(), sp_);
HITCBC 341   15 return *this; 350   15 return *this;
342   } 351   }
343   352  
344   string& 353   string&
HITCBC 345   11 string:: 354   11 string::
346   replace( 355   replace(
347   std::size_t pos, 356   std::size_t pos,
348   std::size_t count, 357   std::size_t count,
349   std::size_t count2, 358   std::size_t count2,
350   char ch) 359   char ch)
351   { 360   {
HITCBC 352   7 std::char_traits<char>::assign( 361   7 std::char_traits<char>::assign(
HITCBC 353   11 impl_.replace_unchecked(pos, count, count2, sp_), 362   11 impl_.replace_unchecked(pos, count, count2, sp_),
354   count2, ch); 363   count2, ch);
HITCBC 355   7 return *this; 364   7 return *this;
356   } 365   }
357   366  
358   //---------------------------------------------------------- 367   //----------------------------------------------------------
359   368  
360   string& 369   string&
HITCBC 361   10 string:: 370   10 string::
362   erase( 371   erase(
363   size_type pos, 372   size_type pos,
364   size_type count) 373   size_type count)
365   { 374   {
HITCBC 366   10 if(pos > impl_.size()) 375   10 if(pos > impl_.size())
367   { 376   {
368   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; 377   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
HITCBC 369   1 detail::throw_system_error( error::out_of_range, &loc ); 378   1 detail::throw_system_error( error::out_of_range, &loc );
370   } 379   }
HITCBC 371   9 if( count > impl_.size() - pos) 380   9 if( count > impl_.size() - pos)
HITCBC 372   4 count = impl_.size() - pos; 381   4 count = impl_.size() - pos;
HITCBC 373   9 std::char_traits<char>::move( 382   9 std::char_traits<char>::move(
HITCBC 374   9 impl_.data() + pos, 383   9 impl_.data() + pos,
HITCBC 375   9 impl_.data() + pos + count, 384   9 impl_.data() + pos + count,
HITCBC 376   9 impl_.size() - pos - count + 1); 385   9 impl_.size() - pos - count + 1);
HITCBC 377   9 impl_.term(impl_.size() - count); 386   9 impl_.term(impl_.size() - count);
HITCBC 378   9 return *this; 387   9 return *this;
379   } 388   }
380   389  
381   auto 390   auto
HITCBC 382   2 string:: 391   2 string::
383   erase(const_iterator pos) -> 392   erase(const_iterator pos) ->
384   iterator 393   iterator
385   { 394   {
HITCBC 386   2 return erase(pos, pos+1); 395   2 return erase(pos, pos+1);
387   } 396   }
388   397  
389   auto 398   auto
HITCBC 390   3 string:: 399   3 string::
391   erase( 400   erase(
392   const_iterator first, 401   const_iterator first,
393   const_iterator last) -> 402   const_iterator last) ->
394   iterator 403   iterator
395   { 404   {
HITCBC 396   3 auto const pos = first - begin(); 405   3 auto const pos = first - begin();
HITCBC 397   3 auto const count = last - first; 406   3 auto const count = last - first;
HITCBC 398   3 erase(pos, count); 407   3 erase(pos, count);
HITCBC 399   3 return data() + pos; 408   3 return data() + pos;
400   } 409   }
401   410  
402   //---------------------------------------------------------- 411   //----------------------------------------------------------
403   412  
404   void 413   void
HITCBC 405   66 string:: 414   66 string::
406   resize(size_type count, char ch) 415   resize(size_type count, char ch)
407   { 416   {
HITCBC 408   66 if(count <= impl_.size()) 417   66 if(count <= impl_.size())
409   { 418   {
HITCBC 410   25 impl_.term(count); 419   25 impl_.term(count);
HITCBC 411   25 return; 420   25 return;
412   } 421   }
413   422  
HITCBC 414   41 reserve(count); 423   41 reserve(count);
HITCBC 415   35 std::char_traits<char>::assign( 424   35 std::char_traits<char>::assign(
416   impl_.end(), 425   impl_.end(),
HITCBC 417   35 count - impl_.size(), 426   35 count - impl_.size(),
418   ch); 427   ch);
HITCBC 419   35 grow(count - size()); 428   35 grow(count - size());
420   } 429   }
421   430  
422   //---------------------------------------------------------- 431   //----------------------------------------------------------
423   432  
424   void 433   void
HITCBC 425   4 string:: 434   4 string::
426   swap(string& other) 435   swap(string& other)
427   { 436   {
HITCBC 428   4 if(*sp_ == *other.sp_) 437   4 if(*sp_ == *other.sp_)
429   { 438   {
HITCBC 430   3 std::swap(impl_, other.impl_); 439   3 std::swap(impl_, other.impl_);
HITCBC 431   3 return; 440   3 return;
432   } 441   }
433   string temp1( 442   string temp1(
HITCBC 434   1 std::move(*this), other.sp_); 443   1 std::move(*this), other.sp_);
435   string temp2( 444   string temp2(
HITCBC 436   1 std::move(other), sp_); 445   1 std::move(other), sp_);
HITCBC 437   1 this->~string(); 446   1 this->~string();
HITCBC 438   1 ::new(this) string(pilfer(temp2)); 447   1 ::new(this) string(pilfer(temp2));
HITCBC 439   1 other.~string(); 448   1 other.~string();
HITCBC 440   1 ::new(&other) string(pilfer(temp1)); 449   1 ::new(&other) string(pilfer(temp1));
HITCBC 441   1 } 450   1 }
442   451  
443   //---------------------------------------------------------- 452   //----------------------------------------------------------
444   453  
445   void 454   void
HITCBC 446   9686 string:: 455   9686 string::
447   reserve_impl(size_type new_cap) 456   reserve_impl(size_type new_cap)
448   { 457   {
HITCBC 449   9686 BOOST_ASSERT( 458   9686 BOOST_ASSERT(
450   new_cap >= impl_.capacity()); 459   new_cap >= impl_.capacity());
HITCBC 451   9686 if(new_cap > impl_.capacity()) 460   9686 if(new_cap > impl_.capacity())
452   { 461   {
453   // grow 462   // grow
HITCBC 454   9686 new_cap = detail::string_impl::growth( 463   9686 new_cap = detail::string_impl::growth(
455   new_cap, impl_.capacity()); 464   new_cap, impl_.capacity());
HITCBC 456   9685 detail::string_impl tmp(new_cap, sp_); 465   9685 detail::string_impl tmp(new_cap, sp_);
HITCBC 457   9675 std::char_traits<char>::copy(tmp.data(), 466   9675 std::char_traits<char>::copy(tmp.data(),
HITCBC 458   9675 impl_.data(), impl_.size() + 1); 467   9675 impl_.data(), impl_.size() + 1);
HITCBC 459   9675 tmp.size(impl_.size()); 468   9675 tmp.size(impl_.size());
HITCBC 460   9675 impl_.destroy(sp_); 469   9675 impl_.destroy(sp_);
HITCBC 461   9675 impl_ = tmp; 470   9675 impl_ = tmp;
HITCBC 462   9675 return; 471   9675 return;
463   } 472   }
464   } 473   }
465   474  
466   } // namespace json 475   } // namespace json
467   } // namespace boost 476   } // namespace boost
468   477  
469   //---------------------------------------------------------- 478   //----------------------------------------------------------
470   479  
471   std::size_t 480   std::size_t
HITCBC 472   3 std::hash< ::boost::json::string >::operator()( 481   3 std::hash< ::boost::json::string >::operator()(
473   ::boost::json::string const& js ) const noexcept 482   ::boost::json::string const& js ) const noexcept
474   { 483   {
HITCBC 475   3 return ::boost::hash< ::boost::json::string >()( js ); 484   3 return ::boost::hash< ::boost::json::string >()( js );
476   } 485   }
477   486  
478   #endif 487   #endif