proxygen
Conv.h
Go to the documentation of this file.
1 /*
2  * Copyright 2011-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
24 #pragma once
25 
26 #include <algorithm>
27 #include <cctype>
28 #include <climits>
29 #include <cstddef>
30 #include <limits>
31 #include <stdexcept>
32 #include <string>
33 #include <tuple>
34 #include <type_traits>
35 #include <typeinfo>
36 #include <utility>
37 
38 #include <double-conversion/double-conversion.h> // V8 JavaScript implementation
39 
40 #include <folly/Demangle.h>
41 #include <folly/Expected.h>
42 #include <folly/FBString.h>
43 #include <folly/Likely.h>
44 #include <folly/Range.h>
45 #include <folly/Traits.h>
46 #include <folly/Unit.h>
47 #include <folly/lang/Exception.h>
48 #include <folly/portability/Math.h>
49 
50 namespace folly {
51 
52 // Keep this in sync with kErrorStrings in Conv.cpp
53 enum class ConversionCode : unsigned char {
54  SUCCESS,
56  NO_DIGITS,
68  NUM_ERROR_CODES, // has to be the last entry
69 };
70 
71 struct ConversionErrorBase : std::range_error {
72  using std::range_error::range_error;
73 };
74 
76  public:
78  : ConversionErrorBase(str), code_(code) {}
79 
80  ConversionError(const char* str, ConversionCode code)
81  : ConversionErrorBase(str), code_(code) {}
82 
84  return code_;
85  }
86 
87  private:
89 };
90 
91 /*******************************************************************************
92  * Custom Error Translation
93  *
94  * Your overloaded parseTo() function can return a custom error code on failure.
95  * ::folly::to() will call makeConversionError to translate that error code into
96  * an object to throw. makeConversionError is found by argument-dependent
97  * lookup. It should have this signature:
98  *
99  * namespace other_namespace {
100  * enum YourErrorCode { BAD_ERROR, WORSE_ERROR };
101  *
102  * struct YourConversionError : ConversionErrorBase {
103  * YourConversionError(const char* what) : ConversionErrorBase(what) {}
104  * };
105  *
106  * YourConversionError
107  * makeConversionError(YourErrorCode code, ::folly::StringPiece sp) {
108  * ...
109  * return YourConversionError(messageString);
110  * }
111  ******************************************************************************/
113 
114 namespace detail {
119  for (auto c : sp) {
120  if (UNLIKELY(!std::isspace(c))) {
122  }
123  }
125 }
126 
131  auto err = enforceWhitespaceErr(sp);
132  if (err != ConversionCode::SUCCESS) {
134  }
135 }
136 } // namespace detail
137 
142 template <class Tgt, class Src>
143 typename std::enable_if<
146 tryTo(Src&& value) {
147  return std::forward<Src>(value);
148 }
149 
150 template <class Tgt, class Src>
151 typename std::enable_if<
153  Tgt>::type
154 to(Src&& value) {
155  return std::forward<Src>(value);
156 }
157 
158 /*******************************************************************************
159  * Arithmetic to boolean
160  ******************************************************************************/
161 
167 template <class Tgt, class Src>
168 typename std::enable_if<
172 tryTo(const Src& value) {
173  return value != Src();
174 }
175 
176 template <class Tgt, class Src>
177 typename std::enable_if<
179  std::is_same<Tgt, bool>::value,
180  Tgt>::type
181 to(const Src& value) {
182  return value != Src();
183 }
184 
185 /*******************************************************************************
186  * Anything to string
187  ******************************************************************************/
188 
189 namespace detail {
190 
191 #ifdef _MSC_VER
192 // MSVC can't quite figure out the LastElementImpl::call() stuff
193 // in the base implementation, so we have to use tuples instead,
194 // which result in significantly more templates being compiled,
195 // though the runtime performance is the same.
196 
197 template <typename... Ts>
198 auto getLastElement(Ts&&... ts) -> decltype(std::get<sizeof...(Ts) - 1>(
199  std::forward_as_tuple(std::forward<Ts>(ts)...))) {
200  return std::get<sizeof...(Ts) - 1>(
201  std::forward_as_tuple(std::forward<Ts>(ts)...));
202 }
203 
204 inline void getLastElement() {}
205 
206 template <size_t size, typename... Ts>
207 struct LastElementType : std::tuple_element<size - 1, std::tuple<Ts...>> {};
208 
209 template <>
210 struct LastElementType<0> {
211  using type = void;
212 };
213 
214 template <class... Ts>
215 struct LastElement
216  : std::decay<typename LastElementType<sizeof...(Ts), Ts...>::type> {};
217 #else
218 template <typename... Ts>
220  static void call(Ignored<Ts>...) {}
221 };
222 
223 template <typename Head, typename... Ts>
224 struct LastElementImpl<Head, Ts...> {
225  template <typename Last>
226  static Last call(Ignored<Ts>..., Last&& last) {
227  return std::forward<Last>(last);
228  }
229 };
230 
231 template <typename... Ts>
232 auto getLastElement(const Ts&... ts)
233  -> decltype(LastElementImpl<Ts...>::call(ts...)) {
234  return LastElementImpl<Ts...>::call(ts...);
235 }
236 
237 template <class... Ts>
238 struct LastElement : std::decay<decltype(
239  LastElementImpl<Ts...>::call(std::declval<Ts>()...))> {
240 };
241 #endif
242 
243 } // namespace detail
244 
245 /*******************************************************************************
246  * Conversions from integral types to string types.
247  ******************************************************************************/
248 
249 #if FOLLY_HAVE_INT128_T
250 namespace detail {
251 
252 template <typename IntegerType>
253 constexpr unsigned int digitsEnough() {
254  return (unsigned int)(ceil(sizeof(IntegerType) * CHAR_BIT * M_LN2 / M_LN10));
255 }
256 
257 inline size_t
258 unsafeTelescope128(char* buffer, size_t room, unsigned __int128 x) {
259  typedef unsigned __int128 Usrc;
260  size_t p = room - 1;
261 
262  while (x >= (Usrc(1) << 64)) { // Using 128-bit division while needed
263  const auto y = x / 10;
264  const auto digit = x % 10;
265 
266  buffer[p--] = static_cast<char>('0' + digit);
267  x = y;
268  }
269 
270  uint64_t xx = static_cast<uint64_t>(x); // Rest uses faster 64-bit division
271 
272  while (xx >= 10) {
273  const auto y = xx / 10ULL;
274  const auto digit = xx % 10ULL;
275 
276  buffer[p--] = static_cast<char>('0' + digit);
277  xx = y;
278  }
279 
280  buffer[p] = static_cast<char>('0' + xx);
281 
282  return p;
283 }
284 
285 } // namespace detail
286 #endif
287 
296 #ifdef __x86_64__
297 
298  // For this arch we can get a little help from specialized CPU instructions
299  // which can count leading zeroes; 64 minus that is appx. log (base 2).
300  // Use that to approximate base-10 digits (log_10) and then adjust if needed.
301 
302  // 10^i, defined for i 0 through 19.
303  // This is 20 * 8 == 160 bytes, which fits neatly into 5 cache lines
304  // (assuming a cache line size of 64).
305  alignas(64) static const uint64_t powersOf10[20] = {
306  1,
307  10,
308  100,
309  1000,
310  10000,
311  100000,
312  1000000,
313  10000000,
314  100000000,
315  1000000000,
316  10000000000,
317  100000000000,
318  1000000000000,
319  10000000000000,
320  100000000000000,
321  1000000000000000,
322  10000000000000000,
323  100000000000000000,
324  1000000000000000000,
325  10000000000000000000UL,
326  };
327 
328  // "count leading zeroes" operation not valid; for 0; special case this.
329  if (UNLIKELY(!v)) {
330  return 1;
331  }
332 
333  // bits is in the ballpark of log_2(v).
334  const uint32_t leadingZeroes = __builtin_clzll(v);
335  const auto bits = 63 - leadingZeroes;
336 
337  // approximate log_10(v) == log_10(2) * bits.
338  // Integer magic below: 77/256 is appx. 0.3010 (log_10(2)).
339  // The +1 is to make this the ceiling of the log_10 estimate.
340  const uint32_t minLength = 1 + ((bits * 77) >> 8);
341 
342  // return that log_10 lower bound, plus adjust if input >= 10^(that bound)
343  // in case there's a small error and we misjudged length.
344  return minLength + uint32_t(v >= powersOf10[minLength]);
345 
346 #else
347 
348  uint32_t result = 1;
349  while (true) {
350  if (LIKELY(v < 10)) {
351  return result;
352  }
353  if (LIKELY(v < 100)) {
354  return result + 1;
355  }
356  if (LIKELY(v < 1000)) {
357  return result + 2;
358  }
359  if (LIKELY(v < 10000)) {
360  return result + 3;
361  }
362  // Skip ahead by 4 orders of magnitude
363  v /= 10000U;
364  result += 4;
365  }
366 
367 #endif
368 }
369 
384  auto const result = digits10(v);
385  // WARNING: using size_t or pointer arithmetic for pos slows down
386  // the loop below 20x. This is because several 32-bit ops can be
387  // done in parallel, but only fewer 64-bit ones.
388  uint32_t pos = result - 1;
389  while (v >= 10) {
390  // Keep these together so a peephole optimization "sees" them and
391  // computes them in one shot.
392  auto const q = v / 10;
393  auto const r = v % 10;
394  buffer[pos--] = static_cast<char>('0' + r);
395  v = q;
396  }
397  // Last digit is trivial to handle
398  buffer[pos] = static_cast<char>(v + '0');
399  return result;
400 }
401 
405 template <class Tgt>
406 void toAppend(char value, Tgt* result) {
407  *result += value;
408 }
409 
410 template <class T>
411 constexpr typename std::enable_if<std::is_same<T, char>::value, size_t>::type
413  return 1;
414 }
415 
416 template <size_t N>
417 constexpr size_t estimateSpaceNeeded(const char (&)[N]) {
418  return N;
419 }
420 
424 template <class Tgt, class Src>
425 typename std::enable_if<
428 toAppend(Src value, Tgt* result) {
429  // Treat null pointers like an empty string, as in:
430  // operator<<(std::ostream&, const char*).
431  const char* c = value;
432  if (c) {
433  result->append(value);
434  }
435 }
436 
437 template <class Src>
439  type
441  const char* c = value;
442  if (c) {
443  return folly::StringPiece(value).size();
444  };
445  return 0;
446 }
447 
448 template <class Src>
451  return value.size();
452 }
453 
454 template <class Src>
455 typename std::enable_if<
459  size_t>::type
461  return folly::StringPiece(value).size();
462 }
463 
464 template <>
465 inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) {
466  return 0;
467 }
468 
469 template <class Src>
470 typename std::enable_if<
473  size_t>::type
475  return value->size();
476 }
477 
481 template <class Tgt, class Src>
482 typename std::enable_if<
484 toAppend(const Src& value, Tgt* result) {
485  result->append(value);
486 }
487 
491 template <class Tgt>
494  Tgt* result) {
495  result->append(value.data(), value.size());
496 }
497 
502 template <class Tgt>
504  const fbstring& value,
505  Tgt* result) {
506  result->append(value.data(), value.size());
507 }
508 
509 #if FOLLY_HAVE_INT128_T
510 
514 template <class Tgt>
515 void toAppend(__int128 value, Tgt* result) {
516  typedef unsigned __int128 Usrc;
517  char buffer[detail::digitsEnough<unsigned __int128>() + 1];
518  size_t p;
519 
520  if (value < 0) {
521  p = detail::unsafeTelescope128(buffer, sizeof(buffer), -Usrc(value));
522  buffer[--p] = '-';
523  } else {
524  p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
525  }
526 
527  result->append(buffer + p, buffer + sizeof(buffer));
528 }
529 
530 template <class Tgt>
531 void toAppend(unsigned __int128 value, Tgt* result) {
532  char buffer[detail::digitsEnough<unsigned __int128>()];
533  size_t p;
534 
535  p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
536 
537  result->append(buffer + p, buffer + sizeof(buffer));
538 }
539 
540 template <class T>
541 constexpr
544  return detail::digitsEnough<__int128>();
545 }
546 
547 template <class T>
548 constexpr typename std::
551  return detail::digitsEnough<unsigned __int128>();
552 }
553 
554 #endif
555 
564 template <class Tgt, class Src>
565 typename std::enable_if<
567  IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
568 toAppend(Src value, Tgt* result) {
569  char buffer[20];
570  if (value < 0) {
571  result->push_back('-');
572  result->append(
573  buffer,
574  uint64ToBufferUnsafe(~static_cast<uint64_t>(value) + 1, buffer));
575  } else {
576  result->append(buffer, uint64ToBufferUnsafe(uint64_t(value), buffer));
577  }
578 }
579 
580 template <class Src>
581 typename std::enable_if<
583  sizeof(Src) >= 4 && sizeof(Src) < 16,
584  size_t>::type
586  if (value < 0) {
587  // When "value" is the smallest negative, negating it would evoke
588  // undefined behavior, so, instead of writing "-value" below, we write
589  // "~static_cast<uint64_t>(value) + 1"
590  return 1 + digits10(~static_cast<uint64_t>(value) + 1);
591  }
592 
593  return digits10(static_cast<uint64_t>(value));
594 }
595 
599 template <class Tgt, class Src>
600 typename std::enable_if<
602  IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
603 toAppend(Src value, Tgt* result) {
604  char buffer[20];
605  result->append(buffer, uint64ToBufferUnsafe(value, buffer));
606 }
607 
608 template <class Src>
609 typename std::enable_if<
611  sizeof(Src) >= 4 && sizeof(Src) < 16,
612  size_t>::type
613 estimateSpaceNeeded(Src value) {
614  return digits10(value);
615 }
616 
621 template <class Tgt, class Src>
622 typename std::enable_if<
624  sizeof(Src) < 4>::type
625 toAppend(Src value, Tgt* result) {
626  typedef
628  type Intermediate;
629  toAppend<Tgt>(static_cast<Intermediate>(value), result);
630 }
631 
632 template <class Src>
633 typename std::enable_if<
634  std::is_integral<Src>::value && sizeof(Src) < 4 &&
636  size_t>::type
637 estimateSpaceNeeded(Src value) {
638  typedef
640  type Intermediate;
641  return estimateSpaceNeeded(static_cast<Intermediate>(value));
642 }
643 
647 template <class Tgt, class Src>
648 typename std::enable_if<
650 toAppend(Src value, Tgt* result) {
651  toAppend(
652  static_cast<typename std::underlying_type<Src>::type>(value), result);
653 }
654 
655 template <class Src>
657 estimateSpaceNeeded(Src value) {
658  return estimateSpaceNeeded(
659  static_cast<typename std::underlying_type<Src>::type>(value));
660 }
661 
662 /*******************************************************************************
663  * Conversions from floating-point types to string types.
664  ******************************************************************************/
665 
666 namespace detail {
667 constexpr int kConvMaxDecimalInShortestLow = -6;
668 constexpr int kConvMaxDecimalInShortestHigh = 21;
669 } // namespace detail
670 
672 template <class Tgt, class Src>
673 typename std::enable_if<
675 toAppend(
676  Src value,
677  Tgt* result,
678  double_conversion::DoubleToStringConverter::DtoaMode mode,
679  unsigned int numDigits) {
680  using namespace double_conversion;
681  DoubleToStringConverter conv(
682  DoubleToStringConverter::NO_FLAGS,
683  "Infinity",
684  "NaN",
685  'E',
686  detail::kConvMaxDecimalInShortestLow,
687  detail::kConvMaxDecimalInShortestHigh,
688  6, // max leading padding zeros
689  1); // max trailing padding zeros
690  char buffer[256];
691  StringBuilder builder(buffer, sizeof(buffer));
692  switch (mode) {
693  case DoubleToStringConverter::SHORTEST:
694  conv.ToShortest(value, &builder);
695  break;
696  case DoubleToStringConverter::SHORTEST_SINGLE:
697  conv.ToShortestSingle(static_cast<float>(value), &builder);
698  break;
699  case DoubleToStringConverter::FIXED:
700  conv.ToFixed(value, int(numDigits), &builder);
701  break;
702  default:
703  CHECK(mode == DoubleToStringConverter::PRECISION);
704  conv.ToPrecision(value, int(numDigits), &builder);
705  break;
706  }
707  const size_t length = size_t(builder.position());
708  builder.Finalize();
709  result->append(buffer, length);
710 }
711 
715 template <class Tgt, class Src>
716 typename std::enable_if<
718 toAppend(Src value, Tgt* result) {
719  toAppend(
720  value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);
721 }
722 
728 template <class Src>
730 estimateSpaceNeeded(Src value) {
731  // kBase10MaximalLength is 17. We add 1 for decimal point,
732  // e.g. 10.0/9 is 17 digits and 18 characters, including the decimal point.
733  constexpr int kMaxMantissaSpace =
734  double_conversion::DoubleToStringConverter::kBase10MaximalLength + 1;
735  // strlen("E-") + digits10(numeric_limits<double>::max_exponent10)
736  constexpr int kMaxExponentSpace = 2 + 3;
737  static const int kMaxPositiveSpace = std::max({
738  // E.g. 1.1111111111111111E-100.
739  kMaxMantissaSpace + kMaxExponentSpace,
740  // E.g. 0.000001.1111111111111111, if kConvMaxDecimalInShortestLow is -6.
741  kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow,
742  // If kConvMaxDecimalInShortestHigh is 21, then 1e21 is the smallest
743  // number > 1 which ToShortest outputs in exponential notation,
744  // so 21 is the longest non-exponential number > 1.
745  detail::kConvMaxDecimalInShortestHigh,
746  });
747  return size_t(
748  kMaxPositiveSpace +
749  (value < 0 ? 1 : 0)); // +1 for minus sign, if negative
750 }
751 
757 template <class Src>
758 struct HasLengthEstimator : std::false_type {};
759 
760 template <class Src>
761 constexpr typename std::enable_if<
763 #if FOLLY_HAVE_INT128_T
764  // On OSX 10.10, is_fundamental<__int128> is false :-O
767 #endif
772  size_t>::type
773 estimateSpaceNeeded(const Src&) {
774  return sizeof(Src) + 1; // dumbest best effort ever?
775 }
776 
777 namespace detail {
778 
779 template <class Tgt>
781 estimateSpaceToReserve(size_t sofar, Tgt*) {
782  return sofar;
783 }
784 
785 template <class T, class... Ts>
786 size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) {
787  return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...);
788 }
789 
790 template <class... Ts>
791 void reserveInTarget(const Ts&... vs) {
792  getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...));
793 }
794 
795 template <class Delimiter, class... Ts>
796 void reserveInTargetDelim(const Delimiter& d, const Ts&... vs) {
797  static_assert(sizeof...(vs) >= 2, "Needs at least 2 args");
798  size_t fordelim = (sizeof...(vs) - 2) *
799  estimateSpaceToReserve(0, d, static_cast<std::string*>(nullptr));
800  getLastElement(vs...)->reserve(estimateSpaceToReserve(fordelim, vs...));
801 }
802 
806 template <class T, class Tgt>
807 typename std::enable_if<
809 toAppendStrImpl(const T& v, Tgt result) {
810  toAppend(v, result);
811 }
812 
813 template <class T, class... Ts>
814 typename std::enable_if<
815  sizeof...(Ts) >= 2 &&
816  IsSomeString<typename std::remove_pointer<
818 toAppendStrImpl(const T& v, const Ts&... vs) {
819  toAppend(v, getLastElement(vs...));
820  toAppendStrImpl(vs...);
821 }
822 
823 template <class Delimiter, class T, class Tgt>
824 typename std::enable_if<
826 toAppendDelimStrImpl(const Delimiter& /* delim */, const T& v, Tgt result) {
827  toAppend(v, result);
828 }
829 
830 template <class Delimiter, class T, class... Ts>
831 typename std::enable_if<
832  sizeof...(Ts) >= 2 &&
833  IsSomeString<typename std::remove_pointer<
835 toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) {
836  // we are really careful here, calling toAppend with just one element does
837  // not try to estimate space needed (as we already did that). If we call
838  // toAppend(v, delim, ....) we would do unnecesary size calculation
839  toAppend(v, detail::getLastElement(vs...));
840  toAppend(delim, detail::getLastElement(vs...));
841  toAppendDelimStrImpl(delim, vs...);
842 }
843 } // namespace detail
844 
866 template <class... Ts>
867 typename std::enable_if<
868  sizeof...(Ts) >= 3 &&
869  IsSomeString<typename std::remove_pointer<
871 toAppend(const Ts&... vs) {
873 }
874 
875 #ifdef _MSC_VER
876 // Special case pid_t on MSVC, because it's a void* rather than an
877 // integral type. We can't do a global special case because this is already
878 // dangerous enough (as most pointers will implicitly convert to a void*)
879 // just doing it for MSVC.
880 template <class Tgt>
881 void toAppend(const pid_t a, Tgt* res) {
882  toAppend(uint64_t(a), res);
883 }
884 #endif
885 
895 template <class... Ts>
896 typename std::enable_if<IsSomeString<typename std::remove_pointer<
897  typename detail::LastElement<const Ts&...>::type>::type>::value>::type
898 toAppendFit(const Ts&... vs) {
899  ::folly::detail::reserveInTarget(vs...);
900  toAppend(vs...);
901 }
902 
903 template <class Ts>
904 void toAppendFit(const Ts&) {}
905 
909 template <class Tgt>
911  Tgt* /* result */) {}
912 
916 template <class Delimiter, class Tgt>
917 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim(
918  const Delimiter& /* delim */,
919  Tgt* /* result */) {}
920 
924 template <class Delimiter, class T, class Tgt>
926 toAppendDelim(const Delimiter& /* delim */, const T& v, Tgt* tgt) {
927  toAppend(v, tgt);
928 }
929 
934 template <class Delimiter, class... Ts>
935 typename std::enable_if<
936  sizeof...(Ts) >= 3 &&
937  IsSomeString<typename std::remove_pointer<
939 toAppendDelim(const Delimiter& delim, const Ts&... vs) {
940  detail::toAppendDelimStrImpl(delim, vs...);
941 }
942 
946 template <class Delimiter, class... Ts>
947 typename std::enable_if<IsSomeString<typename std::remove_pointer<
948  typename detail::LastElement<const Ts&...>::type>::type>::value>::type
949 toAppendDelimFit(const Delimiter& delim, const Ts&... vs) {
950  detail::reserveInTargetDelim(delim, vs...);
951  toAppendDelim(delim, vs...);
952 }
953 
954 template <class De, class Ts>
955 void toAppendDelimFit(const De&, const Ts&) {}
956 
961 template <class Tgt, class... Ts>
962 typename std::enable_if<
964  (sizeof...(Ts) != 1 ||
965  !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
966  value),
967  Tgt>::type
968 to(const Ts&... vs) {
969  Tgt result;
970  toAppendFit(vs..., &result);
971  return result;
972 }
973 
985 template <class Tgt, class Src>
986 typename std::enable_if<
988  Tgt>::type
989 to(Src value) {
990  Tgt result;
991  toAppend(value, &result);
992  return result;
993 }
994 
998 template <class Tgt, class Delim, class Src>
999 typename std::enable_if<
1002  Tgt>::type
1003 toDelim(const Delim& /* delim */, Src&& value) {
1004  return std::forward<Src>(value);
1005 }
1006 
1011 template <class Tgt, class Delim, class... Ts>
1012 typename std::enable_if<
1014  (sizeof...(Ts) != 1 ||
1015  !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
1016  value),
1017  Tgt>::type
1018 toDelim(const Delim& delim, const Ts&... vs) {
1019  Tgt result;
1020  toAppendDelimFit(delim, vs..., &result);
1021  return result;
1022 }
1023 
1024 /*******************************************************************************
1025  * Conversions from string types to integral types.
1026  ******************************************************************************/
1027 
1028 namespace detail {
1029 
1031 
1032 template <typename T>
1034 
1036  StringPiece* src) noexcept;
1038  StringPiece* src) noexcept;
1039 
1040 template <class Tgt>
1041 Expected<Tgt, ConversionCode> digits_to(const char* b, const char* e) noexcept;
1042 
1044  const char*,
1045  const char*) noexcept;
1047  const char*,
1048  const char*) noexcept;
1050 digits_to<unsigned char>(const char*, const char*) noexcept;
1051 
1053  const char*,
1054  const char*) noexcept;
1056 digits_to<unsigned short>(const char*, const char*) noexcept;
1057 
1059  const char*,
1060  const char*) noexcept;
1062  const char*,
1063  const char*) noexcept;
1064 
1066  const char*,
1067  const char*) noexcept;
1069 digits_to<unsigned long>(const char*, const char*) noexcept;
1070 
1072  const char*,
1073  const char*) noexcept;
1075 digits_to<unsigned long long>(const char*, const char*) noexcept;
1076 
1077 #if FOLLY_HAVE_INT128_T
1078 extern template Expected<__int128, ConversionCode> digits_to<__int128>(
1079  const char*,
1080  const char*) noexcept;
1082 digits_to<unsigned __int128>(const char*, const char*) noexcept;
1083 #endif
1084 
1085 template <class T>
1087 
1089  StringPiece* src) noexcept;
1094 
1096  StringPiece* src) noexcept;
1099 
1101  StringPiece* src) noexcept;
1104 
1106  StringPiece* src) noexcept;
1109 
1111  StringPiece* src) noexcept;
1114 
1115 #if FOLLY_HAVE_INT128_T
1116 extern template Expected<__int128, ConversionCode> str_to_integral<__int128>(
1117  StringPiece* src) noexcept;
1119 str_to_integral<unsigned __int128>(StringPiece* src) noexcept;
1120 #endif
1121 
1122 template <typename T>
1123 typename std::
1125  convertTo(StringPiece* src) noexcept {
1126  return str_to_bool(src);
1127 }
1128 
1129 template <typename T>
1130 typename std::enable_if<
1133 convertTo(StringPiece* src) noexcept {
1134  return str_to_floating<T>(src);
1135 }
1136 
1137 template <typename T>
1138 typename std::enable_if<
1141 convertTo(StringPiece* src) noexcept {
1142  return str_to_integral<T>(src);
1143 }
1144 
1145 } // namespace detail
1146 
1151 template <typename Tgt>
1152 typename std::enable_if<
1153  std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1155 tryTo(const char* b, const char* e) {
1156  return detail::digits_to<Tgt>(b, e);
1157 }
1158 
1159 template <typename Tgt>
1160 typename std::enable_if<
1161  std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1162  Tgt>::type
1163 to(const char* b, const char* e) {
1164  return tryTo<Tgt>(b, e).thenOrThrow(
1165  [](Tgt res) { return res; },
1166  [=](ConversionCode code) {
1167  return makeConversionError(code, StringPiece(b, e));
1168  });
1169 }
1170 
1171 /*******************************************************************************
1172  * Conversions from string types to arithmetic types.
1173  ******************************************************************************/
1174 
1178 template <typename Tgt>
1179 FOLLY_NODISCARD inline typename std::enable_if<
1182 parseTo(StringPiece src, Tgt& out) {
1183  return detail::convertTo<Tgt>(&src).then(
1184  [&](Tgt res) { return void(out = res), src; });
1185 }
1186 
1187 /*******************************************************************************
1188  * Integral / Floating Point to integral / Floating Point
1189  ******************************************************************************/
1190 
1191 namespace detail {
1192 
1198 template <class Tgt>
1199 typename std::enable_if<
1200  !std::is_same<Tgt, bool>::value &&
1203 convertTo(const bool& value) noexcept {
1204  return static_cast<Tgt>(value ? 1 : 0);
1205 }
1206 
1212 template <class Tgt, class Src>
1213 typename std::enable_if<
1215  !std::is_same<Tgt, bool>::value && std::is_integral<Tgt>::value,
1217 convertTo(const Src& value) noexcept {
1218  if /* constexpr */ (
1220  folly::_t<std::make_unsigned<Src>>(std::numeric_limits<Src>::max())) {
1223  }
1224  }
1225  if /* constexpr */ (
1227  (!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) {
1230  }
1231  }
1232  return static_cast<Tgt>(value);
1233 }
1234 
1240 template <class Tgt, class Src>
1241 typename std::enable_if<
1242  std::is_floating_point<Tgt>::value && std::is_floating_point<Src>::value &&
1245 convertTo(const Src& value) noexcept {
1246  if /* constexpr */ (
1248  if (value > std::numeric_limits<Tgt>::max()) {
1250  }
1251  if (value < std::numeric_limits<Tgt>::lowest()) {
1253  }
1254  }
1255  return static_cast<Tgt>(value);
1256 }
1257 
1262 template <typename Tgt, typename Src>
1263 inline typename std::enable_if<
1264  std::is_floating_point<Src>::value && std::is_integral<Tgt>::value &&
1265  !std::is_same<Tgt, bool>::value,
1266  bool>::type
1267 checkConversion(const Src& value) {
1268  constexpr Src tgtMaxAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::max());
1269  constexpr Src tgtMinAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::min());
1270  if (value >= tgtMaxAsSrc) {
1271  if (value > tgtMaxAsSrc) {
1272  return false;
1273  }
1274  const Src mmax = folly::nextafter(tgtMaxAsSrc, Src());
1275  if (static_cast<Tgt>(value - mmax) >
1276  std::numeric_limits<Tgt>::max() - static_cast<Tgt>(mmax)) {
1277  return false;
1278  }
1279  } else if (std::is_signed<Tgt>::value && value <= tgtMinAsSrc) {
1280  if (value < tgtMinAsSrc) {
1281  return false;
1282  }
1283  const Src mmin = folly::nextafter(tgtMinAsSrc, Src());
1284  if (static_cast<Tgt>(value - mmin) <
1285  std::numeric_limits<Tgt>::min() - static_cast<Tgt>(mmin)) {
1286  return false;
1287  }
1288  }
1289  return true;
1290 }
1291 
1292 // Integers can always safely be converted to floating point values
1293 template <typename Tgt, typename Src>
1294 constexpr typename std::enable_if<
1296  bool>::type
1297 checkConversion(const Src&) {
1298  return true;
1299 }
1300 
1301 // Also, floating point values can always be safely converted to bool
1302 // Per the standard, any floating point value that is not zero will yield true
1303 template <typename Tgt, typename Src>
1304 constexpr typename std::enable_if<
1305  std::is_floating_point<Src>::value && std::is_same<Tgt, bool>::value,
1306  bool>::type
1307 checkConversion(const Src&) {
1308  return true;
1309 }
1310 
1318 template <typename Tgt, typename Src>
1319 typename std::enable_if<
1320  (std::is_integral<Src>::value && std::is_floating_point<Tgt>::value) ||
1321  (std::is_floating_point<Src>::value && std::is_integral<Tgt>::value),
1323 convertTo(const Src& value) noexcept {
1324  if (LIKELY(checkConversion<Tgt>(value))) {
1325  Tgt result = static_cast<Tgt>(value);
1326  if (LIKELY(checkConversion<Src>(result))) {
1327  Src witness = static_cast<Src>(result);
1328  if (LIKELY(value == witness)) {
1329  return result;
1330  }
1331  }
1332  }
1334 }
1335 
1336 template <typename Tgt, typename Src>
1337 inline std::string errorValue(const Src& value) {
1338 #ifdef FOLLY_HAS_RTTI
1339  return to<std::string>("(", demangle(typeid(Tgt)), ") ", value);
1340 #else
1341  return to<std::string>(value);
1342 #endif
1343 }
1344 
1345 template <typename Tgt, typename Src>
1347  !std::is_same<Tgt, Src>::value && !std::is_same<Tgt, bool>::value &&
1348  std::is_arithmetic<Src>::value && std::is_arithmetic<Tgt>::value>;
1349 
1350 } // namespace detail
1351 
1352 template <typename Tgt, typename Src>
1353 typename std::enable_if<
1356 tryTo(const Src& value) noexcept {
1357  return detail::convertTo<Tgt>(value);
1358 }
1359 
1360 template <typename Tgt, typename Src>
1362  const Src& value) {
1363  return tryTo<Tgt>(value).thenOrThrow(
1364  [](Tgt res) { return res; },
1365  [&](ConversionCode e) {
1366  return makeConversionError(e, detail::errorValue<Tgt>(value));
1367  });
1368 }
1369 
1370 /*******************************************************************************
1371  * Custom Conversions
1372  *
1373  * Any type can be used with folly::to by implementing parseTo. The
1374  * implementation should be provided in the namespace of the type to facilitate
1375  * argument-dependent lookup:
1376  *
1377  * namespace other_namespace {
1378  * ::folly::Expected<::folly::StringPiece, SomeErrorCode>
1379  * parseTo(::folly::StringPiece, OtherType&) noexcept;
1380  * }
1381  ******************************************************************************/
1382 template <class T>
1383 FOLLY_NODISCARD typename std::enable_if<
1387  typename std::underlying_type<T>::type tmp{};
1388  auto restOrError = parseTo(in, tmp);
1389  out = static_cast<T>(tmp); // Harmless if parseTo fails
1390  return restOrError;
1391 }
1392 
1395  StringPiece in,
1396  StringPiece& out) noexcept {
1397  out = in;
1398  return StringPiece{in.end(), in.end()};
1399 }
1400 
1403  StringPiece in,
1404  std::string& out) {
1405  out.clear();
1406  out.append(in.data(), in.size()); // TODO try/catch?
1407  return StringPiece{in.end(), in.end()};
1408 }
1409 
1412  StringPiece in,
1413  fbstring& out) {
1414  out.clear();
1415  out.append(in.data(), in.size()); // TODO try/catch?
1416  return StringPiece{in.end(), in.end()};
1417 }
1418 
1419 namespace detail {
1420 template <typename Tgt>
1421 using ParseToResult = decltype(parseTo(StringPiece{}, std::declval<Tgt&>()));
1422 
1425  auto e = enforceWhitespaceErr(sp);
1426  if (UNLIKELY(e != ConversionCode::SUCCESS)) {
1427  return makeUnexpected(e);
1428  }
1429  return unit;
1430  }
1431 };
1432 
1433 template <class Error>
1434 struct ReturnUnit {
1435  template <class T>
1436  constexpr Expected<Unit, Error> operator()(T&&) const {
1437  return unit;
1438  }
1439 };
1440 
1441 // Older versions of the parseTo customization point threw on error and
1442 // returned void. Handle that.
1443 template <class Tgt>
1444 inline typename std::enable_if<
1445  std::is_void<ParseToResult<Tgt>>::value,
1447 parseToWrap(StringPiece sp, Tgt& out) {
1448  parseTo(sp, out);
1449  return StringPiece(sp.end(), sp.end());
1450 }
1451 
1452 template <class Tgt>
1453 inline typename std::enable_if<
1454  !std::is_void<ParseToResult<Tgt>>::value,
1456 parseToWrap(StringPiece sp, Tgt& out) {
1457  return parseTo(sp, out);
1458 }
1459 
1460 template <typename Tgt>
1461 using ParseToError = ExpectedErrorType<decltype(
1462  detail::parseToWrap(StringPiece{}, std::declval<Tgt&>()))>;
1463 
1464 } // namespace detail
1465 
1471 template <class Tgt>
1472 inline typename std::enable_if<
1476  Tgt result{};
1477  using Error = detail::ParseToError<Tgt>;
1478  using Check = typename std::conditional<
1479  std::is_arithmetic<Tgt>::value,
1482  return parseTo(src, result).then(Check(), [&](Unit) {
1483  return std::move(result);
1484  });
1485 }
1486 
1487 template <class Tgt, class Src>
1488 inline typename std::enable_if<
1490  Tgt>::type
1491 to(Src const& src) {
1492  return to<Tgt>(StringPiece(src.data(), src.size()));
1493 }
1494 
1495 template <class Tgt>
1496 inline
1499  Tgt result{};
1500  using Error = detail::ParseToError<Tgt>;
1501  using Check = typename std::conditional<
1502  std::is_arithmetic<Tgt>::value,
1505  auto tmp = detail::parseToWrap(src, result);
1506  return tmp
1507  .thenOrThrow(
1508  Check(),
1509  [&](Error e) { throw_exception(makeConversionError(e, src)); })
1510  .thenOrThrow(
1511  [&](Unit) { return std::move(result); },
1512  [&](Error e) {
1513  throw_exception(makeConversionError(e, tmp.value()));
1514  });
1515 }
1516 
1522 template <class Tgt>
1524  Tgt result;
1525  return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt {
1526  *src = sp;
1527  return std::move(result);
1528  });
1529 }
1530 
1531 template <class Tgt>
1532 Tgt to(StringPiece* src) {
1533  Tgt result{};
1534  using Error = detail::ParseToError<Tgt>;
1535  return parseTo(*src, result)
1536  .thenOrThrow(
1537  [&, src](StringPiece sp) -> Tgt {
1538  *src = sp;
1539  return std::move(result);
1540  },
1541  [=](Error e) { return makeConversionError(e, *src); });
1542 }
1543 
1544 /*******************************************************************************
1545  * Enum to anything and back
1546  ******************************************************************************/
1547 
1548 template <class Tgt, class Src>
1549 typename std::enable_if<
1553 tryTo(const Src& value) {
1554  using I = typename std::underlying_type<Src>::type;
1555  return tryTo<Tgt>(static_cast<I>(value));
1556 }
1557 
1558 template <class Tgt, class Src>
1559 typename std::enable_if<
1563 tryTo(const Src& value) {
1564  using I = typename std::underlying_type<Tgt>::type;
1565  return tryTo<I>(value).then([](I i) { return static_cast<Tgt>(i); });
1566 }
1567 
1568 template <class Tgt, class Src>
1569 typename std::enable_if<
1572  Tgt>::type
1573 to(const Src& value) {
1574  return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(value));
1575 }
1576 
1577 template <class Tgt, class Src>
1578 typename std::enable_if<
1581  Tgt>::type
1582 to(const Src& value) {
1583  return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
1584 }
1585 
1586 } // namespace folly
Definition: InvokeTest.cpp:58
size_type size() const
Definition: FBString.h:1337
std::vector< uint8_t > buffer(kBufferSize+16)
bool_constant< !std::is_same< Tgt, Src >::value &&!std::is_same< Tgt, bool >::value &&std::is_arithmetic< Src >::value &&std::is_arithmetic< Tgt >::value > IsArithToArith
Definition: Conv.h:1348
template Expected< unsigned long long, ConversionCode > digits_to< unsigned long long >(const char *, const char *) noexcept
template Expected< unsigned long, ConversionCode > digits_to< unsigned long >(const char *, const char *) noexcept
constexpr To ceil(std::chrono::duration< Rep, Period > const &d)
Definition: Chrono.h:91
template Expected< double, ConversionCode > str_to_floating< double >(StringPiece *src) noexcept
std::enable_if< std::is_void< ParseToResult< Tgt > >::value, Expected< StringPiece, ConversionCode > >::type parseToWrap(StringPiece sp, Tgt &out)
Definition: Conv.h:1447
uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer)
Definition: Conv.h:383
template Expected< unsigned long long, ConversionCode > str_to_integral< unsigned long long >(StringPiece *src) noexcept
char b
LogLevel max
Definition: LogLevel.cpp:31
template Expected< short, ConversionCode > str_to_integral< short >(StringPiece *src) noexcept
template Expected< long, ConversionCode > digits_to< long >(const char *, const char *) noexcept
#define FOLLY_NODISCARD
Definition: Portability.h:64
T convertTo(const dynamic &)
bool less_than(LHS const lhs)
Definition: Traits.h:698
template Expected< unsigned char, ConversionCode > digits_to< unsigned char >(const char *, const char *) noexcept
PskType type
uint32_t digits10(uint64_t v)
Definition: Conv.h:295
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const int x
#define LIKELY(x)
Definition: Likely.h:47
constexpr size_type size() const
Definition: Range.h:431
void enforceWhitespace(StringPiece sp)
Definition: Conv.h:130
constexpr std::enable_if< std::is_floating_point< Src >::value &&std::is_same< Tgt, bool >::value, bool >::type checkConversion(const Src &)
Definition: Conv.h:1307
constexpr std::enable_if< std::is_same< T, char >::value, size_t >::type estimateSpaceNeeded(T)
Definition: Conv.h:412
ConversionCode code_
Definition: Conv.h:88
folly::std T
bool greater_than(LHS const lhs)
Definition: Traits.h:704
FOLLY_NODISCARD std::enable_if< std::is_arithmetic< Tgt >::value, Expected< StringPiece, ConversionCode > >::type parseTo(StringPiece src, Tgt &out)
Definition: Conv.h:1182
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
template Expected< unsigned char, ConversionCode > str_to_integral< unsigned char >(StringPiece *src) noexcept
requires E e noexcept(noexcept(s.error(std::move(e))))
ConversionError(const std::string &str, ConversionCode code)
Definition: Conv.h:77
template Expected< char, ConversionCode > digits_to< char >(const char *, const char *) noexcept
ConversionCode
Definition: Conv.h:53
folly::Optional< PskKeyExchangeMode > mode
ConversionCode errorCode() const
Definition: Conv.h:83
template Expected< short, ConversionCode > digits_to< short >(const char *, const char *) noexcept
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
const value_type * data() const
Definition: FBString.h:1716
LogLevel min
Definition: LogLevel.cpp:30
std::integral_constant< bool, B > bool_constant
Definition: Traits.h:145
std::enable_if< detail::is_chrono_conversion< Tgt, Src >::value, Tgt >::type to(const Src &value)
Definition: Conv.h:677
decltype(parseTo(StringPiece{}, std::declval< Tgt & >())) ParseToResult
Definition: Conv.h:1421
typename T::type _t
Definition: Traits.h:171
constexpr Unexpected< typename std::decay< Error >::type > makeUnexpected(Error &&)
Definition: Expected.h:785
folly::std Delimiter
auto getLastElement(const Ts &...ts) -> decltype(LastElementImpl< Ts... >::call(ts...))
Definition: Conv.h:232
constexpr Iter data() const
Definition: Range.h:446
template Expected< long, ConversionCode > str_to_integral< long >(StringPiece *src) noexcept
template Expected< int, ConversionCode > str_to_integral< int >(StringPiece *src) noexcept
void reserveInTargetDelim(const Delimiter &d, const Ts &...vs)
Definition: Conv.h:796
constexpr Unit unit
Definition: Unit.h:45
char a
template Expected< int, ConversionCode > digits_to< int >(const char *, const char *) noexcept
ConversionCode enforceWhitespaceErr(StringPiece sp)
Definition: Conv.h:118
static const char *const value
Definition: Conv.cpp:50
template Expected< long long, ConversionCode > str_to_integral< long long >(StringPiece *src) noexcept
void toAppend(char value, Tgt *result)
Definition: Conv.h:406
template Expected< signed char, ConversionCode > digits_to< signed char >(const char *, const char *) noexcept
template Expected< unsigned short, ConversionCode > digits_to< unsigned short >(const char *, const char *) noexcept
constexpr Iter end() const
Definition: Range.h:455
template Expected< unsigned int, ConversionCode > str_to_integral< unsigned int >(StringPiece *src) noexcept
template Expected< unsigned short, ConversionCode > str_to_integral< unsigned short >(StringPiece *src) noexcept
template Expected< char, ConversionCode > str_to_integral< char >(StringPiece *src) noexcept
template Expected< float, ConversionCode > str_to_floating< float >(StringPiece *src) noexcept
Expected< Unit, ConversionCode > operator()(StringPiece sp) const
Definition: Conv.h:1424
Expected< Tgt, ConversionCode > digits_to(const char *b, const char *const e) noexcept
Definition: Conv.cpp:533
std::string errorValue(const Src &value)
Definition: Conv.h:1337
const char * string
Definition: Conv.cpp:212
typename std::remove_reference< Expected >::type::error_type ExpectedErrorType
Definition: Expected.h:96
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
std::enable_if< detail::is_duration< Tgt >::value, Expected< Tgt, ConversionCode > >::type tryTo(const struct timespec &ts)
Definition: Conv.h:595
Definition: InvokeTest.cpp:65
Expected< Tgt, ConversionCode > str_to_integral(StringPiece *src) noexcept
Definition: Conv.cpp:683
template Expected< unsigned int, ConversionCode > digits_to< unsigned int >(const char *, const char *) noexcept
template Expected< unsigned long, ConversionCode > str_to_integral< unsigned long >(StringPiece *src) noexcept
Expected< Tgt, ConversionCode > str_to_floating(StringPiece *src) noexcept
Definition: Conv.cpp:343
basic_fbstring & append(const basic_fbstring &str)
Definition: FBString.h:1953
Range< const char * > StringPiece
#define UNLIKELY(x)
Definition: Likely.h:48
Expected< bool, ConversionCode > str_to_bool(StringPiece *src) noexcept
Definition: Conv.cpp:266
std::enable_if< !std::is_void< ParseToResult< Tgt > >::value, ParseToResult< Tgt > >::type parseToWrap(StringPiece sp, Tgt &out)
Definition: Conv.h:1456
std::enable_if< IsSomeString< typename std::remove_pointer< Tgt >::type >::value >::type toAppendStrImpl(const T &v, Tgt result)
Definition: Conv.h:809
static void call(Ignored< Ts >...)
Definition: Conv.h:220
template Expected< signed char, ConversionCode > str_to_integral< signed char >(StringPiece *src) noexcept
PUSHMI_INLINE_VAR constexpr detail::get_fn< T > get
Definition: submit.h:391
ConversionError(const char *str, ConversionCode code)
Definition: Conv.h:80
char c
template Expected< long long, ConversionCode > digits_to< long long >(const char *, const char *) noexcept
fbstring demangle(const char *name)
Definition: Demangle.cpp:111
static Last call(Ignored< Ts >..., Last &&last)
Definition: Conv.h:226
FOLLY_NOINLINE FOLLY_COLD void throw_exception(Ex &&ex)
Definition: Exception.h:32
ConversionError makeConversionError(ConversionCode code, StringPiece input)
Definition: Conv.cpp:765
constexpr Expected< Unit, Error > operator()(T &&) const
Definition: Conv.h:1436
ExpectedErrorType< decltype(detail::parseToWrap(StringPiece{}, std::declval< Tgt & >()))> ParseToError
Definition: Conv.h:1462