1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 
17 /**
18  *
19  * This file provides a generic interface for converting objects to and from
20  * string-like types (std::string, fbstring, StringPiece), as well as
21  * range-checked conversions between numeric and enum types. The mechanisms are
22  * extensible, so that user-specified types can add folly::to support.
23  *
24  *******************************************************************************
25  * TYPE -> STRING CONVERSIONS
26  *******************************************************************************
27  * You can call the to<std::string> or to<fbstring>. These are variadic
28  * functions that convert their arguments to strings, and concatenate them to
29  * form a result. So, for example,
30  *
31  * auto str = to<std::string>(123, "456", 789);
32  *
33  * Sets str to "123456789".
34  *
35  * In addition to just concatenating the arguments, related functions can
36  * delimit them with some string: toDelim<std::string>(",", "123", 456, "789")
37  * will return the string "123,456,789".
38  *
39  * toAppend does not return a string; instead, it takes a pointer to a string as
40  * its last argument, and appends the result of the concatenation into it:
41  * std::string str = "123";
42  * toAppend(456, "789", &str); // Now str is "123456789".
43  *
44  * The toAppendFit function acts like toAppend, but it precalculates the size
45  * required to perform the append operation, and reserves that space in the
46  * output string before actually inserting its arguments. This can sometimes
47  * save on string expansion, but beware: appending to the same string many times
48  * with toAppendFit is likely a pessimization, since it will resize the string
49  * once per append.
50  *
51  * The combination of the append and delim variants also exist: toAppendDelim
52  * and toAppendDelimFit are defined, with the obvious semantics.
53  *
54  *******************************************************************************
55  * STRING -> TYPE CONVERSIONS
56  *******************************************************************************
57  * Going in the other direction, and parsing a string into a C++ type, is also
58  * supported:
59  * to<int>("123"); // Returns 123.
60  *
61  * Out of range (e.g. to<std::uint8_t>("1000")), or invalidly formatted (e.g.
62  * to<int>("four")) inputs will throw. If throw-on-error is undesirable (for
63  * instance: you're dealing with untrusted input, and want to protect yourself
64  * from users sending you down a very slow exception-throwing path), you can use
65  * tryTo<T>, which will return an Expected<T, ConversionCode>.
66  *
67  * There are overloads of to() and tryTo() that take a StringPiece*. These parse
68  * out a type from the beginning of a string, and modify the passed-in
69  * StringPiece to indicate the portion of the string not consumed.
70  *
71  *******************************************************************************
72  * NUMERIC / ENUM CONVERSIONS
73  *******************************************************************************
74  * Conv also supports a to<T>(S) overload, where T and S are numeric or enum
75  * types, that checks to see that the target type can represent its argument,
76  * and will throw if it cannot. This includes cases where a floating point ->
77  * integral conversion is attempted on a value with a non-zero fractional
78  * component, and integral -> floating point conversions that would lose
79  * precision. Enum conversions are range-checked for the underlying type of the
80  * enum, but there is no check that the input value is a valid choice of enum
81  * value.
82  *
83  *******************************************************************************
84  * CUSTOM TYPE CONVERSIONS
85  *******************************************************************************
86  * Users may customize the string conversion functionality for their own data
87  * types, . The key functions you should implement are:
88  * // Two functions to allow conversion to your type from a string.
89  * Expected<StringPiece, ConversionCode> parseTo(folly::StringPiece in,
90  *     YourType& out);
91  * YourErrorType makeConversionError(YourErrorType in, StringPiece in);
92  * // Two functions to allow conversion from your type to a string.
93  * template <class String>
94  * void toAppend(const YourType& in, String* out);
95  * size_t estimateSpaceNeeded(const YourType& in);
96  *
97  * These are documented below, inline.
98  */
99 
100 #pragma once
101 
102 #include <algorithm>
103 #include <cassert>
104 #include <cctype>
105 #include <climits>
106 #include <cstddef>
107 #include <limits>
108 #include <stdexcept>
109 #include <string>
110 #include <tuple>
111 #include <type_traits>
112 #include <utility>
113 
114 #include <double-conversion/double-conversion.h> // V8 JavaScript implementation
115 
116 #include <folly/Demangle.h>
117 #include <folly/Expected.h>
118 #include <folly/FBString.h>
119 #include <folly/Likely.h>
120 #include <folly/Portability.h>
121 #include <folly/Range.h>
122 #include <folly/Traits.h>
123 #include <folly/Unit.h>
124 #include <folly/Utility.h>
125 #include <folly/lang/Exception.h>
126 #include <folly/lang/Pretty.h>
127 #include <folly/lang/ToAscii.h>
128 #include <folly/portability/Math.h>
129 
130 namespace folly {
131 
132 // Keep this in sync with kErrorStrings in Conv.cpp
133 enum class ConversionCode : unsigned char {
134   SUCCESS,
135   EMPTY_INPUT_STRING,
136   NO_DIGITS,
137   BOOL_OVERFLOW,
138   BOOL_INVALID_VALUE,
139   NON_DIGIT_CHAR,
140   INVALID_LEADING_CHAR,
141   POSITIVE_OVERFLOW,
142   NEGATIVE_OVERFLOW,
143   STRING_TO_FLOAT_ERROR,
144   NON_WHITESPACE_AFTER_END,
145   ARITH_POSITIVE_OVERFLOW,
146   ARITH_NEGATIVE_OVERFLOW,
147   ARITH_LOSS_OF_PRECISION,
148   NUM_ERROR_CODES, // has to be the last entry
149 };
150 
151 struct ConversionErrorBase : std::range_error {
152   using std::range_error::range_error;
153 };
154 
155 class ConversionError : public ConversionErrorBase {
156  public:
ConversionError(const std::string & str,ConversionCode code)157   ConversionError(const std::string& str, ConversionCode code)
158       : ConversionErrorBase(str), code_(code) {}
159 
ConversionError(const char * str,ConversionCode code)160   ConversionError(const char* str, ConversionCode code)
161       : ConversionErrorBase(str), code_(code) {}
162 
errorCode()163   ConversionCode errorCode() const { return code_; }
164 
165  private:
166   ConversionCode code_;
167 };
168 
169 /*******************************************************************************
170  * Custom Error Translation
171  *
172  * Your overloaded parseTo() function can return a custom error code on failure.
173  * ::folly::to() will call makeConversionError to translate that error code into
174  * an object to throw. makeConversionError is found by argument-dependent
175  * lookup. It should have this signature:
176  *
177  * namespace other_namespace {
178  * enum YourErrorCode { BAD_ERROR, WORSE_ERROR };
179  *
180  * struct YourConversionError : ConversionErrorBase {
181  *   YourConversionError(const char* what) : ConversionErrorBase(what) {}
182  * };
183  *
184  * YourConversionError
185  * makeConversionError(YourErrorCode code, ::folly::StringPiece sp) {
186  *   ...
187  *   return YourConversionError(messageString);
188  * }
189  ******************************************************************************/
190 ConversionError makeConversionError(ConversionCode code, StringPiece input);
191 
192 namespace detail {
193 /**
194  * Enforce that the suffix following a number is made up only of whitespace.
195  */
enforceWhitespaceErr(StringPiece sp)196 inline ConversionCode enforceWhitespaceErr(StringPiece sp) {
197   for (auto c : sp) {
198     if (UNLIKELY(!std::isspace(c))) {
199       return ConversionCode::NON_WHITESPACE_AFTER_END;
200     }
201   }
202   return ConversionCode::SUCCESS;
203 }
204 
205 /**
206  * Keep this implementation around for prettyToDouble().
207  */
enforceWhitespace(StringPiece sp)208 inline void enforceWhitespace(StringPiece sp) {
209   auto err = enforceWhitespaceErr(sp);
210   if (err != ConversionCode::SUCCESS) {
211     throw_exception(makeConversionError(err, sp));
212   }
213 }
214 } // namespace detail
215 
216 /**
217  * The identity conversion function.
218  * tryTo<T>(T) returns itself for all types T.
219  */
220 template <class Tgt, class Src>
221 typename std::enable_if<
222     std::is_same<Tgt, typename std::decay<Src>::type>::value,
223     Expected<Tgt, ConversionCode>>::type
tryTo(Src && value)224 tryTo(Src&& value) {
225   return std::forward<Src>(value);
226 }
227 
228 template <class Tgt, class Src>
229 typename std::enable_if<
230     std::is_same<Tgt, typename std::decay<Src>::type>::value,
231     Tgt>::type
to(Src && value)232 to(Src&& value) {
233   return std::forward<Src>(value);
234 }
235 
236 /*******************************************************************************
237  * Arithmetic to boolean
238  ******************************************************************************/
239 
240 /**
241  * Unchecked conversion from arithmetic to boolean. This is different from the
242  * other arithmetic conversions because we use the C convention of treating any
243  * non-zero value as true, instead of range checking.
244  */
245 template <class Tgt, class Src>
246 typename std::enable_if<
247     is_arithmetic_v<Src> && !std::is_same<Tgt, Src>::value &&
248         std::is_same<Tgt, bool>::value,
249     Expected<Tgt, ConversionCode>>::type
tryTo(const Src & value)250 tryTo(const Src& value) {
251   return value != Src();
252 }
253 
254 template <class Tgt, class Src>
255 typename std::enable_if<
256     is_arithmetic_v<Src> && !std::is_same<Tgt, Src>::value &&
257         std::is_same<Tgt, bool>::value,
258     Tgt>::type
to(const Src & value)259 to(const Src& value) {
260   return value != Src();
261 }
262 
263 /*******************************************************************************
264  * Anything to string
265  ******************************************************************************/
266 
267 namespace detail {
268 
269 #ifdef _MSC_VER
270 // MSVC can't quite figure out the LastElementImpl::call() stuff
271 // in the base implementation, so we have to use tuples instead,
272 // which result in significantly more templates being compiled,
273 // though the runtime performance is the same.
274 
275 template <typename... Ts>
276 auto getLastElement(Ts&&... ts) -> decltype(std::get<sizeof...(Ts) - 1>(
277     std::forward_as_tuple(std::forward<Ts>(ts)...))) {
278   return std::get<sizeof...(Ts) - 1>(
279       std::forward_as_tuple(std::forward<Ts>(ts)...));
280 }
281 
getLastElement()282 inline void getLastElement() {}
283 
284 template <size_t size, typename... Ts>
285 struct LastElementType : std::tuple_element<size - 1, std::tuple<Ts...>> {};
286 
287 template <>
288 struct LastElementType<0> {
289   using type = void;
290 };
291 
292 template <class... Ts>
293 struct LastElement
294     : std::decay<typename LastElementType<sizeof...(Ts), Ts...>::type> {};
295 #else
296 template <typename... Ts>
297 struct LastElementImpl {
298   static void call(Ignored<Ts>...) {}
299 };
300 
301 template <typename Head, typename... Ts>
302 struct LastElementImpl<Head, Ts...> {
303   template <typename Last>
304   static Last call(Ignored<Ts>..., Last&& last) {
305     return std::forward<Last>(last);
306   }
307 };
308 
309 template <typename... Ts>
310 auto getLastElement(const Ts&... ts)
311     -> decltype(LastElementImpl<Ts...>::call(ts...)) {
312   return LastElementImpl<Ts...>::call(ts...);
313 }
314 
315 template <class... Ts>
316 struct LastElement : std::decay<decltype(LastElementImpl<Ts...>::call(
317                          std::declval<Ts>()...))> {};
318 #endif
319 
320 } // namespace detail
321 
322 /*******************************************************************************
323  * Conversions from integral types to string types.
324  ******************************************************************************/
325 
326 #if FOLLY_HAVE_INT128_T
327 namespace detail {
328 
329 template <typename IntegerType>
330 constexpr unsigned int digitsEnough() {
331   // digits10 returns the number of decimal digits that this type can represent,
332   // not the number of characters required for the max value, so we need to add
333   // one. ex: char digits10 returns 2, because 256-999 cannot be represented,
334   // but we need 3.
335   auto const digits10 = std::numeric_limits<IntegerType>::digits10;
336   return static_cast<unsigned int>(digits10) + 1;
337 }
338 
339 inline size_t unsafeTelescope128(
340     char* buffer, size_t room, unsigned __int128 x) {
341   typedef unsigned __int128 Usrc;
342   size_t p = room - 1;
343 
344   while (x >= (Usrc(1) << 64)) { // Using 128-bit division while needed
345     const auto y = x / 10;
346     const auto digit = x % 10;
347 
348     buffer[p--] = static_cast<char>('0' + digit);
349     x = y;
350   }
351 
352   uint64_t xx = static_cast<uint64_t>(x); // Rest uses faster 64-bit division
353 
354   while (xx >= 10) {
355     const auto y = xx / 10ULL;
356     const auto digit = xx % 10ULL;
357 
358     buffer[p--] = static_cast<char>('0' + digit);
359     xx = y;
360   }
361 
362   buffer[p] = static_cast<char>('0' + xx);
363 
364   return p;
365 }
366 
367 } // namespace detail
368 #endif
369 
370 /**
371  * A single char gets appended.
372  */
373 template <class Tgt>
374 void toAppend(char value, Tgt* result) {
375   *result += value;
376 }
377 
378 template <class T>
379 constexpr typename std::enable_if<std::is_same<T, char>::value, size_t>::type
380 estimateSpaceNeeded(T) {
381   return 1;
382 }
383 
384 template <size_t N>
385 constexpr size_t estimateSpaceNeeded(const char (&)[N]) {
386   return N;
387 }
388 
389 /**
390  * Everything implicitly convertible to const char* gets appended.
391  */
392 template <class Tgt, class Src>
393 typename std::enable_if<
394     std::is_convertible<Src, const char*>::value &&
395     IsSomeString<Tgt>::value>::type
396 toAppend(Src value, Tgt* result) {
397   // Treat null pointers like an empty string, as in:
398   // operator<<(std::ostream&, const char*).
399   const char* c = value;
400   if (c) {
401     result->append(value);
402   }
403 }
404 
405 template <class Src>
406 typename std::enable_if<std::is_convertible<Src, const char*>::value, size_t>::
407     type
408     estimateSpaceNeeded(Src value) {
409   const char* c = value;
410   if (c) {
411     return folly::StringPiece(value).size();
412   };
413   return 0;
414 }
415 
416 template <class Src>
417 typename std::enable_if<IsSomeString<Src>::value, size_t>::type
418 estimateSpaceNeeded(Src const& value) {
419   return value.size();
420 }
421 
422 template <class Src>
423 typename std::enable_if<
424     std::is_convertible<Src, folly::StringPiece>::value &&
425         !IsSomeString<Src>::value &&
426         !std::is_convertible<Src, const char*>::value,
427     size_t>::type
428 estimateSpaceNeeded(Src value) {
429   return folly::StringPiece(value).size();
430 }
431 
432 template <>
433 inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) {
434   return 0;
435 }
436 
437 template <class Src>
438 typename std::enable_if<
439     std::is_pointer<Src>::value &&
440         IsSomeString<std::remove_pointer<Src>>::value,
441     size_t>::type
442 estimateSpaceNeeded(Src value) {
443   return value->size();
444 }
445 
446 /**
447  * Strings get appended, too.
448  */
449 template <class Tgt, class Src>
450 typename std::enable_if<
451     IsSomeString<Src>::value && IsSomeString<Tgt>::value>::type
452 toAppend(const Src& value, Tgt* result) {
453   result->append(value);
454 }
455 
456 /**
457  * and StringPiece objects too
458  */
459 template <class Tgt>
460 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
461     StringPiece value, Tgt* result) {
462   result->append(value.data(), value.size());
463 }
464 
465 /**
466  * There's no implicit conversion from fbstring to other string types,
467  * so make a specialization.
468  */
469 template <class Tgt>
470 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
471     const fbstring& value, Tgt* result) {
472   result->append(value.data(), value.size());
473 }
474 
475 #if FOLLY_HAVE_INT128_T
476 /**
477  * Special handling for 128 bit integers.
478  */
479 
480 template <class Tgt>
481 void toAppend(__int128 value, Tgt* result) {
482   typedef unsigned __int128 Usrc;
483   char buffer[detail::digitsEnough<unsigned __int128>() + 1];
484   size_t p;
485 
486   if (value < 0) {
487     p = detail::unsafeTelescope128(buffer, sizeof(buffer), -Usrc(value));
488     buffer[--p] = '-';
489   } else {
490     p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
491   }
492 
493   result->append(buffer + p, buffer + sizeof(buffer));
494 }
495 
496 template <class Tgt>
497 void toAppend(unsigned __int128 value, Tgt* result) {
498   char buffer[detail::digitsEnough<unsigned __int128>()];
499   size_t p;
500 
501   p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
502 
503   result->append(buffer + p, buffer + sizeof(buffer));
504 }
505 
506 template <class T>
507 constexpr
508     typename std::enable_if<std::is_same<T, __int128>::value, size_t>::type
509     estimateSpaceNeeded(T) {
510   return detail::digitsEnough<__int128>();
511 }
512 
513 template <class T>
514 constexpr typename std::
515     enable_if<std::is_same<T, unsigned __int128>::value, size_t>::type
516     estimateSpaceNeeded(T) {
517   return detail::digitsEnough<unsigned __int128>();
518 }
519 
520 #endif
521 
522 /**
523  * int32_t and int64_t to string (by appending) go through here. The
524  * result is APPENDED to a preexisting string passed as the second
525  * parameter. This should be efficient with fbstring because fbstring
526  * incurs no dynamic allocation below 23 bytes and no number has more
527  * than 22 bytes in its textual representation (20 for digits, one for
528  * sign, one for the terminating 0).
529  */
530 template <class Tgt, class Src>
531 typename std::enable_if<
532     is_integral_v<Src> && is_signed_v<Src> && IsSomeString<Tgt>::value &&
533     sizeof(Src) >= 4>::type
534 toAppend(Src value, Tgt* result) {
535   char buffer[to_ascii_size_max_decimal<uint64_t>];
536   auto uvalue = value < 0 ? ~static_cast<uint64_t>(value) + 1
537                           : static_cast<uint64_t>(value);
538   if (value < 0) {
539     result->push_back('-');
540   }
541   result->append(buffer, to_ascii_decimal(buffer, uvalue));
542 }
543 
544 template <class Src>
545 typename std::enable_if<
546     is_integral_v<Src> && is_signed_v<Src> && sizeof(Src) >= 4 &&
547         sizeof(Src) < 16,
548     size_t>::type
549 estimateSpaceNeeded(Src value) {
550   auto uvalue = value < 0 ? ~static_cast<uint64_t>(value) + 1
551                           : static_cast<uint64_t>(value);
552   return size_t(value < 0) + to_ascii_size_decimal(uvalue);
553 }
554 
555 /**
556  * As above, but for uint32_t and uint64_t.
557  */
558 template <class Tgt, class Src>
559 typename std::enable_if<
560     is_integral_v<Src> && !is_signed_v<Src> && IsSomeString<Tgt>::value &&
561     sizeof(Src) >= 4>::type
562 toAppend(Src value, Tgt* result) {
563   char buffer[to_ascii_size_max_decimal<uint64_t>];
564   result->append(buffer, to_ascii_decimal(buffer, value));
565 }
566 
567 template <class Src>
568 typename std::enable_if<
569     is_integral_v<Src> && !is_signed_v<Src> && sizeof(Src) >= 4 &&
570         sizeof(Src) < 16,
571     size_t>::type
572 estimateSpaceNeeded(Src value) {
573   return to_ascii_size_decimal(value);
574 }
575 
576 /**
577  * All small signed and unsigned integers to string go through 32-bit
578  * types int32_t and uint32_t, respectively.
579  */
580 template <class Tgt, class Src>
581 typename std::enable_if<
582     is_integral_v<Src> && IsSomeString<Tgt>::value && sizeof(Src) < 4>::type
583 toAppend(Src value, Tgt* result) {
584   typedef typename std::conditional<is_signed_v<Src>, int64_t, uint64_t>::type
585       Intermediate;
586   toAppend<Tgt>(static_cast<Intermediate>(value), result);
587 }
588 
589 template <class Src>
590 typename std::enable_if<
591     is_integral_v<Src> && sizeof(Src) < 4 && !std::is_same<Src, char>::value,
592     size_t>::type
593 estimateSpaceNeeded(Src value) {
594   typedef typename std::conditional<is_signed_v<Src>, int64_t, uint64_t>::type
595       Intermediate;
596   return estimateSpaceNeeded(static_cast<Intermediate>(value));
597 }
598 
599 /**
600  * Enumerated values get appended as integers.
601  */
602 template <class Tgt, class Src>
603 typename std::enable_if<
604     std::is_enum<Src>::value && IsSomeString<Tgt>::value>::type
605 toAppend(Src value, Tgt* result) {
606   toAppend(to_underlying(value), result);
607 }
608 
609 template <class Src>
610 typename std::enable_if<std::is_enum<Src>::value, size_t>::type
611 estimateSpaceNeeded(Src value) {
612   return estimateSpaceNeeded(to_underlying(value));
613 }
614 
615 /*******************************************************************************
616  * Conversions from floating-point types to string types.
617  ******************************************************************************/
618 
619 namespace detail {
620 constexpr int kConvMaxDecimalInShortestLow = -6;
621 constexpr int kConvMaxDecimalInShortestHigh = 21;
622 } // namespace detail
623 
624 /** Wrapper around DoubleToStringConverter **/
625 template <class Tgt, class Src>
626 typename std::enable_if<
627     std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
628 toAppend(
629     Src value,
630     Tgt* result,
631     double_conversion::DoubleToStringConverter::DtoaMode mode,
632     unsigned int numDigits) {
633   using namespace double_conversion;
634   DoubleToStringConverter conv(
635       DoubleToStringConverter::NO_FLAGS,
636       "Infinity",
637       "NaN",
638       'E',
639       detail::kConvMaxDecimalInShortestLow,
640       detail::kConvMaxDecimalInShortestHigh,
641       6, // max leading padding zeros
642       1); // max trailing padding zeros
643   char buffer[256];
644   StringBuilder builder(buffer, sizeof(buffer));
645   FOLLY_PUSH_WARNING
646   FOLLY_CLANG_DISABLE_WARNING("-Wcovered-switch-default")
647   switch (mode) {
648     case DoubleToStringConverter::SHORTEST:
649       conv.ToShortest(value, &builder);
650       break;
651     case DoubleToStringConverter::SHORTEST_SINGLE:
652       conv.ToShortestSingle(static_cast<float>(value), &builder);
653       break;
654     case DoubleToStringConverter::FIXED:
655       conv.ToFixed(value, int(numDigits), &builder);
656       break;
657     case DoubleToStringConverter::PRECISION:
658     default:
659       assert(mode == DoubleToStringConverter::PRECISION);
660       conv.ToPrecision(value, int(numDigits), &builder);
661       break;
662   }
663   FOLLY_POP_WARNING
664   const size_t length = size_t(builder.position());
665   builder.Finalize();
666   result->append(buffer, length);
667 }
668 
669 /**
670  * As above, but for floating point
671  */
672 template <class Tgt, class Src>
673 typename std::enable_if<
674     std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
675 toAppend(Src value, Tgt* result) {
676   toAppend(
677       value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);
678 }
679 
680 /**
681  * Upper bound of the length of the output from
682  * DoubleToStringConverter::ToShortest(double, StringBuilder*),
683  * as used in toAppend(double, string*).
684  */
685 template <class Src>
686 typename std::enable_if<std::is_floating_point<Src>::value, size_t>::type
687 estimateSpaceNeeded(Src value) {
688   // kBase10MaximalLength is 17. We add 1 for decimal point,
689   // e.g. 10.0/9 is 17 digits and 18 characters, including the decimal point.
690   constexpr int kMaxMantissaSpace =
691       double_conversion::DoubleToStringConverter::kBase10MaximalLength + 1;
692   // strlen("E-") + digits10(numeric_limits<double>::max_exponent10)
693   constexpr int kMaxExponentSpace = 2 + 3;
694   static const int kMaxPositiveSpace = std::max({
695       // E.g. 1.1111111111111111E-100.
696       kMaxMantissaSpace + kMaxExponentSpace,
697       // E.g. 0.000001.1111111111111111, if kConvMaxDecimalInShortestLow is -6.
698       kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow,
699       // If kConvMaxDecimalInShortestHigh is 21, then 1e21 is the smallest
700       // number > 1 which ToShortest outputs in exponential notation,
701       // so 21 is the longest non-exponential number > 1.
702       detail::kConvMaxDecimalInShortestHigh,
703   });
704   return size_t(
705       kMaxPositiveSpace +
706       (value < 0 ? 1 : 0)); // +1 for minus sign, if negative
707 }
708 
709 /**
710  * This can be specialized, together with adding specialization
711  * for estimateSpaceNeed for your type, so that we allocate
712  * as much as you need instead of the default
713  */
714 template <class Src>
715 struct HasLengthEstimator : std::false_type {};
716 
717 template <class Src>
718 constexpr typename std::enable_if<
719     !std::is_fundamental<Src>::value &&
720 #if FOLLY_HAVE_INT128_T
721         // On OSX 10.10, is_fundamental<__int128> is false :-O
722         !std::is_same<__int128, Src>::value &&
723         !std::is_same<unsigned __int128, Src>::value &&
724 #endif
725         !IsSomeString<Src>::value &&
726         !std::is_convertible<Src, const char*>::value &&
727         !std::is_convertible<Src, StringPiece>::value &&
728         !std::is_enum<Src>::value && !HasLengthEstimator<Src>::value,
729     size_t>::type
730 estimateSpaceNeeded(const Src&) {
731   return sizeof(Src) + 1; // dumbest best effort ever?
732 }
733 
734 namespace detail {
735 
736 template <class Tgt>
737 typename std::enable_if<IsSomeString<Tgt>::value, size_t>::type
738 estimateSpaceToReserve(size_t sofar, Tgt*) {
739   return sofar;
740 }
741 
742 template <class T, class... Ts>
743 size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) {
744   return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...);
745 }
746 
747 template <class... Ts>
748 void reserveInTarget(const Ts&... vs) {
749   getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...));
750 }
751 
752 template <class Delimiter, class... Ts>
753 void reserveInTargetDelim(const Delimiter& d, const Ts&... vs) {
754   static_assert(sizeof...(vs) >= 2, "Needs at least 2 args");
755   size_t fordelim = (sizeof...(vs) - 2) *
756       estimateSpaceToReserve(0, d, static_cast<std::string*>(nullptr));
757   getLastElement(vs...)->reserve(estimateSpaceToReserve(fordelim, vs...));
758 }
759 
760 /**
761  * Variadic base case: append one element
762  */
763 template <class T, class Tgt>
764 typename std::enable_if<
765     IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
766 toAppendStrImpl(const T& v, Tgt result) {
767   toAppend(v, result);
768 }
769 
770 template <class T, class... Ts>
771 typename std::enable_if<
772     sizeof...(Ts) >= 2 &&
773     IsSomeString<typename std::remove_pointer<
774         typename detail::LastElement<const Ts&...>::type>::type>::value>::type
775 toAppendStrImpl(const T& v, const Ts&... vs) {
776   toAppend(v, getLastElement(vs...));
777   toAppendStrImpl(vs...);
778 }
779 
780 template <class Delimiter, class T, class Tgt>
781 typename std::enable_if<
782     IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
783 toAppendDelimStrImpl(const Delimiter& /* delim */, const T& v, Tgt result) {
784   toAppend(v, result);
785 }
786 
787 template <class Delimiter, class T, class... Ts>
788 typename std::enable_if<
789     sizeof...(Ts) >= 2 &&
790     IsSomeString<typename std::remove_pointer<
791         typename detail::LastElement<const Ts&...>::type>::type>::value>::type
792 toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) {
793   // we are really careful here, calling toAppend with just one element does
794   // not try to estimate space needed (as we already did that). If we call
795   // toAppend(v, delim, ....) we would do unnecessary size calculation
796   toAppend(v, detail::getLastElement(vs...));
797   toAppend(delim, detail::getLastElement(vs...));
798   toAppendDelimStrImpl(delim, vs...);
799 }
800 } // namespace detail
801 
802 /**
803  * Variadic conversion to string. Appends each element in turn.
804  * If we have two or more things to append, we will not reserve
805  * the space for them and will depend on strings exponential growth.
806  * If you just append once consider using toAppendFit which reserves
807  * the space needed (but does not have exponential as a result).
808  *
809  * Custom implementations of toAppend() can be provided in the same namespace as
810  * the type to customize printing. estimateSpaceNeed() may also be provided to
811  * avoid reallocations in toAppendFit():
812  *
813  * namespace other_namespace {
814  *
815  * template <class String>
816  * void toAppend(const OtherType&, String* out);
817  *
818  * // optional
819  * size_t estimateSpaceNeeded(const OtherType&);
820  *
821  * }
822  */
823 template <class... Ts>
824 typename std::enable_if<
825     sizeof...(Ts) >= 3 &&
826     IsSomeString<typename std::remove_pointer<
827         typename detail::LastElement<const Ts&...>::type>::type>::value>::type
828 toAppend(const Ts&... vs) {
829   ::folly::detail::toAppendStrImpl(vs...);
830 }
831 
832 #ifdef _MSC_VER
833 // Special case pid_t on MSVC, because it's a void* rather than an
834 // integral type. We can't do a global special case because this is already
835 // dangerous enough (as most pointers will implicitly convert to a void*)
836 // just doing it for MSVC.
837 template <class Tgt>
838 void toAppend(const pid_t a, Tgt* res) {
839   toAppend(uint64_t(a), res);
840 }
841 #endif
842 
843 /**
844  * Special version of the call that preallocates exactly as much memory
845  * as need for arguments to be stored in target. This means we are
846  * not doing exponential growth when we append. If you are using it
847  * in a loop you are aiming at your foot with a big perf-destroying
848  * bazooka.
849  * On the other hand if you are appending to a string once, this
850  * will probably save a few calls to malloc.
851  */
852 template <class... Ts>
853 typename std::enable_if<IsSomeString<typename std::remove_pointer<
854     typename detail::LastElement<const Ts&...>::type>::type>::value>::type
855 toAppendFit(const Ts&... vs) {
856   ::folly::detail::reserveInTarget(vs...);
857   toAppend(vs...);
858 }
859 
860 template <class Ts>
861 void toAppendFit(const Ts&) {}
862 
863 /**
864  * Variadic base case: do nothing.
865  */
866 template <class Tgt>
867 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
868     Tgt* /* result */) {}
869 
870 /**
871  * Variadic base case: do nothing.
872  */
873 template <class Delimiter, class Tgt>
874 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim(
875     const Delimiter& /* delim */, Tgt* /* result */) {}
876 
877 /**
878  * 1 element: same as toAppend.
879  */
880 template <class Delimiter, class T, class Tgt>
881 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim(
882     const Delimiter& /* delim */, const T& v, Tgt* tgt) {
883   toAppend(v, tgt);
884 }
885 
886 /**
887  * Append to string with a delimiter in between elements. Check out
888  * comments for toAppend for details about memory allocation.
889  */
890 template <class Delimiter, class... Ts>
891 typename std::enable_if<
892     sizeof...(Ts) >= 3 &&
893     IsSomeString<typename std::remove_pointer<
894         typename detail::LastElement<const Ts&...>::type>::type>::value>::type
895 toAppendDelim(const Delimiter& delim, const Ts&... vs) {
896   detail::toAppendDelimStrImpl(delim, vs...);
897 }
898 
899 /**
900  * Detail in comment for toAppendFit
901  */
902 template <class Delimiter, class... Ts>
903 typename std::enable_if<IsSomeString<typename std::remove_pointer<
904     typename detail::LastElement<const Ts&...>::type>::type>::value>::type
905 toAppendDelimFit(const Delimiter& delim, const Ts&... vs) {
906   detail::reserveInTargetDelim(delim, vs...);
907   toAppendDelim(delim, vs...);
908 }
909 
910 template <class De, class Ts>
911 void toAppendDelimFit(const De&, const Ts&) {}
912 
913 /**
914  * to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end
915  * for all types.
916  */
917 template <class Tgt, class... Ts>
918 typename std::enable_if<
919     IsSomeString<Tgt>::value &&
920         (sizeof...(Ts) != 1 ||
921          !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
922              value),
923     Tgt>::type
924 to(const Ts&... vs) {
925   Tgt result;
926   toAppendFit(vs..., &result);
927   return result;
928 }
929 
930 /**
931  * Special version of to<SomeString> for floating point. When calling
932  * folly::to<SomeString>(double), generic implementation above will
933  * firstly reserve 24 (or 25 when negative value) bytes. This will
934  * introduce a malloc call for most mainstream string implementations.
935  *
936  * But for most cases, a floating point doesn't need 24 (or 25) bytes to
937  * be converted as a string.
938  *
939  * This special version will not do string reserve.
940  */
941 template <class Tgt, class Src>
942 typename std::enable_if<
943     IsSomeString<Tgt>::value && std::is_floating_point<Src>::value,
944     Tgt>::type
945 to(Src value) {
946   Tgt result;
947   toAppend(value, &result);
948   return result;
949 }
950 
951 /**
952  * toDelim<SomeString>(SomeString str) returns itself.
953  */
954 template <class Tgt, class Delim, class Src>
955 typename std::enable_if<
956     IsSomeString<Tgt>::value &&
957         std::is_same<Tgt, typename std::decay<Src>::type>::value,
958     Tgt>::type
959 toDelim(const Delim& /* delim */, Src&& value) {
960   return std::forward<Src>(value);
961 }
962 
963 /**
964  * toDelim<SomeString>(delim, v1, v2, ...) uses toAppendDelim() as
965  * back-end for all types.
966  */
967 template <class Tgt, class Delim, class... Ts>
968 typename std::enable_if<
969     IsSomeString<Tgt>::value &&
970         (sizeof...(Ts) != 1 ||
971          !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
972              value),
973     Tgt>::type
974 toDelim(const Delim& delim, const Ts&... vs) {
975   Tgt result;
976   toAppendDelimFit(delim, vs..., &result);
977   return result;
978 }
979 
980 /*******************************************************************************
981  * Conversions from string types to integral types.
982  ******************************************************************************/
983 
984 namespace detail {
985 
986 Expected<bool, ConversionCode> str_to_bool(StringPiece* src) noexcept;
987 
988 template <typename T>
989 Expected<T, ConversionCode> str_to_floating(StringPiece* src) noexcept;
990 
991 extern template Expected<float, ConversionCode> str_to_floating<float>(
992     StringPiece* src) noexcept;
993 extern template Expected<double, ConversionCode> str_to_floating<double>(
994     StringPiece* src) noexcept;
995 
996 template <class Tgt>
997 Expected<Tgt, ConversionCode> digits_to(const char* b, const char* e) noexcept;
998 
999 extern template Expected<char, ConversionCode> digits_to<char>(
1000     const char*, const char*) noexcept;
1001 extern template Expected<signed char, ConversionCode> digits_to<signed char>(
1002     const char*, const char*) noexcept;
1003 extern template Expected<unsigned char, ConversionCode>
1004 digits_to<unsigned char>(const char*, const char*) noexcept;
1005 
1006 extern template Expected<short, ConversionCode> digits_to<short>(
1007     const char*, const char*) noexcept;
1008 extern template Expected<unsigned short, ConversionCode>
1009 digits_to<unsigned short>(const char*, const char*) noexcept;
1010 
1011 extern template Expected<int, ConversionCode> digits_to<int>(
1012     const char*, const char*) noexcept;
1013 extern template Expected<unsigned int, ConversionCode> digits_to<unsigned int>(
1014     const char*, const char*) noexcept;
1015 
1016 extern template Expected<long, ConversionCode> digits_to<long>(
1017     const char*, const char*) noexcept;
1018 extern template Expected<unsigned long, ConversionCode>
1019 digits_to<unsigned long>(const char*, const char*) noexcept;
1020 
1021 extern template Expected<long long, ConversionCode> digits_to<long long>(
1022     const char*, const char*) noexcept;
1023 extern template Expected<unsigned long long, ConversionCode>
1024 digits_to<unsigned long long>(const char*, const char*) noexcept;
1025 
1026 #if FOLLY_HAVE_INT128_T
1027 extern template Expected<__int128, ConversionCode> digits_to<__int128>(
1028     const char*, const char*) noexcept;
1029 extern template Expected<unsigned __int128, ConversionCode>
1030 digits_to<unsigned __int128>(const char*, const char*) noexcept;
1031 #endif
1032 
1033 template <class T>
1034 Expected<T, ConversionCode> str_to_integral(StringPiece* src) noexcept;
1035 
1036 extern template Expected<char, ConversionCode> str_to_integral<char>(
1037     StringPiece* src) noexcept;
1038 extern template Expected<signed char, ConversionCode>
1039 str_to_integral<signed char>(StringPiece* src) noexcept;
1040 extern template Expected<unsigned char, ConversionCode>
1041 str_to_integral<unsigned char>(StringPiece* src) noexcept;
1042 
1043 extern template Expected<short, ConversionCode> str_to_integral<short>(
1044     StringPiece* src) noexcept;
1045 extern template Expected<unsigned short, ConversionCode>
1046 str_to_integral<unsigned short>(StringPiece* src) noexcept;
1047 
1048 extern template Expected<int, ConversionCode> str_to_integral<int>(
1049     StringPiece* src) noexcept;
1050 extern template Expected<unsigned int, ConversionCode>
1051 str_to_integral<unsigned int>(StringPiece* src) noexcept;
1052 
1053 extern template Expected<long, ConversionCode> str_to_integral<long>(
1054     StringPiece* src) noexcept;
1055 extern template Expected<unsigned long, ConversionCode>
1056 str_to_integral<unsigned long>(StringPiece* src) noexcept;
1057 
1058 extern template Expected<long long, ConversionCode> str_to_integral<long long>(
1059     StringPiece* src) noexcept;
1060 extern template Expected<unsigned long long, ConversionCode>
1061 str_to_integral<unsigned long long>(StringPiece* src) noexcept;
1062 
1063 #if FOLLY_HAVE_INT128_T
1064 extern template Expected<__int128, ConversionCode> str_to_integral<__int128>(
1065     StringPiece* src) noexcept;
1066 extern template Expected<unsigned __int128, ConversionCode>
1067 str_to_integral<unsigned __int128>(StringPiece* src) noexcept;
1068 #endif
1069 
1070 template <typename T>
1071 typename std::
1072     enable_if<std::is_same<T, bool>::value, Expected<T, ConversionCode>>::type
1073     convertTo(StringPiece* src) noexcept {
1074   return str_to_bool(src);
1075 }
1076 
1077 template <typename T>
1078 typename std::enable_if<
1079     std::is_floating_point<T>::value,
1080     Expected<T, ConversionCode>>::type
1081 convertTo(StringPiece* src) noexcept {
1082   return str_to_floating<T>(src);
1083 }
1084 
1085 template <typename T>
1086 typename std::enable_if<
1087     is_integral_v<T> && !std::is_same<T, bool>::value,
1088     Expected<T, ConversionCode>>::type
1089 convertTo(StringPiece* src) noexcept {
1090   return str_to_integral<T>(src);
1091 }
1092 
1093 } // namespace detail
1094 
1095 /**
1096  * String represented as a pair of pointers to char to unsigned
1097  * integrals. Assumes NO whitespace before or after.
1098  */
1099 template <typename Tgt>
1100 typename std::enable_if<
1101     is_integral_v<Tgt> && !std::is_same<Tgt, bool>::value,
1102     Expected<Tgt, ConversionCode>>::type
1103 tryTo(const char* b, const char* e) {
1104   return detail::digits_to<Tgt>(b, e);
1105 }
1106 
1107 template <typename Tgt>
1108 typename std::enable_if< //
1109     is_integral_v<Tgt> && !std::is_same<Tgt, bool>::value,
1110     Tgt>::type
1111 to(const char* b, const char* e) {
1112   return tryTo<Tgt>(b, e).thenOrThrow(
1113       [](Tgt res) { return res; },
1114       [=](ConversionCode code) {
1115         return makeConversionError(code, StringPiece(b, e));
1116       });
1117 }
1118 
1119 /*******************************************************************************
1120  * Conversions from string types to arithmetic types.
1121  ******************************************************************************/
1122 
1123 /**
1124  * Parsing strings to numeric types.
1125  */
1126 template <typename Tgt>
1127 FOLLY_NODISCARD inline typename std::enable_if< //
1128     is_arithmetic_v<Tgt>,
1129     Expected<StringPiece, ConversionCode>>::type
1130 parseTo(StringPiece src, Tgt& out) {
1131   return detail::convertTo<Tgt>(&src).then(
1132       [&](Tgt res) { return void(out = res), src; });
1133 }
1134 
1135 /*******************************************************************************
1136  * Integral / Floating Point to integral / Floating Point
1137  ******************************************************************************/
1138 
1139 namespace detail {
1140 
1141 /**
1142  * Bool to integral/float doesn't need any special checks, and this
1143  * overload means we aren't trying to see if a bool is less than
1144  * an integer.
1145  */
1146 template <class Tgt>
1147 typename std::enable_if<
1148     !std::is_same<Tgt, bool>::value &&
1149         (is_integral_v<Tgt> || std::is_floating_point<Tgt>::value),
1150     Expected<Tgt, ConversionCode>>::type
1151 convertTo(const bool& value) noexcept {
1152   return static_cast<Tgt>(value ? 1 : 0);
1153 }
1154 
1155 /**
1156  * Checked conversion from integral to integral. The checks are only
1157  * performed when meaningful, e.g. conversion from int to long goes
1158  * unchecked.
1159  */
1160 template <class Tgt, class Src>
1161 typename std::enable_if<
1162     is_integral_v<Src> && !std::is_same<Tgt, Src>::value &&
1163         !std::is_same<Tgt, bool>::value && is_integral_v<Tgt>,
1164     Expected<Tgt, ConversionCode>>::type
1165 convertTo(const Src& value) noexcept {
1166   if /* constexpr */ (
1167       make_unsigned_t<Tgt>(std::numeric_limits<Tgt>::max()) <
1168       make_unsigned_t<Src>(std::numeric_limits<Src>::max())) {
1169     if (greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)) {
1170       return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1171     }
1172   }
1173   if /* constexpr */ (
1174       is_signed_v<Src> && (!is_signed_v<Tgt> || sizeof(Src) > sizeof(Tgt))) {
1175     if (less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)) {
1176       return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1177     }
1178   }
1179   return static_cast<Tgt>(value);
1180 }
1181 
1182 /**
1183  * Checked conversion from floating to floating. The checks are only
1184  * performed when meaningful, e.g. conversion from float to double goes
1185  * unchecked.
1186  */
1187 template <class Tgt, class Src>
1188 typename std::enable_if<
1189     std::is_floating_point<Tgt>::value && std::is_floating_point<Src>::value &&
1190         !std::is_same<Tgt, Src>::value,
1191     Expected<Tgt, ConversionCode>>::type
1192 convertTo(const Src& value) noexcept {
1193   if /* constexpr */ (
1194       std::numeric_limits<Tgt>::max() < std::numeric_limits<Src>::max()) {
1195     if (value > std::numeric_limits<Tgt>::max()) {
1196       return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1197     }
1198     if (value < std::numeric_limits<Tgt>::lowest()) {
1199       return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1200     }
1201   }
1202   return static_cast<Tgt>(value);
1203 }
1204 
1205 /**
1206  * Check if a floating point value can safely be converted to an
1207  * integer value without triggering undefined behaviour.
1208  */
1209 template <typename Tgt, typename Src>
1210 inline typename std::enable_if<
1211     std::is_floating_point<Src>::value && is_integral_v<Tgt> &&
1212         !std::is_same<Tgt, bool>::value,
1213     bool>::type
1214 checkConversion(const Src& value) {
1215   constexpr Src tgtMaxAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::max());
1216   constexpr Src tgtMinAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::min());
1217   if (value >= tgtMaxAsSrc) {
1218     if (value > tgtMaxAsSrc) {
1219       return false;
1220     }
1221     const Src mmax = folly::nextafter(tgtMaxAsSrc, Src());
1222     if (static_cast<Tgt>(value - mmax) >
1223         std::numeric_limits<Tgt>::max() - static_cast<Tgt>(mmax)) {
1224       return false;
1225     }
1226   } else if (is_signed_v<Tgt> && value <= tgtMinAsSrc) {
1227     if (value < tgtMinAsSrc) {
1228       return false;
1229     }
1230     const Src mmin = folly::nextafter(tgtMinAsSrc, Src());
1231     if (static_cast<Tgt>(value - mmin) <
1232         std::numeric_limits<Tgt>::min() - static_cast<Tgt>(mmin)) {
1233       return false;
1234     }
1235   }
1236   return true;
1237 }
1238 
1239 // Integers can always safely be converted to floating point values
1240 template <typename Tgt, typename Src>
1241 constexpr typename std::enable_if<
1242     is_integral_v<Src> && std::is_floating_point<Tgt>::value,
1243     bool>::type
1244 checkConversion(const Src&) {
1245   return true;
1246 }
1247 
1248 // Also, floating point values can always be safely converted to bool
1249 // Per the standard, any floating point value that is not zero will yield true
1250 template <typename Tgt, typename Src>
1251 constexpr typename std::enable_if<
1252     std::is_floating_point<Src>::value && std::is_same<Tgt, bool>::value,
1253     bool>::type
1254 checkConversion(const Src&) {
1255   return true;
1256 }
1257 
1258 /**
1259  * Checked conversion from integral to floating point and back. The
1260  * result must be convertible back to the source type without loss of
1261  * precision. This seems Draconian but sometimes is what's needed, and
1262  * complements existing routines nicely. For various rounding
1263  * routines, see <math>.
1264  */
1265 template <typename Tgt, typename Src>
1266 typename std::enable_if<
1267     (is_integral_v<Src> && std::is_floating_point<Tgt>::value) ||
1268         (std::is_floating_point<Src>::value && is_integral_v<Tgt>),
1269     Expected<Tgt, ConversionCode>>::type
1270 convertTo(const Src& value) noexcept {
1271   if (LIKELY(checkConversion<Tgt>(value))) {
1272     Tgt result = static_cast<Tgt>(value);
1273     if (LIKELY(checkConversion<Src>(result))) {
1274       Src witness = static_cast<Src>(result);
1275       if (LIKELY(value == witness)) {
1276         return result;
1277       }
1278     }
1279   }
1280   return makeUnexpected(ConversionCode::ARITH_LOSS_OF_PRECISION);
1281 }
1282 
1283 template <typename Tgt, typename Src>
1284 inline std::string errorValue(const Src& value) {
1285   return to<std::string>("(", pretty_name<Tgt>(), ") ", value);
1286 }
1287 
1288 template <typename Tgt, typename Src>
1289 using IsArithToArith = bool_constant<
1290     !std::is_same<Tgt, Src>::value && !std::is_same<Tgt, bool>::value &&
1291     is_arithmetic_v<Src> && is_arithmetic_v<Tgt>>;
1292 
1293 } // namespace detail
1294 
1295 template <typename Tgt, typename Src>
1296 typename std::enable_if<
1297     detail::IsArithToArith<Tgt, Src>::value,
1298     Expected<Tgt, ConversionCode>>::type
1299 tryTo(const Src& value) noexcept {
1300   return detail::convertTo<Tgt>(value);
1301 }
1302 
1303 template <typename Tgt, typename Src>
1304 typename std::enable_if<detail::IsArithToArith<Tgt, Src>::value, Tgt>::type to(
1305     const Src& value) {
1306   return tryTo<Tgt>(value).thenOrThrow(
1307       [](Tgt res) { return res; },
1308       [&](ConversionCode e) {
1309         return makeConversionError(e, detail::errorValue<Tgt>(value));
1310       });
1311 }
1312 
1313 /*******************************************************************************
1314  * Custom Conversions
1315  *
1316  * Any type can be used with folly::to by implementing parseTo. The
1317  * implementation should be provided in the namespace of the type to facilitate
1318  * argument-dependent lookup:
1319  *
1320  * namespace other_namespace {
1321  * ::folly::Expected<::folly::StringPiece, SomeErrorCode>
1322  *   parseTo(::folly::StringPiece, OtherType&) noexcept;
1323  * }
1324  ******************************************************************************/
1325 template <class T>
1326 FOLLY_NODISCARD typename std::enable_if<
1327     std::is_enum<T>::value,
1328     Expected<StringPiece, ConversionCode>>::type
1329 parseTo(StringPiece in, T& out) noexcept {
1330   typename std::underlying_type<T>::type tmp{};
1331   auto restOrError = parseTo(in, tmp);
1332   out = static_cast<T>(tmp); // Harmless if parseTo fails
1333   return restOrError;
1334 }
1335 
1336 FOLLY_NODISCARD
1337 inline Expected<StringPiece, ConversionCode> parseTo(
1338     StringPiece in, StringPiece& out) noexcept {
1339   out = in;
1340   return StringPiece{in.end(), in.end()};
1341 }
1342 
1343 namespace detail {
1344 
1345 template <class Str>
1346 FOLLY_ERASE Expected<StringPiece, ConversionCode> parseToStr(
1347     StringPiece in, Str& out) {
1348   out.clear();
1349   out.append(in.data(), in.size()); // TODO try/catch?
1350   return StringPiece{in.end(), in.end()};
1351 }
1352 
1353 } // namespace detail
1354 
1355 FOLLY_NODISCARD
1356 inline Expected<StringPiece, ConversionCode> parseTo(
1357     StringPiece in, std::string& out) {
1358   return detail::parseToStr(in, out);
1359 }
1360 
1361 #if FOLLY_HAS_STRING_VIEW
1362 FOLLY_NODISCARD
1363 inline Expected<StringPiece, ConversionCode> parseTo(
1364     StringPiece in, std::string_view& out) {
1365   out = std::string_view(in.data(), in.size());
1366   return StringPiece{in.end(), in.end()};
1367 }
1368 #endif
1369 
1370 FOLLY_NODISCARD
1371 inline Expected<StringPiece, ConversionCode> parseTo(
1372     StringPiece in, fbstring& out) {
1373   return detail::parseToStr(in, out);
1374 }
1375 
1376 template <class Str>
1377 FOLLY_NODISCARD inline typename std::enable_if<
1378     IsSomeString<Str>::value,
1379     Expected<StringPiece, ConversionCode>>::type
1380 parseTo(StringPiece in, Str& out) {
1381   return detail::parseToStr(in, out);
1382 }
1383 
1384 namespace detail {
1385 template <typename Tgt>
1386 using ParseToResult = decltype(parseTo(StringPiece{}, std::declval<Tgt&>()));
1387 
1388 struct CheckTrailingSpace {
1389   Expected<Unit, ConversionCode> operator()(StringPiece sp) const {
1390     auto e = enforceWhitespaceErr(sp);
1391     if (UNLIKELY(e != ConversionCode::SUCCESS)) {
1392       return makeUnexpected(e);
1393     }
1394     return unit;
1395   }
1396 };
1397 
1398 template <class Error>
1399 struct ReturnUnit {
1400   template <class T>
1401   constexpr Expected<Unit, Error> operator()(T&&) const {
1402     return unit;
1403   }
1404 };
1405 
1406 // Older versions of the parseTo customization point threw on error and
1407 // returned void. Handle that.
1408 template <class Tgt>
1409 inline typename std::enable_if<
1410     std::is_void<ParseToResult<Tgt>>::value,
1411     Expected<StringPiece, ConversionCode>>::type
1412 parseToWrap(StringPiece sp, Tgt& out) {
1413   parseTo(sp, out);
1414   return StringPiece(sp.end(), sp.end());
1415 }
1416 
1417 template <class Tgt>
1418 inline typename std::enable_if<
1419     !std::is_void<ParseToResult<Tgt>>::value,
1420     ParseToResult<Tgt>>::type
1421 parseToWrap(StringPiece sp, Tgt& out) {
1422   return parseTo(sp, out);
1423 }
1424 
1425 template <typename Tgt>
1426 using ParseToError = ExpectedErrorType<decltype(detail::parseToWrap(
1427     StringPiece{}, std::declval<Tgt&>()))>;
1428 
1429 } // namespace detail
1430 
1431 /**
1432  * String or StringPiece to target conversion. Accepts leading and trailing
1433  * whitespace, but no non-space trailing characters.
1434  */
1435 
1436 template <class Tgt>
1437 inline typename std::enable_if<
1438     !std::is_same<StringPiece, Tgt>::value,
1439     Expected<Tgt, detail::ParseToError<Tgt>>>::type
1440 tryTo(StringPiece src) {
1441   Tgt result{};
1442   using Error = detail::ParseToError<Tgt>;
1443   using Check = typename std::conditional<
1444       is_arithmetic_v<Tgt>,
1445       detail::CheckTrailingSpace,
1446       detail::ReturnUnit<Error>>::type;
1447   return parseTo(src, result).then(Check(), [&](Unit) {
1448     return std::move(result);
1449   });
1450 }
1451 
1452 template <class Tgt, class Src>
1453 inline typename std::enable_if<
1454     IsSomeString<Src>::value && !std::is_same<StringPiece, Tgt>::value,
1455     Tgt>::type
1456 to(Src const& src) {
1457   return to<Tgt>(StringPiece(src.data(), src.size()));
1458 }
1459 
1460 template <class Tgt>
1461 inline
1462     typename std::enable_if<!std::is_same<StringPiece, Tgt>::value, Tgt>::type
1463     to(StringPiece src) {
1464   Tgt result{};
1465   using Error = detail::ParseToError<Tgt>;
1466   using Check = typename std::conditional<
1467       is_arithmetic_v<Tgt>,
1468       detail::CheckTrailingSpace,
1469       detail::ReturnUnit<Error>>::type;
1470   auto tmp = detail::parseToWrap(src, result);
1471   return tmp
1472       .thenOrThrow(
1473           Check(),
1474           [&](Error e) { throw_exception(makeConversionError(e, src)); })
1475       .thenOrThrow(
1476           [&](Unit) { return std::move(result); },
1477           [&](Error e) {
1478             throw_exception(makeConversionError(e, tmp.value()));
1479           });
1480 }
1481 
1482 /**
1483  * tryTo/to that take the strings by pointer so the caller gets information
1484  * about how much of the string was consumed by the conversion. These do not
1485  * check for trailing whitespace.
1486  */
1487 template <class Tgt>
1488 Expected<Tgt, detail::ParseToError<Tgt>> tryTo(StringPiece* src) {
1489   Tgt result;
1490   return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt {
1491     *src = sp;
1492     return std::move(result);
1493   });
1494 }
1495 
1496 template <class Tgt>
1497 Tgt to(StringPiece* src) {
1498   Tgt result{};
1499   using Error = detail::ParseToError<Tgt>;
1500   return parseTo(*src, result)
1501       .thenOrThrow(
1502           [&, src](StringPiece sp) -> Tgt {
1503             *src = sp;
1504             return std::move(result);
1505           },
1506           [=](Error e) { return makeConversionError(e, *src); });
1507 }
1508 
1509 /*******************************************************************************
1510  * Enum to anything and back
1511  ******************************************************************************/
1512 
1513 template <class Tgt, class Src>
1514 typename std::enable_if<
1515     std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1516         !std::is_convertible<Tgt, StringPiece>::value,
1517     Expected<Tgt, ConversionCode>>::type
1518 tryTo(const Src& value) {
1519   return tryTo<Tgt>(to_underlying(value));
1520 }
1521 
1522 template <class Tgt, class Src>
1523 typename std::enable_if<
1524     !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1525         !std::is_same<Src, Tgt>::value,
1526     Expected<Tgt, ConversionCode>>::type
1527 tryTo(const Src& value) {
1528   using I = typename std::underlying_type<Tgt>::type;
1529   return tryTo<I>(value).then([](I i) { return static_cast<Tgt>(i); });
1530 }
1531 
1532 template <class Tgt, class Src>
1533 typename std::enable_if<
1534     std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1535         !std::is_convertible<Tgt, StringPiece>::value,
1536     Tgt>::type
1537 to(const Src& value) {
1538   return to<Tgt>(to_underlying(value));
1539 }
1540 
1541 template <class Tgt, class Src>
1542 typename std::enable_if<
1543     !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1544         !std::is_same<Src, Tgt>::value,
1545     Tgt>::type
1546 to(const Src& value) {
1547   return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
1548 }
1549 
1550 } // namespace folly
1551