react-native-windows 0.73.20 → 0.73.22

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