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
17/**
18 * Converts anything to anything, with an emphasis on performance and
19 * safety.
20 *
21 * @author Andrei Alexandrescu (andrei.alexandrescu@fb.com)
22 */
23
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
50namespace folly {
51
52// Keep this in sync with kErrorStrings in Conv.cpp
53enum class ConversionCode : unsigned char {
54 SUCCESS,
55 EMPTY_INPUT_STRING,
56 NO_DIGITS,
57 BOOL_OVERFLOW,
58 BOOL_INVALID_VALUE,
59 NON_DIGIT_CHAR,
60 INVALID_LEADING_CHAR,
61 POSITIVE_OVERFLOW,
62 NEGATIVE_OVERFLOW,
63 STRING_TO_FLOAT_ERROR,
64 NON_WHITESPACE_AFTER_END,
65 ARITH_POSITIVE_OVERFLOW,
66 ARITH_NEGATIVE_OVERFLOW,
67 ARITH_LOSS_OF_PRECISION,
68 NUM_ERROR_CODES, // has to be the last entry
69};
70
71struct ConversionErrorBase : std::range_error {
72 using std::range_error::range_error;
73};
74
75class ConversionError : public ConversionErrorBase {
76 public:
77 ConversionError(const std::string& str, ConversionCode code)
78 : ConversionErrorBase(str), code_(code) {}
79
80 ConversionError(const char* str, ConversionCode code)
81 : ConversionErrorBase(str), code_(code) {}
82
83 ConversionCode errorCode() const {
84 return code_;
85 }
86
87 private:
88 ConversionCode code_;
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 ******************************************************************************/
112ConversionError makeConversionError(ConversionCode code, StringPiece sp);
113
114namespace detail {
115/**
116 * Enforce that the suffix following a number is made up only of whitespace.
117 */
118inline ConversionCode enforceWhitespaceErr(StringPiece sp) {
119 for (auto c : sp) {
120 if (UNLIKELY(!std::isspace(c))) {
121 return ConversionCode::NON_WHITESPACE_AFTER_END;
122 }
123 }
124 return ConversionCode::SUCCESS;
125}
126
127/**
128 * Keep this implementation around for prettyToDouble().
129 */
130inline void enforceWhitespace(StringPiece sp) {
131 auto err = enforceWhitespaceErr(sp);
132 if (err != ConversionCode::SUCCESS) {
133 throw_exception(makeConversionError(err, sp));
134 }
135}
136} // namespace detail
137
138/**
139 * The identity conversion function.
140 * tryTo<T>(T) returns itself for all types T.
141 */
142template <class Tgt, class Src>
143typename std::enable_if<
144 std::is_same<Tgt, typename std::decay<Src>::type>::value,
145 Expected<Tgt, ConversionCode>>::type
146tryTo(Src&& value) {
147 return std::forward<Src>(value);
148}
149
150template <class Tgt, class Src>
151typename std::enable_if<
152 std::is_same<Tgt, typename std::decay<Src>::type>::value,
153 Tgt>::type
154to(Src&& value) {
155 return std::forward<Src>(value);
156}
157
158/*******************************************************************************
159 * Arithmetic to boolean
160 ******************************************************************************/
161
162/**
163 * Unchecked conversion from arithmetic to boolean. This is different from the
164 * other arithmetic conversions because we use the C convention of treating any
165 * non-zero value as true, instead of range checking.
166 */
167template <class Tgt, class Src>
168typename std::enable_if<
169 std::is_arithmetic<Src>::value && !std::is_same<Tgt, Src>::value &&
170 std::is_same<Tgt, bool>::value,
171 Expected<Tgt, ConversionCode>>::type
172tryTo(const Src& value) {
173 return value != Src();
174}
175
176template <class Tgt, class Src>
177typename std::enable_if<
178 std::is_arithmetic<Src>::value && !std::is_same<Tgt, Src>::value &&
179 std::is_same<Tgt, bool>::value,
180 Tgt>::type
181to(const Src& value) {
182 return value != Src();
183}
184
185/*******************************************************************************
186 * Anything to string
187 ******************************************************************************/
188
189namespace 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
197template <typename... Ts>
198auto 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
204inline void getLastElement() {}
205
206template <size_t size, typename... Ts>
207struct LastElementType : std::tuple_element<size - 1, std::tuple<Ts...>> {};
208
209template <>
210struct LastElementType<0> {
211 using type = void;
212};
213
214template <class... Ts>
215struct LastElement
216 : std::decay<typename LastElementType<sizeof...(Ts), Ts...>::type> {};
217#else
218template <typename... Ts>
219struct LastElementImpl {
220 static void call(Ignored<Ts>...) {}
221};
222
223template <typename Head, typename... Ts>
224struct LastElementImpl<Head, Ts...> {
225 template <typename Last>
226 static Last call(Ignored<Ts>..., Last&& last) {
227 return std::forward<Last>(last);
228 }
229};
230
231template <typename... Ts>
232auto getLastElement(const Ts&... ts)
233 -> decltype(LastElementImpl<Ts...>::call(ts...)) {
234 return LastElementImpl<Ts...>::call(ts...);
235}
236
237template <class... Ts>
238struct 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
250namespace detail {
251
252template <typename IntegerType>
253constexpr unsigned int digitsEnough() {
254 return (unsigned int)(ceil(sizeof(IntegerType) * CHAR_BIT * M_LN2 / M_LN10));
255}
256
257inline size_t
258unsafeTelescope128(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
288/**
289 * Returns the number of digits in the base 10 representation of an
290 * uint64_t. Useful for preallocating buffers and such. It's also used
291 * internally, see below. Measurements suggest that defining a
292 * separate overload for 32-bit integers is not worthwhile.
293 */
294
295inline uint32_t digits10(uint64_t v) {
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
370/**
371 * Copies the ASCII base 10 representation of v into buffer and
372 * returns the number of bytes written. Does NOT append a \0. Assumes
373 * the buffer points to digits10(v) bytes of valid memory. Note that
374 * uint64 needs at most 20 bytes, uint32_t needs at most 10 bytes,
375 * uint16_t needs at most 5 bytes, and so on. Measurements suggest
376 * that defining a separate overload for 32-bit integers is not
377 * worthwhile.
378 *
379 * This primitive is unsafe because it makes the size assumption and
380 * because it does not add a terminating \0.
381 */
382
383inline uint32_t uint64ToBufferUnsafe(uint64_t v, char* const buffer) {
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
402/**
403 * A single char gets appended.
404 */
405template <class Tgt>
406void toAppend(char value, Tgt* result) {
407 *result += value;
408}
409
410template <class T>
411constexpr typename std::enable_if<std::is_same<T, char>::value, size_t>::type
412estimateSpaceNeeded(T) {
413 return 1;
414}
415
416template <size_t N>
417constexpr size_t estimateSpaceNeeded(const char (&)[N]) {
418 return N;
419}
420
421/**
422 * Everything implicitly convertible to const char* gets appended.
423 */
424template <class Tgt, class Src>
425typename std::enable_if<
426 std::is_convertible<Src, const char*>::value &&
427 IsSomeString<Tgt>::value>::type
428toAppend(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
437template <class Src>
438typename std::enable_if<std::is_convertible<Src, const char*>::value, size_t>::
439 type
440 estimateSpaceNeeded(Src value) {
441 const char* c = value;
442 if (c) {
443 return folly::StringPiece(value).size();
444 };
445 return 0;
446}
447
448template <class Src>
449typename std::enable_if<IsSomeString<Src>::value, size_t>::type
450estimateSpaceNeeded(Src const& value) {
451 return value.size();
452}
453
454template <class Src>
455typename std::enable_if<
456 std::is_convertible<Src, folly::StringPiece>::value &&
457 !IsSomeString<Src>::value &&
458 !std::is_convertible<Src, const char*>::value,
459 size_t>::type
460estimateSpaceNeeded(Src value) {
461 return folly::StringPiece(value).size();
462}
463
464template <>
465inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) {
466 return 0;
467}
468
469template <class Src>
470typename std::enable_if<
471 std::is_pointer<Src>::value &&
472 IsSomeString<std::remove_pointer<Src>>::value,
473 size_t>::type
474estimateSpaceNeeded(Src value) {
475 return value->size();
476}
477
478/**
479 * Strings get appended, too.
480 */
481template <class Tgt, class Src>
482typename std::enable_if<
483 IsSomeString<Src>::value && IsSomeString<Tgt>::value>::type
484toAppend(const Src& value, Tgt* result) {
485 result->append(value);
486}
487
488/**
489 * and StringPiece objects too
490 */
491template <class Tgt>
492typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
493 StringPiece value,
494 Tgt* result) {
495 result->append(value.data(), value.size());
496}
497
498/**
499 * There's no implicit conversion from fbstring to other string types,
500 * so make a specialization.
501 */
502template <class Tgt>
503typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
504 const fbstring& value,
505 Tgt* result) {
506 result->append(value.data(), value.size());
507}
508
509#if FOLLY_HAVE_INT128_T
510/**
511 * Special handling for 128 bit integers.
512 */
513
514template <class Tgt>
515void 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
530template <class Tgt>
531void 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
540template <class T>
541constexpr
542 typename std::enable_if<std::is_same<T, __int128>::value, size_t>::type
543 estimateSpaceNeeded(T) {
544 return detail::digitsEnough<__int128>();
545}
546
547template <class T>
548constexpr typename std::
549 enable_if<std::is_same<T, unsigned __int128>::value, size_t>::type
550 estimateSpaceNeeded(T) {
551 return detail::digitsEnough<unsigned __int128>();
552}
553
554#endif
555
556/**
557 * int32_t and int64_t to string (by appending) go through here. The
558 * result is APPENDED to a preexisting string passed as the second
559 * parameter. This should be efficient with fbstring because fbstring
560 * incurs no dynamic allocation below 23 bytes and no number has more
561 * than 22 bytes in its textual representation (20 for digits, one for
562 * sign, one for the terminating 0).
563 */
564template <class Tgt, class Src>
565typename std::enable_if<
566 std::is_integral<Src>::value && std::is_signed<Src>::value &&
567 IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
568toAppend(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
580template <class Src>
581typename std::enable_if<
582 std::is_integral<Src>::value && std::is_signed<Src>::value &&
583 sizeof(Src) >= 4 && sizeof(Src) < 16,
584 size_t>::type
585estimateSpaceNeeded(Src value) {
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
596/**
597 * As above, but for uint32_t and uint64_t.
598 */
599template <class Tgt, class Src>
600typename std::enable_if<
601 std::is_integral<Src>::value && !std::is_signed<Src>::value &&
602 IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
603toAppend(Src value, Tgt* result) {
604 char buffer[20];
605 result->append(buffer, uint64ToBufferUnsafe(value, buffer));
606}
607
608template <class Src>
609typename std::enable_if<
610 std::is_integral<Src>::value && !std::is_signed<Src>::value &&
611 sizeof(Src) >= 4 && sizeof(Src) < 16,
612 size_t>::type
613estimateSpaceNeeded(Src value) {
614 return digits10(value);
615}
616
617/**
618 * All small signed and unsigned integers to string go through 32-bit
619 * types int32_t and uint32_t, respectively.
620 */
621template <class Tgt, class Src>
622typename std::enable_if<
623 std::is_integral<Src>::value && IsSomeString<Tgt>::value &&
624 sizeof(Src) < 4>::type
625toAppend(Src value, Tgt* result) {
626 typedef
627 typename std::conditional<std::is_signed<Src>::value, int64_t, uint64_t>::
628 type Intermediate;
629 toAppend<Tgt>(static_cast<Intermediate>(value), result);
630}
631
632template <class Src>
633typename std::enable_if<
634 std::is_integral<Src>::value && sizeof(Src) < 4 &&
635 !std::is_same<Src, char>::value,
636 size_t>::type
637estimateSpaceNeeded(Src value) {
638 typedef
639 typename std::conditional<std::is_signed<Src>::value, int64_t, uint64_t>::
640 type Intermediate;
641 return estimateSpaceNeeded(static_cast<Intermediate>(value));
642}
643
644/**
645 * Enumerated values get appended as integers.
646 */
647template <class Tgt, class Src>
648typename std::enable_if<
649 std::is_enum<Src>::value && IsSomeString<Tgt>::value>::type
650toAppend(Src value, Tgt* result) {
651 toAppend(
652 static_cast<typename std::underlying_type<Src>::type>(value), result);
653}
654
655template <class Src>
656typename std::enable_if<std::is_enum<Src>::value, size_t>::type
657estimateSpaceNeeded(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
666namespace detail {
667constexpr int kConvMaxDecimalInShortestLow = -6;
668constexpr int kConvMaxDecimalInShortestHigh = 21;
669} // namespace detail
670
671/** Wrapper around DoubleToStringConverter **/
672template <class Tgt, class Src>
673typename std::enable_if<
674 std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
675toAppend(
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
712/**
713 * As above, but for floating point
714 */
715template <class Tgt, class Src>
716typename std::enable_if<
717 std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
718toAppend(Src value, Tgt* result) {
719 toAppend(
720 value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);
721}
722
723/**
724 * Upper bound of the length of the output from
725 * DoubleToStringConverter::ToShortest(double, StringBuilder*),
726 * as used in toAppend(double, string*).
727 */
728template <class Src>
729typename std::enable_if<std::is_floating_point<Src>::value, size_t>::type
730estimateSpaceNeeded(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
752/**
753 * This can be specialized, together with adding specialization
754 * for estimateSpaceNeed for your type, so that we allocate
755 * as much as you need instead of the default
756 */
757template <class Src>
758struct HasLengthEstimator : std::false_type {};
759
760template <class Src>
761constexpr typename std::enable_if<
762 !std::is_fundamental<Src>::value &&
763#if FOLLY_HAVE_INT128_T
764 // On OSX 10.10, is_fundamental<__int128> is false :-O
765 !std::is_same<__int128, Src>::value &&
766 !std::is_same<unsigned __int128, Src>::value &&
767#endif
768 !IsSomeString<Src>::value &&
769 !std::is_convertible<Src, const char*>::value &&
770 !std::is_convertible<Src, StringPiece>::value &&
771 !std::is_enum<Src>::value && !HasLengthEstimator<Src>::value,
772 size_t>::type
773estimateSpaceNeeded(const Src&) {
774 return sizeof(Src) + 1; // dumbest best effort ever?
775}
776
777namespace detail {
778
779template <class Tgt>
780typename std::enable_if<IsSomeString<Tgt>::value, size_t>::type
781estimateSpaceToReserve(size_t sofar, Tgt*) {
782 return sofar;
783}
784
785template <class T, class... Ts>
786size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) {
787 return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...);
788}
789
790template <class... Ts>
791void reserveInTarget(const Ts&... vs) {
792 getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...));
793}
794
795template <class Delimiter, class... Ts>
796void 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
803/**
804 * Variadic base case: append one element
805 */
806template <class T, class Tgt>
807typename std::enable_if<
808 IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
809toAppendStrImpl(const T& v, Tgt result) {
810 toAppend(v, result);
811}
812
813template <class T, class... Ts>
814typename std::enable_if<
815 sizeof...(Ts) >= 2 &&
816 IsSomeString<typename std::remove_pointer<
817 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
818toAppendStrImpl(const T& v, const Ts&... vs) {
819 toAppend(v, getLastElement(vs...));
820 toAppendStrImpl(vs...);
821}
822
823template <class Delimiter, class T, class Tgt>
824typename std::enable_if<
825 IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
826toAppendDelimStrImpl(const Delimiter& /* delim */, const T& v, Tgt result) {
827 toAppend(v, result);
828}
829
830template <class Delimiter, class T, class... Ts>
831typename std::enable_if<
832 sizeof...(Ts) >= 2 &&
833 IsSomeString<typename std::remove_pointer<
834 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
835toAppendDelimStrImpl(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
845/**
846 * Variadic conversion to string. Appends each element in turn.
847 * If we have two or more things to append, we will not reserve
848 * the space for them and will depend on strings exponential growth.
849 * If you just append once consider using toAppendFit which reserves
850 * the space needed (but does not have exponential as a result).
851 *
852 * Custom implementations of toAppend() can be provided in the same namespace as
853 * the type to customize printing. estimateSpaceNeed() may also be provided to
854 * avoid reallocations in toAppendFit():
855 *
856 * namespace other_namespace {
857 *
858 * template <class String>
859 * void toAppend(const OtherType&, String* out);
860 *
861 * // optional
862 * size_t estimateSpaceNeeded(const OtherType&);
863 *
864 * }
865 */
866template <class... Ts>
867typename std::enable_if<
868 sizeof...(Ts) >= 3 &&
869 IsSomeString<typename std::remove_pointer<
870 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
871toAppend(const Ts&... vs) {
872 ::folly::detail::toAppendStrImpl(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.
880template <class Tgt>
881void toAppend(const pid_t a, Tgt* res) {
882 toAppend(uint64_t(a), res);
883}
884#endif
885
886/**
887 * Special version of the call that preallocates exaclty as much memory
888 * as need for arguments to be stored in target. This means we are
889 * not doing exponential growth when we append. If you are using it
890 * in a loop you are aiming at your foot with a big perf-destroying
891 * bazooka.
892 * On the other hand if you are appending to a string once, this
893 * will probably save a few calls to malloc.
894 */
895template <class... Ts>
896typename std::enable_if<IsSomeString<typename std::remove_pointer<
897 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
898toAppendFit(const Ts&... vs) {
899 ::folly::detail::reserveInTarget(vs...);
900 toAppend(vs...);
901}
902
903template <class Ts>
904void toAppendFit(const Ts&) {}
905
906/**
907 * Variadic base case: do nothing.
908 */
909template <class Tgt>
910typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
911 Tgt* /* result */) {}
912
913/**
914 * Variadic base case: do nothing.
915 */
916template <class Delimiter, class Tgt>
917typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim(
918 const Delimiter& /* delim */,
919 Tgt* /* result */) {}
920
921/**
922 * 1 element: same as toAppend.
923 */
924template <class Delimiter, class T, class Tgt>
925typename std::enable_if<IsSomeString<Tgt>::value>::type
926toAppendDelim(const Delimiter& /* delim */, const T& v, Tgt* tgt) {
927 toAppend(v, tgt);
928}
929
930/**
931 * Append to string with a delimiter in between elements. Check out
932 * comments for toAppend for details about memory allocation.
933 */
934template <class Delimiter, class... Ts>
935typename std::enable_if<
936 sizeof...(Ts) >= 3 &&
937 IsSomeString<typename std::remove_pointer<
938 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
939toAppendDelim(const Delimiter& delim, const Ts&... vs) {
940 detail::toAppendDelimStrImpl(delim, vs...);
941}
942
943/**
944 * Detail in comment for toAppendFit
945 */
946template <class Delimiter, class... Ts>
947typename std::enable_if<IsSomeString<typename std::remove_pointer<
948 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
949toAppendDelimFit(const Delimiter& delim, const Ts&... vs) {
950 detail::reserveInTargetDelim(delim, vs...);
951 toAppendDelim(delim, vs...);
952}
953
954template <class De, class Ts>
955void toAppendDelimFit(const De&, const Ts&) {}
956
957/**
958 * to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end
959 * for all types.
960 */
961template <class Tgt, class... Ts>
962typename std::enable_if<
963 IsSomeString<Tgt>::value &&
964 (sizeof...(Ts) != 1 ||
965 !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
966 value),
967 Tgt>::type
968to(const Ts&... vs) {
969 Tgt result;
970 toAppendFit(vs..., &result);
971 return result;
972}
973
974/**
975 * Special version of to<SomeString> for floating point. When calling
976 * folly::to<SomeString>(double), generic implementation above will
977 * firstly reserve 24 (or 25 when negative value) bytes. This will
978 * introduce a malloc call for most mainstream string implementations.
979 *
980 * But for most cases, a floating point doesn't need 24 (or 25) bytes to
981 * be converted as a string.
982 *
983 * This special version will not do string reserve.
984 */
985template <class Tgt, class Src>
986typename std::enable_if<
987 IsSomeString<Tgt>::value && std::is_floating_point<Src>::value,
988 Tgt>::type
989to(Src value) {
990 Tgt result;
991 toAppend(value, &result);
992 return result;
993}
994
995/**
996 * toDelim<SomeString>(SomeString str) returns itself.
997 */
998template <class Tgt, class Delim, class Src>
999typename std::enable_if<
1000 IsSomeString<Tgt>::value &&
1001 std::is_same<Tgt, typename std::decay<Src>::type>::value,
1002 Tgt>::type
1003toDelim(const Delim& /* delim */, Src&& value) {
1004 return std::forward<Src>(value);
1005}
1006
1007/**
1008 * toDelim<SomeString>(delim, v1, v2, ...) uses toAppendDelim() as
1009 * back-end for all types.
1010 */
1011template <class Tgt, class Delim, class... Ts>
1012typename std::enable_if<
1013 IsSomeString<Tgt>::value &&
1014 (sizeof...(Ts) != 1 ||
1015 !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
1016 value),
1017 Tgt>::type
1018toDelim(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
1028namespace detail {
1029
1030Expected<bool, ConversionCode> str_to_bool(StringPiece* src) noexcept;
1031
1032template <typename T>
1033Expected<T, ConversionCode> str_to_floating(StringPiece* src) noexcept;
1034
1035extern template Expected<float, ConversionCode> str_to_floating<float>(
1036 StringPiece* src) noexcept;
1037extern template Expected<double, ConversionCode> str_to_floating<double>(
1038 StringPiece* src) noexcept;
1039
1040template <class Tgt>
1041Expected<Tgt, ConversionCode> digits_to(const char* b, const char* e) noexcept;
1042
1043extern template Expected<char, ConversionCode> digits_to<char>(
1044 const char*,
1045 const char*) noexcept;
1046extern template Expected<signed char, ConversionCode> digits_to<signed char>(
1047 const char*,
1048 const char*) noexcept;
1049extern template Expected<unsigned char, ConversionCode>
1050digits_to<unsigned char>(const char*, const char*) noexcept;
1051
1052extern template Expected<short, ConversionCode> digits_to<short>(
1053 const char*,
1054 const char*) noexcept;
1055extern template Expected<unsigned short, ConversionCode>
1056digits_to<unsigned short>(const char*, const char*) noexcept;
1057
1058extern template Expected<int, ConversionCode> digits_to<int>(
1059 const char*,
1060 const char*) noexcept;
1061extern template Expected<unsigned int, ConversionCode> digits_to<unsigned int>(
1062 const char*,
1063 const char*) noexcept;
1064
1065extern template Expected<long, ConversionCode> digits_to<long>(
1066 const char*,
1067 const char*) noexcept;
1068extern template Expected<unsigned long, ConversionCode>
1069digits_to<unsigned long>(const char*, const char*) noexcept;
1070
1071extern template Expected<long long, ConversionCode> digits_to<long long>(
1072 const char*,
1073 const char*) noexcept;
1074extern template Expected<unsigned long long, ConversionCode>
1075digits_to<unsigned long long>(const char*, const char*) noexcept;
1076
1077#if FOLLY_HAVE_INT128_T
1078extern template Expected<__int128, ConversionCode> digits_to<__int128>(
1079 const char*,
1080 const char*) noexcept;
1081extern template Expected<unsigned __int128, ConversionCode>
1082digits_to<unsigned __int128>(const char*, const char*) noexcept;
1083#endif
1084
1085template <class T>
1086Expected<T, ConversionCode> str_to_integral(StringPiece* src) noexcept;
1087
1088extern template Expected<char, ConversionCode> str_to_integral<char>(
1089 StringPiece* src) noexcept;
1090extern template Expected<signed char, ConversionCode>
1091str_to_integral<signed char>(StringPiece* src) noexcept;
1092extern template Expected<unsigned char, ConversionCode>
1093str_to_integral<unsigned char>(StringPiece* src) noexcept;
1094
1095extern template Expected<short, ConversionCode> str_to_integral<short>(
1096 StringPiece* src) noexcept;
1097extern template Expected<unsigned short, ConversionCode>
1098str_to_integral<unsigned short>(StringPiece* src) noexcept;
1099
1100extern template Expected<int, ConversionCode> str_to_integral<int>(
1101 StringPiece* src) noexcept;
1102extern template Expected<unsigned int, ConversionCode>
1103str_to_integral<unsigned int>(StringPiece* src) noexcept;
1104
1105extern template Expected<long, ConversionCode> str_to_integral<long>(
1106 StringPiece* src) noexcept;
1107extern template Expected<unsigned long, ConversionCode>
1108str_to_integral<unsigned long>(StringPiece* src) noexcept;
1109
1110extern template Expected<long long, ConversionCode> str_to_integral<long long>(
1111 StringPiece* src) noexcept;
1112extern template Expected<unsigned long long, ConversionCode>
1113str_to_integral<unsigned long long>(StringPiece* src) noexcept;
1114
1115#if FOLLY_HAVE_INT128_T
1116extern template Expected<__int128, ConversionCode> str_to_integral<__int128>(
1117 StringPiece* src) noexcept;
1118extern template Expected<unsigned __int128, ConversionCode>
1119str_to_integral<unsigned __int128>(StringPiece* src) noexcept;
1120#endif
1121
1122template <typename T>
1123typename std::
1124 enable_if<std::is_same<T, bool>::value, Expected<T, ConversionCode>>::type
1125 convertTo(StringPiece* src) noexcept {
1126 return str_to_bool(src);
1127}
1128
1129template <typename T>
1130typename std::enable_if<
1131 std::is_floating_point<T>::value,
1132 Expected<T, ConversionCode>>::type
1133convertTo(StringPiece* src) noexcept {
1134 return str_to_floating<T>(src);
1135}
1136
1137template <typename T>
1138typename std::enable_if<
1139 std::is_integral<T>::value && !std::is_same<T, bool>::value,
1140 Expected<T, ConversionCode>>::type
1141convertTo(StringPiece* src) noexcept {
1142 return str_to_integral<T>(src);
1143}
1144
1145} // namespace detail
1146
1147/**
1148 * String represented as a pair of pointers to char to unsigned
1149 * integrals. Assumes NO whitespace before or after.
1150 */
1151template <typename Tgt>
1152typename std::enable_if<
1153 std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1154 Expected<Tgt, ConversionCode>>::type
1155tryTo(const char* b, const char* e) {
1156 return detail::digits_to<Tgt>(b, e);
1157}
1158
1159template <typename Tgt>
1160typename std::enable_if<
1161 std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1162 Tgt>::type
1163to(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
1175/**
1176 * Parsing strings to numeric types.
1177 */
1178template <typename Tgt>
1179FOLLY_NODISCARD inline typename std::enable_if<
1180 std::is_arithmetic<Tgt>::value,
1181 Expected<StringPiece, ConversionCode>>::type
1182parseTo(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
1191namespace detail {
1192
1193/**
1194 * Bool to integral/float doesn't need any special checks, and this
1195 * overload means we aren't trying to see if a bool is less than
1196 * an integer.
1197 */
1198template <class Tgt>
1199typename std::enable_if<
1200 !std::is_same<Tgt, bool>::value &&
1201 (std::is_integral<Tgt>::value || std::is_floating_point<Tgt>::value),
1202 Expected<Tgt, ConversionCode>>::type
1203convertTo(const bool& value) noexcept {
1204 return static_cast<Tgt>(value ? 1 : 0);
1205}
1206
1207/**
1208 * Checked conversion from integral to integral. The checks are only
1209 * performed when meaningful, e.g. conversion from int to long goes
1210 * unchecked.
1211 */
1212template <class Tgt, class Src>
1213typename std::enable_if<
1214 std::is_integral<Src>::value && !std::is_same<Tgt, Src>::value &&
1215 !std::is_same<Tgt, bool>::value && std::is_integral<Tgt>::value,
1216 Expected<Tgt, ConversionCode>>::type
1217convertTo(const Src& value) noexcept {
1218 if /* constexpr */ (
1219 std::make_unsigned_t<Tgt>(std::numeric_limits<Tgt>::max()) <
1220 std::make_unsigned_t<Src>(std::numeric_limits<Src>::max())) {
1221 if (greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)) {
1222 return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1223 }
1224 }
1225 if /* constexpr */ (
1226 std::is_signed<Src>::value &&
1227 (!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) {
1228 if (less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)) {
1229 return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1230 }
1231 }
1232 return static_cast<Tgt>(value);
1233}
1234
1235/**
1236 * Checked conversion from floating to floating. The checks are only
1237 * performed when meaningful, e.g. conversion from float to double goes
1238 * unchecked.
1239 */
1240template <class Tgt, class Src>
1241typename std::enable_if<
1242 std::is_floating_point<Tgt>::value && std::is_floating_point<Src>::value &&
1243 !std::is_same<Tgt, Src>::value,
1244 Expected<Tgt, ConversionCode>>::type
1245convertTo(const Src& value) noexcept {
1246 if /* constexpr */ (
1247 std::numeric_limits<Tgt>::max() < std::numeric_limits<Src>::max()) {
1248 if (value > std::numeric_limits<Tgt>::max()) {
1249 return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1250 }
1251 if (value < std::numeric_limits<Tgt>::lowest()) {
1252 return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1253 }
1254 }
1255 return static_cast<Tgt>(value);
1256}
1257
1258/**
1259 * Check if a floating point value can safely be converted to an
1260 * integer value without triggering undefined behaviour.
1261 */
1262template <typename Tgt, typename Src>
1263inline 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
1267checkConversion(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
1293template <typename Tgt, typename Src>
1294constexpr typename std::enable_if<
1295 std::is_integral<Src>::value && std::is_floating_point<Tgt>::value,
1296 bool>::type
1297checkConversion(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
1303template <typename Tgt, typename Src>
1304constexpr typename std::enable_if<
1305 std::is_floating_point<Src>::value && std::is_same<Tgt, bool>::value,
1306 bool>::type
1307checkConversion(const Src&) {
1308 return true;
1309}
1310
1311/**
1312 * Checked conversion from integral to floating point and back. The
1313 * result must be convertible back to the source type without loss of
1314 * precision. This seems Draconian but sometimes is what's needed, and
1315 * complements existing routines nicely. For various rounding
1316 * routines, see <math>.
1317 */
1318template <typename Tgt, typename Src>
1319typename 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),
1322 Expected<Tgt, ConversionCode>>::type
1323convertTo(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 }
1333 return makeUnexpected(ConversionCode::ARITH_LOSS_OF_PRECISION);
1334}
1335
1336template <typename Tgt, typename Src>
1337inline 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
1345template <typename Tgt, typename Src>
1346using IsArithToArith = bool_constant<
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
1352template <typename Tgt, typename Src>
1353typename std::enable_if<
1354 detail::IsArithToArith<Tgt, Src>::value,
1355 Expected<Tgt, ConversionCode>>::type
1356tryTo(const Src& value) noexcept {
1357 return detail::convertTo<Tgt>(value);
1358}
1359
1360template <typename Tgt, typename Src>
1361typename std::enable_if<detail::IsArithToArith<Tgt, Src>::value, Tgt>::type to(
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 ******************************************************************************/
1382template <class T>
1383FOLLY_NODISCARD typename std::enable_if<
1384 std::is_enum<T>::value,
1385 Expected<StringPiece, ConversionCode>>::type
1386parseTo(StringPiece in, T& out) noexcept {
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
1393FOLLY_NODISCARD
1394inline Expected<StringPiece, ConversionCode> parseTo(
1395 StringPiece in,
1396 StringPiece& out) noexcept {
1397 out = in;
1398 return StringPiece{in.end(), in.end()};
1399}
1400
1401FOLLY_NODISCARD
1402inline Expected<StringPiece, ConversionCode> parseTo(
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
1410FOLLY_NODISCARD
1411inline Expected<StringPiece, ConversionCode> parseTo(
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
1419namespace detail {
1420template <typename Tgt>
1421using ParseToResult = decltype(parseTo(StringPiece{}, std::declval<Tgt&>()));
1422
1423struct CheckTrailingSpace {
1424 Expected<Unit, ConversionCode> operator()(StringPiece sp) const {
1425 auto e = enforceWhitespaceErr(sp);
1426 if (UNLIKELY(e != ConversionCode::SUCCESS)) {
1427 return makeUnexpected(e);
1428 }
1429 return unit;
1430 }
1431};
1432
1433template <class Error>
1434struct 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.
1443template <class Tgt>
1444inline typename std::enable_if<
1445 std::is_void<ParseToResult<Tgt>>::value,
1446 Expected<StringPiece, ConversionCode>>::type
1447parseToWrap(StringPiece sp, Tgt& out) {
1448 parseTo(sp, out);
1449 return StringPiece(sp.end(), sp.end());
1450}
1451
1452template <class Tgt>
1453inline typename std::enable_if<
1454 !std::is_void<ParseToResult<Tgt>>::value,
1455 ParseToResult<Tgt>>::type
1456parseToWrap(StringPiece sp, Tgt& out) {
1457 return parseTo(sp, out);
1458}
1459
1460template <typename Tgt>
1461using ParseToError = ExpectedErrorType<decltype(
1462 detail::parseToWrap(StringPiece{}, std::declval<Tgt&>()))>;
1463
1464} // namespace detail
1465
1466/**
1467 * String or StringPiece to target conversion. Accepts leading and trailing
1468 * whitespace, but no non-space trailing characters.
1469 */
1470
1471template <class Tgt>
1472inline typename std::enable_if<
1473 !std::is_same<StringPiece, Tgt>::value,
1474 Expected<Tgt, detail::ParseToError<Tgt>>>::type
1475tryTo(StringPiece src) {
1476 Tgt result{};
1477 using Error = detail::ParseToError<Tgt>;
1478 using Check = typename std::conditional<
1479 std::is_arithmetic<Tgt>::value,
1480 detail::CheckTrailingSpace,
1481 detail::ReturnUnit<Error>>::type;
1482 return parseTo(src, result).then(Check(), [&](Unit) {
1483 return std::move(result);
1484 });
1485}
1486
1487template <class Tgt, class Src>
1488inline typename std::enable_if<
1489 IsSomeString<Src>::value && !std::is_same<StringPiece, Tgt>::value,
1490 Tgt>::type
1491to(Src const& src) {
1492 return to<Tgt>(StringPiece(src.data(), src.size()));
1493}
1494
1495template <class Tgt>
1496inline
1497 typename std::enable_if<!std::is_same<StringPiece, Tgt>::value, Tgt>::type
1498 to(StringPiece src) {
1499 Tgt result{};
1500 using Error = detail::ParseToError<Tgt>;
1501 using Check = typename std::conditional<
1502 std::is_arithmetic<Tgt>::value,
1503 detail::CheckTrailingSpace,
1504 detail::ReturnUnit<Error>>::type;
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
1517/**
1518 * tryTo/to that take the strings by pointer so the caller gets information
1519 * about how much of the string was consumed by the conversion. These do not
1520 * check for trailing whitepsace.
1521 */
1522template <class Tgt>
1523Expected<Tgt, detail::ParseToError<Tgt>> tryTo(StringPiece* src) {
1524 Tgt result;
1525 return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt {
1526 *src = sp;
1527 return std::move(result);
1528 });
1529}
1530
1531template <class Tgt>
1532Tgt 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
1548template <class Tgt, class Src>
1549typename std::enable_if<
1550 std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1551 !std::is_convertible<Tgt, StringPiece>::value,
1552 Expected<Tgt, ConversionCode>>::type
1553tryTo(const Src& value) {
1554 using I = typename std::underlying_type<Src>::type;
1555 return tryTo<Tgt>(static_cast<I>(value));
1556}
1557
1558template <class Tgt, class Src>
1559typename std::enable_if<
1560 !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1561 !std::is_same<Src, Tgt>::value,
1562 Expected<Tgt, ConversionCode>>::type
1563tryTo(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
1568template <class Tgt, class Src>
1569typename std::enable_if<
1570 std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1571 !std::is_convertible<Tgt, StringPiece>::value,
1572 Tgt>::type
1573to(const Src& value) {
1574 return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(value));
1575}
1576
1577template <class Tgt, class Src>
1578typename std::enable_if<
1579 !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1580 !std::is_same<Src, Tgt>::value,
1581 Tgt>::type
1582to(const Src& value) {
1583 return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
1584}
1585
1586} // namespace folly
1587