X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FConv.h;h=20cf3d51b2fe84c208014bf30732e129a211c95a;hp=9fc196965763bfddcfb997c1f1e4b781abd2637c;hb=37af03980d1e36c1417998d7df2edbf6f182f07a;hpb=89cc32931877aa684e1a1f06776f564a49d39eab diff --git a/folly/Conv.h b/folly/Conv.h index 9fc19696..20cf3d51 100644 --- a/folly/Conv.h +++ b/folly/Conv.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -187,6 +188,33 @@ to(const Src& value) { namespace detail { +#ifdef _MSC_VER +// MSVC can't quite figure out the LastElementImpl::call() stuff +// in the base implementation, so we have to use tuples instead, +// which result in significantly more templates being compiled, +// though the runtime performance is the same. + +template +auto getLastElement(Ts&&... ts) -> decltype( + std::get(std::forward_as_tuple(std::forward(ts)...))) { + return std::get( + std::forward_as_tuple(std::forward(ts)...)); +} + +inline void getLastElement() {} + +template +struct LastElementType : std::tuple_element> {}; + +template <> +struct LastElementType<0> { + using type = void; +}; + +template +struct LastElement + : std::decay::type> {}; +#else template struct LastElementImpl { static void call(Ignored...) {} @@ -210,6 +238,7 @@ template struct LastElement : std::decay::call(std::declval()...))> { }; +#endif } // namespace detail @@ -354,12 +383,12 @@ inline uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer) { // Keep these together so a peephole optimization "sees" them and // computes them in one shot. auto const q = v / 10; - auto const r = static_cast(v % 10); + auto const r = static_cast(v % 10); buffer[pos--] = '0' + r; v = q; } // Last digit is trivial to handle - buffer[pos] = static_cast(v) + '0'; + buffer[pos] = static_cast(v) + '0'; return result; } @@ -528,9 +557,10 @@ toAppend(Src value, Tgt * result) { char buffer[20]; if (value < 0) { result->push_back('-'); - result->append(buffer, uint64ToBufferUnsafe(-uint64_t(value), buffer)); + result->append( + buffer, uint64ToBufferUnsafe(uint64_t(-uint64_t(value)), buffer)); } else { - result->append(buffer, uint64ToBufferUnsafe(value, buffer)); + result->append(buffer, uint64ToBufferUnsafe(uint64_t(value), buffer)); } } @@ -652,14 +682,14 @@ toAppend( conv.ToShortest(value, &builder); break; case DoubleToStringConverter::FIXED: - conv.ToFixed(value, numDigits, &builder); + conv.ToFixed(value, int(numDigits), &builder); break; default: CHECK(mode == DoubleToStringConverter::PRECISION); - conv.ToPrecision(value, numDigits, &builder); + conv.ToPrecision(value, int(numDigits), &builder); break; } - const size_t length = builder.position(); + const size_t length = size_t(builder.position()); builder.Finalize(); result->append(buffer, length); } @@ -701,7 +731,9 @@ estimateSpaceNeeded(Src value) { // so 21 is the longest non-exponential number > 1. detail::kConvMaxDecimalInShortestHigh }); - return kMaxPositiveSpace + (value < 0); // +1 for minus sign, if negative + return size_t( + kMaxPositiveSpace + + (value < 0 ? 1 : 0)); // +1 for minus sign, if negative } /** @@ -928,6 +960,27 @@ to(const Ts&... vs) { return result; } +/** + * Special version of to for floating point. When calling + * folly::to(double), generic implementation above will + * firstly reserve 24 (or 25 when negative value) bytes. This will + * introduce a malloc call for most mainstream string implementations. + * + * But for most cases, a floating point doesn't need 24 (or 25) bytes to + * be converted as a string. + * + * This special version will not do string reserve. + */ +template +typename std::enable_if< + IsSomeString::value && std::is_floating_point::value, + Tgt>::type +to(Src value) { + Tgt result; + toAppend(value, &result); + return result; +} + /** * toDelim(SomeString str) returns itself. */ @@ -1125,6 +1178,19 @@ parseTo(StringPiece src, Tgt& out) { namespace detail { +/** + * Bool to integral doesn't need any special checks, and this + * overload means we aren't trying to see if a bool is less than + * an integer. + */ +template +typename std::enable_if< + !std::is_same::value && std::is_integral::value, + Expected>::type +convertTo(const bool& value) noexcept { + return static_cast(value ? 1 : 0); +} + /** * Checked conversion from integral to integral. The checks are only * performed when meaningful, e.g. conversion from int to long goes @@ -1138,7 +1204,8 @@ typename std::enable_if< Expected>::type convertTo(const Src& value) noexcept { /* static */ if ( - std::numeric_limits::max() < std::numeric_limits::max()) { + folly::_t>(std::numeric_limits::max()) < + folly::_t>(std::numeric_limits::max())) { if (greater_than::max()>(value)) { return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW); } @@ -1173,7 +1240,7 @@ convertTo(const Src& value) noexcept { return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); } } - return boost::implicit_cast(value); + return static_cast(value); } /** @@ -1440,7 +1507,7 @@ Expected> tryTo(StringPiece* src) { template Tgt to(StringPiece* src) { - Tgt result; + Tgt result{}; using Error = detail::ParseToError; return parseTo(*src, result) .thenOrThrow(