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/Range.h>
121#include <folly/Traits.h>
122#include <folly/Unit.h>
123#include <folly/Utility.h>
124#include <folly/lang/Exception.h>
125#include <folly/lang/Pretty.h>
126#include <folly/portability/Math.h>
127
128namespace folly {
129
130// Keep this in sync with kErrorStrings in Conv.cpp
131enum class ConversionCode : unsigned char {
132 SUCCESS,
133 EMPTY_INPUT_STRING,
134 NO_DIGITS,
135 BOOL_OVERFLOW,
136 BOOL_INVALID_VALUE,
137 NON_DIGIT_CHAR,
138 INVALID_LEADING_CHAR,
139 POSITIVE_OVERFLOW,
140 NEGATIVE_OVERFLOW,
141 STRING_TO_FLOAT_ERROR,
142 NON_WHITESPACE_AFTER_END,
143 ARITH_POSITIVE_OVERFLOW,
144 ARITH_NEGATIVE_OVERFLOW,
145 ARITH_LOSS_OF_PRECISION,
146 NUM_ERROR_CODES, // has to be the last entry
147};
148
149struct ConversionErrorBase : std::range_error {
150 using std::range_error::range_error;
151};
152
153class ConversionError : public ConversionErrorBase {
154 public:
155 ConversionError(const std::string& str, ConversionCode code)
156 : ConversionErrorBase(str), code_(code) {}
157
158 ConversionError(const char* str, ConversionCode code)
159 : ConversionErrorBase(str), code_(code) {}
160
161 ConversionCode errorCode() const {
162 return code_;
163 }
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 ******************************************************************************/
190ConversionError makeConversionError(ConversionCode code, StringPiece input);
191
192namespace detail {
193/**
194 * Enforce that the suffix following a number is made up only of whitespace.
195 */
196inline 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 */
208inline 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 */
220template <class Tgt, class Src>
221typename std::enable_if<
222 std::is_same<Tgt, typename std::decay<Src>::type>::value,
223 Expected<Tgt, ConversionCode>>::type
224tryTo(Src&& value) {
225 return std::forward<Src>(value);
226}
227
228template <class Tgt, class Src>
229typename std::enable_if<
230 std::is_same<Tgt, typename std::decay<Src>::type>::value,
231 Tgt>::type
232to(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 */
245template <class Tgt, class Src>
246typename std::enable_if<
247 std::is_arithmetic<Src>::value && !std::is_same<Tgt, Src>::value &&
248 std::is_same<Tgt, bool>::value,
249 Expected<Tgt, ConversionCode>>::type
250tryTo(const Src& value) {
251 return value != Src();
252}
253
254template <class Tgt, class Src>
255typename std::enable_if<
256 std::is_arithmetic<Src>::value && !std::is_same<Tgt, Src>::value &&
257 std::is_same<Tgt, bool>::value,
258 Tgt>::type
259to(const Src& value) {
260 return value != Src();
261}
262
263/*******************************************************************************
264 * Anything to string
265 ******************************************************************************/
266
267namespace 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
275template <typename... Ts>
276auto 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
282inline void getLastElement() {}
283
284template <size_t size, typename... Ts>
285struct LastElementType : std::tuple_element<size - 1, std::tuple<Ts...>> {};
286
287template <>
288struct LastElementType<0> {
289 using type = void;
290};
291
292template <class... Ts>
293struct LastElement
294 : std::decay<typename LastElementType<sizeof...(Ts), Ts...>::type> {};
295#else
296template <typename... Ts>
297struct LastElementImpl {
298 static void call(Ignored<Ts>...) {}
299};
300
301template <typename Head, typename... Ts>
302struct LastElementImpl<Head, Ts...> {
303 template <typename Last>
304 static Last call(Ignored<Ts>..., Last&& last) {
305 return std::forward<Last>(last);
306 }
307};
308
309template <typename... Ts>
310auto getLastElement(const Ts&... ts)
311 -> decltype(LastElementImpl<Ts...>::call(ts...)) {
312 return LastElementImpl<Ts...>::call(ts...);
313}
314
315template <class... Ts>
316struct LastElement : std::decay<decltype(
317 LastElementImpl<Ts...>::call(std::declval<Ts>()...))> {
318};
319#endif
320
321} // namespace detail
322
323/*******************************************************************************
324 * Conversions from integral types to string types.
325 ******************************************************************************/
326
327#if FOLLY_HAVE_INT128_T
328namespace detail {
329
330template <typename IntegerType>
331constexpr unsigned int digitsEnough() {
332 return (unsigned int)(ceil(sizeof(IntegerType) * CHAR_BIT * M_LN2 / M_LN10));
333}
334
335inline size_t
336unsafeTelescope128(char* buffer, size_t room, unsigned __int128 x) {
337 typedef unsigned __int128 Usrc;
338 size_t p = room - 1;
339
340 while (x >= (Usrc(1) << 64)) { // Using 128-bit division while needed
341 const auto y = x / 10;
342 const auto digit = x % 10;
343
344 buffer[p--] = static_cast<char>('0' + digit);
345 x = y;
346 }
347
348 uint64_t xx = static_cast<uint64_t>(x); // Rest uses faster 64-bit division
349
350 while (xx >= 10) {
351 const auto y = xx / 10ULL;
352 const auto digit = xx % 10ULL;
353
354 buffer[p--] = static_cast<char>('0' + digit);
355 xx = y;
356 }
357
358 buffer[p] = static_cast<char>('0' + xx);
359
360 return p;
361}
362
363} // namespace detail
364#endif
365
366/**
367 * Returns the number of digits in the base 10 representation of an
368 * uint64_t. Useful for preallocating buffers and such. It's also used
369 * internally, see below. Measurements suggest that defining a
370 * separate overload for 32-bit integers is not worthwhile.
371 */
372
373inline uint32_t digits10(uint64_t v) {
374#ifdef __x86_64__
375
376 // For this arch we can get a little help from specialized CPU instructions
377 // which can count leading zeroes; 64 minus that is appx. log (base 2).
378 // Use that to approximate base-10 digits (log_10) and then adjust if needed.
379
380 // 10^i, defined for i 0 through 19.
381 // This is 20 * 8 == 160 bytes, which fits neatly into 5 cache lines
382 // (assuming a cache line size of 64).
383 alignas(64) static const uint64_t powersOf10[20] = {
384 1,
385 10,
386 100,
387 1000,
388 10000,
389 100000,
390 1000000,
391 10000000,
392 100000000,
393 1000000000,
394 10000000000,
395 100000000000,
396 1000000000000,
397 10000000000000,
398 100000000000000,
399 1000000000000000,
400 10000000000000000,
401 100000000000000000,
402 1000000000000000000,
403 10000000000000000000UL,
404 };
405
406 // "count leading zeroes" operation not valid; for 0; special case this.
407 if (UNLIKELY(!v)) {
408 return 1;
409 }
410
411 // bits is in the ballpark of log_2(v).
412 const uint32_t leadingZeroes = __builtin_clzll(v);
413 const auto bits = 63 - leadingZeroes;
414
415 // approximate log_10(v) == log_10(2) * bits.
416 // Integer magic below: 77/256 is appx. 0.3010 (log_10(2)).
417 // The +1 is to make this the ceiling of the log_10 estimate.
418 const uint32_t minLength = 1 + ((bits * 77) >> 8);
419
420 // return that log_10 lower bound, plus adjust if input >= 10^(that bound)
421 // in case there's a small error and we misjudged length.
422 return minLength + uint32_t(v >= powersOf10[minLength]);
423
424#else
425
426 uint32_t result = 1;
427 while (true) {
428 if (LIKELY(v < 10)) {
429 return result;
430 }
431 if (LIKELY(v < 100)) {
432 return result + 1;
433 }
434 if (LIKELY(v < 1000)) {
435 return result + 2;
436 }
437 if (LIKELY(v < 10000)) {
438 return result + 3;
439 }
440 // Skip ahead by 4 orders of magnitude
441 v /= 10000U;
442 result += 4;
443 }
444
445#endif
446}
447
448/**
449 * Copies the ASCII base 10 representation of v into buffer and
450 * returns the number of bytes written. Does NOT append a \0. Assumes
451 * the buffer points to digits10(v) bytes of valid memory. Note that
452 * uint64 needs at most 20 bytes, uint32_t needs at most 10 bytes,
453 * uint16_t needs at most 5 bytes, and so on. Measurements suggest
454 * that defining a separate overload for 32-bit integers is not
455 * worthwhile.
456 *
457 * This primitive is unsafe because it makes the size assumption and
458 * because it does not add a terminating \0.
459 */
460
461inline uint32_t uint64ToBufferUnsafe(uint64_t v, char* const buffer) {
462 auto const result = digits10(v);
463 // WARNING: using size_t or pointer arithmetic for pos slows down
464 // the loop below 20x. This is because several 32-bit ops can be
465 // done in parallel, but only fewer 64-bit ones.
466 uint32_t pos = result - 1;
467 while (v >= 10) {
468 // Keep these together so a peephole optimization "sees" them and
469 // computes them in one shot.
470 auto const q = v / 10;
471 auto const r = v % 10;
472 buffer[pos--] = static_cast<char>('0' + r);
473 v = q;
474 }
475 // Last digit is trivial to handle
476 buffer[pos] = static_cast<char>(v + '0');
477 return result;
478}
479
480/**
481 * A single char gets appended.
482 */
483template <class Tgt>
484void toAppend(char value, Tgt* result) {
485 *result += value;
486}
487
488template <class T>
489constexpr typename std::enable_if<std::is_same<T, char>::value, size_t>::type
490estimateSpaceNeeded(T) {
491 return 1;
492}
493
494template <size_t N>
495constexpr size_t estimateSpaceNeeded(const char (&)[N]) {
496 return N;
497}
498
499/**
500 * Everything implicitly convertible to const char* gets appended.
501 */
502template <class Tgt, class Src>
503typename std::enable_if<
504 std::is_convertible<Src, const char*>::value &&
505 IsSomeString<Tgt>::value>::type
506toAppend(Src value, Tgt* result) {
507 // Treat null pointers like an empty string, as in:
508 // operator<<(std::ostream&, const char*).
509 const char* c = value;
510 if (c) {
511 result->append(value);
512 }
513}
514
515template <class Src>
516typename std::enable_if<std::is_convertible<Src, const char*>::value, size_t>::
517 type
518 estimateSpaceNeeded(Src value) {
519 const char* c = value;
520 if (c) {
521 return folly::StringPiece(value).size();
522 };
523 return 0;
524}
525
526template <class Src>
527typename std::enable_if<IsSomeString<Src>::value, size_t>::type
528estimateSpaceNeeded(Src const& value) {
529 return value.size();
530}
531
532template <class Src>
533typename std::enable_if<
534 std::is_convertible<Src, folly::StringPiece>::value &&
535 !IsSomeString<Src>::value &&
536 !std::is_convertible<Src, const char*>::value,
537 size_t>::type
538estimateSpaceNeeded(Src value) {
539 return folly::StringPiece(value).size();
540}
541
542template <>
543inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) {
544 return 0;
545}
546
547template <class Src>
548typename std::enable_if<
549 std::is_pointer<Src>::value &&
550 IsSomeString<std::remove_pointer<Src>>::value,
551 size_t>::type
552estimateSpaceNeeded(Src value) {
553 return value->size();
554}
555
556/**
557 * Strings get appended, too.
558 */
559template <class Tgt, class Src>
560typename std::enable_if<
561 IsSomeString<Src>::value && IsSomeString<Tgt>::value>::type
562toAppend(const Src& value, Tgt* result) {
563 result->append(value);
564}
565
566/**
567 * and StringPiece objects too
568 */
569template <class Tgt>
570typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
571 StringPiece value,
572 Tgt* result) {
573 result->append(value.data(), value.size());
574}
575
576/**
577 * There's no implicit conversion from fbstring to other string types,
578 * so make a specialization.
579 */
580template <class Tgt>
581typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
582 const fbstring& value,
583 Tgt* result) {
584 result->append(value.data(), value.size());
585}
586
587#if FOLLY_HAVE_INT128_T
588/**
589 * Special handling for 128 bit integers.
590 */
591
592template <class Tgt>
593void toAppend(__int128 value, Tgt* result) {
594 typedef unsigned __int128 Usrc;
595 char buffer[detail::digitsEnough<unsigned __int128>() + 1];
596 size_t p;
597
598 if (value < 0) {
599 p = detail::unsafeTelescope128(buffer, sizeof(buffer), -Usrc(value));
600 buffer[--p] = '-';
601 } else {
602 p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
603 }
604
605 result->append(buffer + p, buffer + sizeof(buffer));
606}
607
608template <class Tgt>
609void toAppend(unsigned __int128 value, Tgt* result) {
610 char buffer[detail::digitsEnough<unsigned __int128>()];
611 size_t p;
612
613 p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
614
615 result->append(buffer + p, buffer + sizeof(buffer));
616}
617
618template <class T>
619constexpr
620 typename std::enable_if<std::is_same<T, __int128>::value, size_t>::type
621 estimateSpaceNeeded(T) {
622 return detail::digitsEnough<__int128>();
623}
624
625template <class T>
626constexpr typename std::
627 enable_if<std::is_same<T, unsigned __int128>::value, size_t>::type
628 estimateSpaceNeeded(T) {
629 return detail::digitsEnough<unsigned __int128>();
630}
631
632#endif
633
634/**
635 * int32_t and int64_t to string (by appending) go through here. The
636 * result is APPENDED to a preexisting string passed as the second
637 * parameter. This should be efficient with fbstring because fbstring
638 * incurs no dynamic allocation below 23 bytes and no number has more
639 * than 22 bytes in its textual representation (20 for digits, one for
640 * sign, one for the terminating 0).
641 */
642template <class Tgt, class Src>
643typename std::enable_if<
644 std::is_integral<Src>::value && std::is_signed<Src>::value &&
645 IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
646toAppend(Src value, Tgt* result) {
647 char buffer[20];
648 if (value < 0) {
649 result->push_back('-');
650 result->append(
651 buffer,
652 uint64ToBufferUnsafe(~static_cast<uint64_t>(value) + 1, buffer));
653 } else {
654 result->append(buffer, uint64ToBufferUnsafe(uint64_t(value), buffer));
655 }
656}
657
658template <class Src>
659typename std::enable_if<
660 std::is_integral<Src>::value && std::is_signed<Src>::value &&
661 sizeof(Src) >= 4 && sizeof(Src) < 16,
662 size_t>::type
663estimateSpaceNeeded(Src value) {
664 if (value < 0) {
665 // When "value" is the smallest negative, negating it would evoke
666 // undefined behavior, so, instead of writing "-value" below, we write
667 // "~static_cast<uint64_t>(value) + 1"
668 return 1 + digits10(~static_cast<uint64_t>(value) + 1);
669 }
670
671 return digits10(static_cast<uint64_t>(value));
672}
673
674/**
675 * As above, but for uint32_t and uint64_t.
676 */
677template <class Tgt, class Src>
678typename std::enable_if<
679 std::is_integral<Src>::value && !std::is_signed<Src>::value &&
680 IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
681toAppend(Src value, Tgt* result) {
682 char buffer[20];
683 result->append(buffer, uint64ToBufferUnsafe(value, buffer));
684}
685
686template <class Src>
687typename std::enable_if<
688 std::is_integral<Src>::value && !std::is_signed<Src>::value &&
689 sizeof(Src) >= 4 && sizeof(Src) < 16,
690 size_t>::type
691estimateSpaceNeeded(Src value) {
692 return digits10(value);
693}
694
695/**
696 * All small signed and unsigned integers to string go through 32-bit
697 * types int32_t and uint32_t, respectively.
698 */
699template <class Tgt, class Src>
700typename std::enable_if<
701 std::is_integral<Src>::value && IsSomeString<Tgt>::value &&
702 sizeof(Src) < 4>::type
703toAppend(Src value, Tgt* result) {
704 typedef
705 typename std::conditional<std::is_signed<Src>::value, int64_t, uint64_t>::
706 type Intermediate;
707 toAppend<Tgt>(static_cast<Intermediate>(value), result);
708}
709
710template <class Src>
711typename std::enable_if<
712 std::is_integral<Src>::value && sizeof(Src) < 4 &&
713 !std::is_same<Src, char>::value,
714 size_t>::type
715estimateSpaceNeeded(Src value) {
716 typedef
717 typename std::conditional<std::is_signed<Src>::value, int64_t, uint64_t>::
718 type Intermediate;
719 return estimateSpaceNeeded(static_cast<Intermediate>(value));
720}
721
722/**
723 * Enumerated values get appended as integers.
724 */
725template <class Tgt, class Src>
726typename std::enable_if<
727 std::is_enum<Src>::value && IsSomeString<Tgt>::value>::type
728toAppend(Src value, Tgt* result) {
729 toAppend(to_underlying(value), result);
730}
731
732template <class Src>
733typename std::enable_if<std::is_enum<Src>::value, size_t>::type
734estimateSpaceNeeded(Src value) {
735 return estimateSpaceNeeded(to_underlying(value));
736}
737
738/*******************************************************************************
739 * Conversions from floating-point types to string types.
740 ******************************************************************************/
741
742namespace detail {
743constexpr int kConvMaxDecimalInShortestLow = -6;
744constexpr int kConvMaxDecimalInShortestHigh = 21;
745} // namespace detail
746
747/** Wrapper around DoubleToStringConverter **/
748template <class Tgt, class Src>
749typename std::enable_if<
750 std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
751toAppend(
752 Src value,
753 Tgt* result,
754 double_conversion::DoubleToStringConverter::DtoaMode mode,
755 unsigned int numDigits) {
756 using namespace double_conversion;
757 DoubleToStringConverter conv(
758 DoubleToStringConverter::NO_FLAGS,
759 "Infinity",
760 "NaN",
761 'E',
762 detail::kConvMaxDecimalInShortestLow,
763 detail::kConvMaxDecimalInShortestHigh,
764 6, // max leading padding zeros
765 1); // max trailing padding zeros
766 char buffer[256];
767 StringBuilder builder(buffer, sizeof(buffer));
768 switch (mode) {
769 case DoubleToStringConverter::SHORTEST:
770 conv.ToShortest(value, &builder);
771 break;
772 case DoubleToStringConverter::SHORTEST_SINGLE:
773 conv.ToShortestSingle(static_cast<float>(value), &builder);
774 break;
775 case DoubleToStringConverter::FIXED:
776 conv.ToFixed(value, int(numDigits), &builder);
777 break;
778 case DoubleToStringConverter::PRECISION:
779 default:
780 assert(mode == DoubleToStringConverter::PRECISION);
781 conv.ToPrecision(value, int(numDigits), &builder);
782 break;
783 }
784 const size_t length = size_t(builder.position());
785 builder.Finalize();
786 result->append(buffer, length);
787}
788
789/**
790 * As above, but for floating point
791 */
792template <class Tgt, class Src>
793typename std::enable_if<
794 std::is_floating_point<Src>::value && IsSomeString<Tgt>::value>::type
795toAppend(Src value, Tgt* result) {
796 toAppend(
797 value, result, double_conversion::DoubleToStringConverter::SHORTEST, 0);
798}
799
800/**
801 * Upper bound of the length of the output from
802 * DoubleToStringConverter::ToShortest(double, StringBuilder*),
803 * as used in toAppend(double, string*).
804 */
805template <class Src>
806typename std::enable_if<std::is_floating_point<Src>::value, size_t>::type
807estimateSpaceNeeded(Src value) {
808 // kBase10MaximalLength is 17. We add 1 for decimal point,
809 // e.g. 10.0/9 is 17 digits and 18 characters, including the decimal point.
810 constexpr int kMaxMantissaSpace =
811 double_conversion::DoubleToStringConverter::kBase10MaximalLength + 1;
812 // strlen("E-") + digits10(numeric_limits<double>::max_exponent10)
813 constexpr int kMaxExponentSpace = 2 + 3;
814 static const int kMaxPositiveSpace = std::max({
815 // E.g. 1.1111111111111111E-100.
816 kMaxMantissaSpace + kMaxExponentSpace,
817 // E.g. 0.000001.1111111111111111, if kConvMaxDecimalInShortestLow is -6.
818 kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow,
819 // If kConvMaxDecimalInShortestHigh is 21, then 1e21 is the smallest
820 // number > 1 which ToShortest outputs in exponential notation,
821 // so 21 is the longest non-exponential number > 1.
822 detail::kConvMaxDecimalInShortestHigh,
823 });
824 return size_t(
825 kMaxPositiveSpace +
826 (value < 0 ? 1 : 0)); // +1 for minus sign, if negative
827}
828
829/**
830 * This can be specialized, together with adding specialization
831 * for estimateSpaceNeed for your type, so that we allocate
832 * as much as you need instead of the default
833 */
834template <class Src>
835struct HasLengthEstimator : std::false_type {};
836
837template <class Src>
838constexpr typename std::enable_if<
839 !std::is_fundamental<Src>::value &&
840#if FOLLY_HAVE_INT128_T
841 // On OSX 10.10, is_fundamental<__int128> is false :-O
842 !std::is_same<__int128, Src>::value &&
843 !std::is_same<unsigned __int128, Src>::value &&
844#endif
845 !IsSomeString<Src>::value &&
846 !std::is_convertible<Src, const char*>::value &&
847 !std::is_convertible<Src, StringPiece>::value &&
848 !std::is_enum<Src>::value && !HasLengthEstimator<Src>::value,
849 size_t>::type
850estimateSpaceNeeded(const Src&) {
851 return sizeof(Src) + 1; // dumbest best effort ever?
852}
853
854namespace detail {
855
856template <class Tgt>
857typename std::enable_if<IsSomeString<Tgt>::value, size_t>::type
858estimateSpaceToReserve(size_t sofar, Tgt*) {
859 return sofar;
860}
861
862template <class T, class... Ts>
863size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) {
864 return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...);
865}
866
867template <class... Ts>
868void reserveInTarget(const Ts&... vs) {
869 getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...));
870}
871
872template <class Delimiter, class... Ts>
873void reserveInTargetDelim(const Delimiter& d, const Ts&... vs) {
874 static_assert(sizeof...(vs) >= 2, "Needs at least 2 args");
875 size_t fordelim = (sizeof...(vs) - 2) *
876 estimateSpaceToReserve(0, d, static_cast<std::string*>(nullptr));
877 getLastElement(vs...)->reserve(estimateSpaceToReserve(fordelim, vs...));
878}
879
880/**
881 * Variadic base case: append one element
882 */
883template <class T, class Tgt>
884typename std::enable_if<
885 IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
886toAppendStrImpl(const T& v, Tgt result) {
887 toAppend(v, result);
888}
889
890template <class T, class... Ts>
891typename std::enable_if<
892 sizeof...(Ts) >= 2 &&
893 IsSomeString<typename std::remove_pointer<
894 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
895toAppendStrImpl(const T& v, const Ts&... vs) {
896 toAppend(v, getLastElement(vs...));
897 toAppendStrImpl(vs...);
898}
899
900template <class Delimiter, class T, class Tgt>
901typename std::enable_if<
902 IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type
903toAppendDelimStrImpl(const Delimiter& /* delim */, const T& v, Tgt result) {
904 toAppend(v, result);
905}
906
907template <class Delimiter, class T, class... Ts>
908typename std::enable_if<
909 sizeof...(Ts) >= 2 &&
910 IsSomeString<typename std::remove_pointer<
911 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
912toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) {
913 // we are really careful here, calling toAppend with just one element does
914 // not try to estimate space needed (as we already did that). If we call
915 // toAppend(v, delim, ....) we would do unnecesary size calculation
916 toAppend(v, detail::getLastElement(vs...));
917 toAppend(delim, detail::getLastElement(vs...));
918 toAppendDelimStrImpl(delim, vs...);
919}
920} // namespace detail
921
922/**
923 * Variadic conversion to string. Appends each element in turn.
924 * If we have two or more things to append, we will not reserve
925 * the space for them and will depend on strings exponential growth.
926 * If you just append once consider using toAppendFit which reserves
927 * the space needed (but does not have exponential as a result).
928 *
929 * Custom implementations of toAppend() can be provided in the same namespace as
930 * the type to customize printing. estimateSpaceNeed() may also be provided to
931 * avoid reallocations in toAppendFit():
932 *
933 * namespace other_namespace {
934 *
935 * template <class String>
936 * void toAppend(const OtherType&, String* out);
937 *
938 * // optional
939 * size_t estimateSpaceNeeded(const OtherType&);
940 *
941 * }
942 */
943template <class... Ts>
944typename std::enable_if<
945 sizeof...(Ts) >= 3 &&
946 IsSomeString<typename std::remove_pointer<
947 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
948toAppend(const Ts&... vs) {
949 ::folly::detail::toAppendStrImpl(vs...);
950}
951
952#ifdef _MSC_VER
953// Special case pid_t on MSVC, because it's a void* rather than an
954// integral type. We can't do a global special case because this is already
955// dangerous enough (as most pointers will implicitly convert to a void*)
956// just doing it for MSVC.
957template <class Tgt>
958void toAppend(const pid_t a, Tgt* res) {
959 toAppend(uint64_t(a), res);
960}
961#endif
962
963/**
964 * Special version of the call that preallocates exaclty as much memory
965 * as need for arguments to be stored in target. This means we are
966 * not doing exponential growth when we append. If you are using it
967 * in a loop you are aiming at your foot with a big perf-destroying
968 * bazooka.
969 * On the other hand if you are appending to a string once, this
970 * will probably save a few calls to malloc.
971 */
972template <class... Ts>
973typename std::enable_if<IsSomeString<typename std::remove_pointer<
974 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
975toAppendFit(const Ts&... vs) {
976 ::folly::detail::reserveInTarget(vs...);
977 toAppend(vs...);
978}
979
980template <class Ts>
981void toAppendFit(const Ts&) {}
982
983/**
984 * Variadic base case: do nothing.
985 */
986template <class Tgt>
987typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
988 Tgt* /* result */) {}
989
990/**
991 * Variadic base case: do nothing.
992 */
993template <class Delimiter, class Tgt>
994typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim(
995 const Delimiter& /* delim */,
996 Tgt* /* result */) {}
997
998/**
999 * 1 element: same as toAppend.
1000 */
1001template <class Delimiter, class T, class Tgt>
1002typename std::enable_if<IsSomeString<Tgt>::value>::type
1003toAppendDelim(const Delimiter& /* delim */, const T& v, Tgt* tgt) {
1004 toAppend(v, tgt);
1005}
1006
1007/**
1008 * Append to string with a delimiter in between elements. Check out
1009 * comments for toAppend for details about memory allocation.
1010 */
1011template <class Delimiter, class... Ts>
1012typename std::enable_if<
1013 sizeof...(Ts) >= 3 &&
1014 IsSomeString<typename std::remove_pointer<
1015 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
1016toAppendDelim(const Delimiter& delim, const Ts&... vs) {
1017 detail::toAppendDelimStrImpl(delim, vs...);
1018}
1019
1020/**
1021 * Detail in comment for toAppendFit
1022 */
1023template <class Delimiter, class... Ts>
1024typename std::enable_if<IsSomeString<typename std::remove_pointer<
1025 typename detail::LastElement<const Ts&...>::type>::type>::value>::type
1026toAppendDelimFit(const Delimiter& delim, const Ts&... vs) {
1027 detail::reserveInTargetDelim(delim, vs...);
1028 toAppendDelim(delim, vs...);
1029}
1030
1031template <class De, class Ts>
1032void toAppendDelimFit(const De&, const Ts&) {}
1033
1034/**
1035 * to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end
1036 * for all types.
1037 */
1038template <class Tgt, class... Ts>
1039typename std::enable_if<
1040 IsSomeString<Tgt>::value &&
1041 (sizeof...(Ts) != 1 ||
1042 !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
1043 value),
1044 Tgt>::type
1045to(const Ts&... vs) {
1046 Tgt result;
1047 toAppendFit(vs..., &result);
1048 return result;
1049}
1050
1051/**
1052 * Special version of to<SomeString> for floating point. When calling
1053 * folly::to<SomeString>(double), generic implementation above will
1054 * firstly reserve 24 (or 25 when negative value) bytes. This will
1055 * introduce a malloc call for most mainstream string implementations.
1056 *
1057 * But for most cases, a floating point doesn't need 24 (or 25) bytes to
1058 * be converted as a string.
1059 *
1060 * This special version will not do string reserve.
1061 */
1062template <class Tgt, class Src>
1063typename std::enable_if<
1064 IsSomeString<Tgt>::value && std::is_floating_point<Src>::value,
1065 Tgt>::type
1066to(Src value) {
1067 Tgt result;
1068 toAppend(value, &result);
1069 return result;
1070}
1071
1072/**
1073 * toDelim<SomeString>(SomeString str) returns itself.
1074 */
1075template <class Tgt, class Delim, class Src>
1076typename std::enable_if<
1077 IsSomeString<Tgt>::value &&
1078 std::is_same<Tgt, typename std::decay<Src>::type>::value,
1079 Tgt>::type
1080toDelim(const Delim& /* delim */, Src&& value) {
1081 return std::forward<Src>(value);
1082}
1083
1084/**
1085 * toDelim<SomeString>(delim, v1, v2, ...) uses toAppendDelim() as
1086 * back-end for all types.
1087 */
1088template <class Tgt, class Delim, class... Ts>
1089typename std::enable_if<
1090 IsSomeString<Tgt>::value &&
1091 (sizeof...(Ts) != 1 ||
1092 !std::is_same<Tgt, typename detail::LastElement<const Ts&...>::type>::
1093 value),
1094 Tgt>::type
1095toDelim(const Delim& delim, const Ts&... vs) {
1096 Tgt result;
1097 toAppendDelimFit(delim, vs..., &result);
1098 return result;
1099}
1100
1101/*******************************************************************************
1102 * Conversions from string types to integral types.
1103 ******************************************************************************/
1104
1105namespace detail {
1106
1107Expected<bool, ConversionCode> str_to_bool(StringPiece* src) noexcept;
1108
1109template <typename T>
1110Expected<T, ConversionCode> str_to_floating(StringPiece* src) noexcept;
1111
1112extern template Expected<float, ConversionCode> str_to_floating<float>(
1113 StringPiece* src) noexcept;
1114extern template Expected<double, ConversionCode> str_to_floating<double>(
1115 StringPiece* src) noexcept;
1116
1117template <class Tgt>
1118Expected<Tgt, ConversionCode> digits_to(const char* b, const char* e) noexcept;
1119
1120extern template Expected<char, ConversionCode> digits_to<char>(
1121 const char*,
1122 const char*) noexcept;
1123extern template Expected<signed char, ConversionCode> digits_to<signed char>(
1124 const char*,
1125 const char*) noexcept;
1126extern template Expected<unsigned char, ConversionCode>
1127digits_to<unsigned char>(const char*, const char*) noexcept;
1128
1129extern template Expected<short, ConversionCode> digits_to<short>(
1130 const char*,
1131 const char*) noexcept;
1132extern template Expected<unsigned short, ConversionCode>
1133digits_to<unsigned short>(const char*, const char*) noexcept;
1134
1135extern template Expected<int, ConversionCode> digits_to<int>(
1136 const char*,
1137 const char*) noexcept;
1138extern template Expected<unsigned int, ConversionCode> digits_to<unsigned int>(
1139 const char*,
1140 const char*) noexcept;
1141
1142extern template Expected<long, ConversionCode> digits_to<long>(
1143 const char*,
1144 const char*) noexcept;
1145extern template Expected<unsigned long, ConversionCode>
1146digits_to<unsigned long>(const char*, const char*) noexcept;
1147
1148extern template Expected<long long, ConversionCode> digits_to<long long>(
1149 const char*,
1150 const char*) noexcept;
1151extern template Expected<unsigned long long, ConversionCode>
1152digits_to<unsigned long long>(const char*, const char*) noexcept;
1153
1154#if FOLLY_HAVE_INT128_T
1155extern template Expected<__int128, ConversionCode> digits_to<__int128>(
1156 const char*,
1157 const char*) noexcept;
1158extern template Expected<unsigned __int128, ConversionCode>
1159digits_to<unsigned __int128>(const char*, const char*) noexcept;
1160#endif
1161
1162template <class T>
1163Expected<T, ConversionCode> str_to_integral(StringPiece* src) noexcept;
1164
1165extern template Expected<char, ConversionCode> str_to_integral<char>(
1166 StringPiece* src) noexcept;
1167extern template Expected<signed char, ConversionCode>
1168str_to_integral<signed char>(StringPiece* src) noexcept;
1169extern template Expected<unsigned char, ConversionCode>
1170str_to_integral<unsigned char>(StringPiece* src) noexcept;
1171
1172extern template Expected<short, ConversionCode> str_to_integral<short>(
1173 StringPiece* src) noexcept;
1174extern template Expected<unsigned short, ConversionCode>
1175str_to_integral<unsigned short>(StringPiece* src) noexcept;
1176
1177extern template Expected<int, ConversionCode> str_to_integral<int>(
1178 StringPiece* src) noexcept;
1179extern template Expected<unsigned int, ConversionCode>
1180str_to_integral<unsigned int>(StringPiece* src) noexcept;
1181
1182extern template Expected<long, ConversionCode> str_to_integral<long>(
1183 StringPiece* src) noexcept;
1184extern template Expected<unsigned long, ConversionCode>
1185str_to_integral<unsigned long>(StringPiece* src) noexcept;
1186
1187extern template Expected<long long, ConversionCode> str_to_integral<long long>(
1188 StringPiece* src) noexcept;
1189extern template Expected<unsigned long long, ConversionCode>
1190str_to_integral<unsigned long long>(StringPiece* src) noexcept;
1191
1192#if FOLLY_HAVE_INT128_T
1193extern template Expected<__int128, ConversionCode> str_to_integral<__int128>(
1194 StringPiece* src) noexcept;
1195extern template Expected<unsigned __int128, ConversionCode>
1196str_to_integral<unsigned __int128>(StringPiece* src) noexcept;
1197#endif
1198
1199template <typename T>
1200typename std::
1201 enable_if<std::is_same<T, bool>::value, Expected<T, ConversionCode>>::type
1202 convertTo(StringPiece* src) noexcept {
1203 return str_to_bool(src);
1204}
1205
1206template <typename T>
1207typename std::enable_if<
1208 std::is_floating_point<T>::value,
1209 Expected<T, ConversionCode>>::type
1210convertTo(StringPiece* src) noexcept {
1211 return str_to_floating<T>(src);
1212}
1213
1214template <typename T>
1215typename std::enable_if<
1216 std::is_integral<T>::value && !std::is_same<T, bool>::value,
1217 Expected<T, ConversionCode>>::type
1218convertTo(StringPiece* src) noexcept {
1219 return str_to_integral<T>(src);
1220}
1221
1222} // namespace detail
1223
1224/**
1225 * String represented as a pair of pointers to char to unsigned
1226 * integrals. Assumes NO whitespace before or after.
1227 */
1228template <typename Tgt>
1229typename std::enable_if<
1230 std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1231 Expected<Tgt, ConversionCode>>::type
1232tryTo(const char* b, const char* e) {
1233 return detail::digits_to<Tgt>(b, e);
1234}
1235
1236template <typename Tgt>
1237typename std::enable_if<
1238 std::is_integral<Tgt>::value && !std::is_same<Tgt, bool>::value,
1239 Tgt>::type
1240to(const char* b, const char* e) {
1241 return tryTo<Tgt>(b, e).thenOrThrow(
1242 [](Tgt res) { return res; },
1243 [=](ConversionCode code) {
1244 return makeConversionError(code, StringPiece(b, e));
1245 });
1246}
1247
1248/*******************************************************************************
1249 * Conversions from string types to arithmetic types.
1250 ******************************************************************************/
1251
1252/**
1253 * Parsing strings to numeric types.
1254 */
1255template <typename Tgt>
1256FOLLY_NODISCARD inline typename std::enable_if<
1257 std::is_arithmetic<Tgt>::value,
1258 Expected<StringPiece, ConversionCode>>::type
1259parseTo(StringPiece src, Tgt& out) {
1260 return detail::convertTo<Tgt>(&src).then(
1261 [&](Tgt res) { return void(out = res), src; });
1262}
1263
1264/*******************************************************************************
1265 * Integral / Floating Point to integral / Floating Point
1266 ******************************************************************************/
1267
1268namespace detail {
1269
1270/**
1271 * Bool to integral/float doesn't need any special checks, and this
1272 * overload means we aren't trying to see if a bool is less than
1273 * an integer.
1274 */
1275template <class Tgt>
1276typename std::enable_if<
1277 !std::is_same<Tgt, bool>::value &&
1278 (std::is_integral<Tgt>::value || std::is_floating_point<Tgt>::value),
1279 Expected<Tgt, ConversionCode>>::type
1280convertTo(const bool& value) noexcept {
1281 return static_cast<Tgt>(value ? 1 : 0);
1282}
1283
1284/**
1285 * Checked conversion from integral to integral. The checks are only
1286 * performed when meaningful, e.g. conversion from int to long goes
1287 * unchecked.
1288 */
1289template <class Tgt, class Src>
1290typename std::enable_if<
1291 std::is_integral<Src>::value && !std::is_same<Tgt, Src>::value &&
1292 !std::is_same<Tgt, bool>::value && std::is_integral<Tgt>::value,
1293 Expected<Tgt, ConversionCode>>::type
1294convertTo(const Src& value) noexcept {
1295 if /* constexpr */ (
1296 std::make_unsigned_t<Tgt>(std::numeric_limits<Tgt>::max()) <
1297 std::make_unsigned_t<Src>(std::numeric_limits<Src>::max())) {
1298 if (greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)) {
1299 return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1300 }
1301 }
1302 if /* constexpr */ (
1303 std::is_signed<Src>::value &&
1304 (!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) {
1305 if (less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)) {
1306 return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1307 }
1308 }
1309 return static_cast<Tgt>(value);
1310}
1311
1312/**
1313 * Checked conversion from floating to floating. The checks are only
1314 * performed when meaningful, e.g. conversion from float to double goes
1315 * unchecked.
1316 */
1317template <class Tgt, class Src>
1318typename std::enable_if<
1319 std::is_floating_point<Tgt>::value && std::is_floating_point<Src>::value &&
1320 !std::is_same<Tgt, Src>::value,
1321 Expected<Tgt, ConversionCode>>::type
1322convertTo(const Src& value) noexcept {
1323 if /* constexpr */ (
1324 std::numeric_limits<Tgt>::max() < std::numeric_limits<Src>::max()) {
1325 if (value > std::numeric_limits<Tgt>::max()) {
1326 return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW);
1327 }
1328 if (value < std::numeric_limits<Tgt>::lowest()) {
1329 return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW);
1330 }
1331 }
1332 return static_cast<Tgt>(value);
1333}
1334
1335/**
1336 * Check if a floating point value can safely be converted to an
1337 * integer value without triggering undefined behaviour.
1338 */
1339template <typename Tgt, typename Src>
1340inline typename std::enable_if<
1341 std::is_floating_point<Src>::value && std::is_integral<Tgt>::value &&
1342 !std::is_same<Tgt, bool>::value,
1343 bool>::type
1344checkConversion(const Src& value) {
1345 constexpr Src tgtMaxAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::max());
1346 constexpr Src tgtMinAsSrc = static_cast<Src>(std::numeric_limits<Tgt>::min());
1347 if (value >= tgtMaxAsSrc) {
1348 if (value > tgtMaxAsSrc) {
1349 return false;
1350 }
1351 const Src mmax = folly::nextafter(tgtMaxAsSrc, Src());
1352 if (static_cast<Tgt>(value - mmax) >
1353 std::numeric_limits<Tgt>::max() - static_cast<Tgt>(mmax)) {
1354 return false;
1355 }
1356 } else if (std::is_signed<Tgt>::value && value <= tgtMinAsSrc) {
1357 if (value < tgtMinAsSrc) {
1358 return false;
1359 }
1360 const Src mmin = folly::nextafter(tgtMinAsSrc, Src());
1361 if (static_cast<Tgt>(value - mmin) <
1362 std::numeric_limits<Tgt>::min() - static_cast<Tgt>(mmin)) {
1363 return false;
1364 }
1365 }
1366 return true;
1367}
1368
1369// Integers can always safely be converted to floating point values
1370template <typename Tgt, typename Src>
1371constexpr typename std::enable_if<
1372 std::is_integral<Src>::value && std::is_floating_point<Tgt>::value,
1373 bool>::type
1374checkConversion(const Src&) {
1375 return true;
1376}
1377
1378// Also, floating point values can always be safely converted to bool
1379// Per the standard, any floating point value that is not zero will yield true
1380template <typename Tgt, typename Src>
1381constexpr typename std::enable_if<
1382 std::is_floating_point<Src>::value && std::is_same<Tgt, bool>::value,
1383 bool>::type
1384checkConversion(const Src&) {
1385 return true;
1386}
1387
1388/**
1389 * Checked conversion from integral to floating point and back. The
1390 * result must be convertible back to the source type without loss of
1391 * precision. This seems Draconian but sometimes is what's needed, and
1392 * complements existing routines nicely. For various rounding
1393 * routines, see <math>.
1394 */
1395template <typename Tgt, typename Src>
1396typename std::enable_if<
1397 (std::is_integral<Src>::value && std::is_floating_point<Tgt>::value) ||
1398 (std::is_floating_point<Src>::value && std::is_integral<Tgt>::value),
1399 Expected<Tgt, ConversionCode>>::type
1400convertTo(const Src& value) noexcept {
1401 if (LIKELY(checkConversion<Tgt>(value))) {
1402 Tgt result = static_cast<Tgt>(value);
1403 if (LIKELY(checkConversion<Src>(result))) {
1404 Src witness = static_cast<Src>(result);
1405 if (LIKELY(value == witness)) {
1406 return result;
1407 }
1408 }
1409 }
1410 return makeUnexpected(ConversionCode::ARITH_LOSS_OF_PRECISION);
1411}
1412
1413template <typename Tgt, typename Src>
1414inline std::string errorValue(const Src& value) {
1415 return to<std::string>("(", pretty_name<Tgt>(), ") ", value);
1416}
1417
1418template <typename Tgt, typename Src>
1419using IsArithToArith = bool_constant<
1420 !std::is_same<Tgt, Src>::value && !std::is_same<Tgt, bool>::value &&
1421 std::is_arithmetic<Src>::value && std::is_arithmetic<Tgt>::value>;
1422
1423} // namespace detail
1424
1425template <typename Tgt, typename Src>
1426typename std::enable_if<
1427 detail::IsArithToArith<Tgt, Src>::value,
1428 Expected<Tgt, ConversionCode>>::type
1429tryTo(const Src& value) noexcept {
1430 return detail::convertTo<Tgt>(value);
1431}
1432
1433template <typename Tgt, typename Src>
1434typename std::enable_if<detail::IsArithToArith<Tgt, Src>::value, Tgt>::type to(
1435 const Src& value) {
1436 return tryTo<Tgt>(value).thenOrThrow(
1437 [](Tgt res) { return res; },
1438 [&](ConversionCode e) {
1439 return makeConversionError(e, detail::errorValue<Tgt>(value));
1440 });
1441}
1442
1443/*******************************************************************************
1444 * Custom Conversions
1445 *
1446 * Any type can be used with folly::to by implementing parseTo. The
1447 * implementation should be provided in the namespace of the type to facilitate
1448 * argument-dependent lookup:
1449 *
1450 * namespace other_namespace {
1451 * ::folly::Expected<::folly::StringPiece, SomeErrorCode>
1452 * parseTo(::folly::StringPiece, OtherType&) noexcept;
1453 * }
1454 ******************************************************************************/
1455template <class T>
1456FOLLY_NODISCARD typename std::enable_if<
1457 std::is_enum<T>::value,
1458 Expected<StringPiece, ConversionCode>>::type
1459parseTo(StringPiece in, T& out) noexcept {
1460 typename std::underlying_type<T>::type tmp{};
1461 auto restOrError = parseTo(in, tmp);
1462 out = static_cast<T>(tmp); // Harmless if parseTo fails
1463 return restOrError;
1464}
1465
1466FOLLY_NODISCARD
1467inline Expected<StringPiece, ConversionCode> parseTo(
1468 StringPiece in,
1469 StringPiece& out) noexcept {
1470 out = in;
1471 return StringPiece{in.end(), in.end()};
1472}
1473
1474FOLLY_NODISCARD
1475inline Expected<StringPiece, ConversionCode> parseTo(
1476 StringPiece in,
1477 std::string& out) {
1478 out.clear();
1479 out.append(in.data(), in.size()); // TODO try/catch?
1480 return StringPiece{in.end(), in.end()};
1481}
1482
1483FOLLY_NODISCARD
1484inline Expected<StringPiece, ConversionCode> parseTo(
1485 StringPiece in,
1486 fbstring& out) {
1487 out.clear();
1488 out.append(in.data(), in.size()); // TODO try/catch?
1489 return StringPiece{in.end(), in.end()};
1490}
1491
1492namespace detail {
1493template <typename Tgt>
1494using ParseToResult = decltype(parseTo(StringPiece{}, std::declval<Tgt&>()));
1495
1496struct CheckTrailingSpace {
1497 Expected<Unit, ConversionCode> operator()(StringPiece sp) const {
1498 auto e = enforceWhitespaceErr(sp);
1499 if (UNLIKELY(e != ConversionCode::SUCCESS)) {
1500 return makeUnexpected(e);
1501 }
1502 return unit;
1503 }
1504};
1505
1506template <class Error>
1507struct ReturnUnit {
1508 template <class T>
1509 constexpr Expected<Unit, Error> operator()(T&&) const {
1510 return unit;
1511 }
1512};
1513
1514// Older versions of the parseTo customization point threw on error and
1515// returned void. Handle that.
1516template <class Tgt>
1517inline typename std::enable_if<
1518 std::is_void<ParseToResult<Tgt>>::value,
1519 Expected<StringPiece, ConversionCode>>::type
1520parseToWrap(StringPiece sp, Tgt& out) {
1521 parseTo(sp, out);
1522 return StringPiece(sp.end(), sp.end());
1523}
1524
1525template <class Tgt>
1526inline typename std::enable_if<
1527 !std::is_void<ParseToResult<Tgt>>::value,
1528 ParseToResult<Tgt>>::type
1529parseToWrap(StringPiece sp, Tgt& out) {
1530 return parseTo(sp, out);
1531}
1532
1533template <typename Tgt>
1534using ParseToError = ExpectedErrorType<decltype(
1535 detail::parseToWrap(StringPiece{}, std::declval<Tgt&>()))>;
1536
1537} // namespace detail
1538
1539/**
1540 * String or StringPiece to target conversion. Accepts leading and trailing
1541 * whitespace, but no non-space trailing characters.
1542 */
1543
1544template <class Tgt>
1545inline typename std::enable_if<
1546 !std::is_same<StringPiece, Tgt>::value,
1547 Expected<Tgt, detail::ParseToError<Tgt>>>::type
1548tryTo(StringPiece src) {
1549 Tgt result{};
1550 using Error = detail::ParseToError<Tgt>;
1551 using Check = typename std::conditional<
1552 std::is_arithmetic<Tgt>::value,
1553 detail::CheckTrailingSpace,
1554 detail::ReturnUnit<Error>>::type;
1555 return parseTo(src, result).then(Check(), [&](Unit) {
1556 return std::move(result);
1557 });
1558}
1559
1560template <class Tgt, class Src>
1561inline typename std::enable_if<
1562 IsSomeString<Src>::value && !std::is_same<StringPiece, Tgt>::value,
1563 Tgt>::type
1564to(Src const& src) {
1565 return to<Tgt>(StringPiece(src.data(), src.size()));
1566}
1567
1568template <class Tgt>
1569inline
1570 typename std::enable_if<!std::is_same<StringPiece, Tgt>::value, Tgt>::type
1571 to(StringPiece src) {
1572 Tgt result{};
1573 using Error = detail::ParseToError<Tgt>;
1574 using Check = typename std::conditional<
1575 std::is_arithmetic<Tgt>::value,
1576 detail::CheckTrailingSpace,
1577 detail::ReturnUnit<Error>>::type;
1578 auto tmp = detail::parseToWrap(src, result);
1579 return tmp
1580 .thenOrThrow(
1581 Check(),
1582 [&](Error e) { throw_exception(makeConversionError(e, src)); })
1583 .thenOrThrow(
1584 [&](Unit) { return std::move(result); },
1585 [&](Error e) {
1586 throw_exception(makeConversionError(e, tmp.value()));
1587 });
1588}
1589
1590/**
1591 * tryTo/to that take the strings by pointer so the caller gets information
1592 * about how much of the string was consumed by the conversion. These do not
1593 * check for trailing whitepsace.
1594 */
1595template <class Tgt>
1596Expected<Tgt, detail::ParseToError<Tgt>> tryTo(StringPiece* src) {
1597 Tgt result;
1598 return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt {
1599 *src = sp;
1600 return std::move(result);
1601 });
1602}
1603
1604template <class Tgt>
1605Tgt to(StringPiece* src) {
1606 Tgt result{};
1607 using Error = detail::ParseToError<Tgt>;
1608 return parseTo(*src, result)
1609 .thenOrThrow(
1610 [&, src](StringPiece sp) -> Tgt {
1611 *src = sp;
1612 return std::move(result);
1613 },
1614 [=](Error e) { return makeConversionError(e, *src); });
1615}
1616
1617/*******************************************************************************
1618 * Enum to anything and back
1619 ******************************************************************************/
1620
1621template <class Tgt, class Src>
1622typename std::enable_if<
1623 std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1624 !std::is_convertible<Tgt, StringPiece>::value,
1625 Expected<Tgt, ConversionCode>>::type
1626tryTo(const Src& value) {
1627 return tryTo<Tgt>(to_underlying(value));
1628}
1629
1630template <class Tgt, class Src>
1631typename std::enable_if<
1632 !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1633 !std::is_same<Src, Tgt>::value,
1634 Expected<Tgt, ConversionCode>>::type
1635tryTo(const Src& value) {
1636 using I = typename std::underlying_type<Tgt>::type;
1637 return tryTo<I>(value).then([](I i) { return static_cast<Tgt>(i); });
1638}
1639
1640template <class Tgt, class Src>
1641typename std::enable_if<
1642 std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value &&
1643 !std::is_convertible<Tgt, StringPiece>::value,
1644 Tgt>::type
1645to(const Src& value) {
1646 return to<Tgt>(to_underlying(value));
1647}
1648
1649template <class Tgt, class Src>
1650typename std::enable_if<
1651 !std::is_convertible<Src, StringPiece>::value && std::is_enum<Tgt>::value &&
1652 !std::is_same<Src, Tgt>::value,
1653 Tgt>::type
1654to(const Src& value) {
1655 return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
1656}
1657
1658} // namespace folly
1659