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