X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FConv.h;h=a545816d327307ff460b7d99cd91a388115fc562;hb=a335700fba3a818043d53de320711dc97b680894;hp=468d33cb08a74d467b9ed9366499f30aa87dc88e;hpb=1675b8959037b2e0c038866c2e5fb60e0ef2e305;p=folly.git diff --git a/folly/Conv.h b/folly/Conv.h index 468d33cb..a545816d 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 @@ -132,7 +133,7 @@ inline void enforceWhitespace(StringPiece sp) { throw makeConversionError(err, sp); } } -} +} // namespace detail /** * The identity conversion function. @@ -282,7 +283,7 @@ unsafeTelescope128(char * buffer, size_t room, unsigned __int128 x) { return p; } -} +} // namespace detail #endif /** @@ -382,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; } @@ -399,7 +400,7 @@ void toAppend(char value, Tgt * result) { *result += value; } -template +template constexpr typename std::enable_if< std::is_same::value, size_t>::type @@ -407,6 +408,11 @@ estimateSpaceNeeded(T) { return 1; } +template +constexpr size_t estimateSpaceNeeded(const char (&)[N]) { + return N; +} + /** * Everything implicitly convertible to const char* gets appended. */ @@ -434,12 +440,18 @@ typename std::enable_if::value, size_t>:: return 0; } -template +template +typename std::enable_if::value, size_t>::type +estimateSpaceNeeded(Src const& value) { + return value.size(); +} + +template typename std::enable_if< - (std::is_convertible::value || - IsSomeString::value) && - !std::is_convertible::value, - size_t>::type + std::is_convertible::value && + !IsSomeString::value && + !std::is_convertible::value, + size_t>::type estimateSpaceNeeded(Src value) { return folly::StringPiece(value).size(); } @@ -449,7 +461,7 @@ inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) { return 0; } -template +template typename std::enable_if< std::is_pointer::value && IsSomeString>::value, @@ -522,7 +534,7 @@ toAppend(unsigned __int128 value, Tgt * result) { result->append(buffer + p, buffer + sizeof(buffer)); } -template +template constexpr typename std::enable_if< std::is_same::value, size_t>::type @@ -530,7 +542,7 @@ estimateSpaceNeeded(T) { return detail::digitsEnough<__int128>(); } -template +template constexpr typename std::enable_if< std::is_same::value, size_t>::type @@ -556,9 +568,11 @@ 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(~static_cast(value) + 1, buffer)); } else { - result->append(buffer, uint64ToBufferUnsafe(value, buffer)); + result->append(buffer, uint64ToBufferUnsafe(uint64_t(value), buffer)); } } @@ -653,7 +667,7 @@ estimateSpaceNeeded(Src value) { namespace detail { constexpr int kConvMaxDecimalInShortestLow = -6; constexpr int kConvMaxDecimalInShortestHigh = 21; -} // folly::detail +} // namespace detail /** Wrapper around DoubleToStringConverter **/ template @@ -680,14 +694,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); } @@ -729,7 +743,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 } /** @@ -737,7 +753,7 @@ estimateSpaceNeeded(Src value) { * for estimateSpaceNeed for your type, so that we allocate * as much as you need instead of the default */ -template +template struct HasLengthEstimator : std::false_type {}; template @@ -771,12 +787,12 @@ size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) { return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...); } -template +template void reserveInTarget(const Ts&...vs) { getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...)); } -template +template void reserveInTargetDelim(const Delimiter& d, const Ts&...vs) { static_assert(sizeof...(vs) >= 2, "Needs at least 2 args"); size_t fordelim = (sizeof...(vs) - 2) * @@ -825,8 +841,7 @@ toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) { toAppend(delim, detail::getLastElement(vs...)); toAppendDelimStrImpl(delim, vs...); } -} // folly::detail - +} // namespace detail /** * Variadic conversion to string. Appends each element in turn. @@ -981,11 +996,12 @@ to(Src value) { * toDelim(SomeString str) returns itself. */ template -typename std::enable_if::value && - std::is_same::value, - Tgt>::type -toDelim(const Delim& /* delim */, const Src& value) { - return value; +typename std::enable_if< + IsSomeString::value && + std::is_same::type>::value, + Tgt>::type +toDelim(const Delim& /* delim */, Src&& value) { + return std::forward(value); } /** @@ -1160,7 +1176,7 @@ to(const char* b, const char* e) { * Parsing strings to numeric types. */ template -FOLLY_WARN_UNUSED_RESULT inline typename std::enable_if< +FOLLY_NODISCARD inline typename std::enable_if< std::is_arithmetic::value, Expected>::type parseTo(StringPiece src, Tgt& out) { @@ -1174,6 +1190,20 @@ parseTo(StringPiece src, Tgt& out) { namespace detail { +/** + * Bool to integral/float 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 || std::is_floating_point::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 @@ -1187,7 +1217,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); } @@ -1222,7 +1253,7 @@ convertTo(const Src& value) noexcept { return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); } } - return boost::implicit_cast(value); + return static_cast(value); } /** @@ -1352,7 +1383,7 @@ typename std::enable_if::value, Tgt>::type to( * } ******************************************************************************/ template -FOLLY_WARN_UNUSED_RESULT typename std::enable_if< +FOLLY_NODISCARD typename std::enable_if< std::is_enum::value, Expected>::type parseTo(StringPiece in, T& out) noexcept { @@ -1362,7 +1393,7 @@ parseTo(StringPiece in, T& out) noexcept { return restOrError; } -FOLLY_WARN_UNUSED_RESULT +FOLLY_NODISCARD inline Expected parseTo( StringPiece in, StringPiece& out) noexcept { @@ -1370,7 +1401,7 @@ inline Expected parseTo( return StringPiece{in.end(), in.end()}; } -FOLLY_WARN_UNUSED_RESULT +FOLLY_NODISCARD inline Expected parseTo( StringPiece in, std::string& out) { @@ -1379,7 +1410,7 @@ inline Expected parseTo( return StringPiece{in.end(), in.end()}; } -FOLLY_WARN_UNUSED_RESULT +FOLLY_NODISCARD inline Expected parseTo( StringPiece in, fbstring& out) { @@ -1395,8 +1426,9 @@ using ParseToResult = decltype(parseTo(StringPiece{}, std::declval())); struct CheckTrailingSpace { Expected operator()(StringPiece sp) const { auto e = enforceWhitespaceErr(sp); - if (UNLIKELY(e != ConversionCode::SUCCESS)) + if (UNLIKELY(e != ConversionCode::SUCCESS)) { return makeUnexpected(e); + } return unit; } }; @@ -1455,6 +1487,14 @@ tryTo(StringPiece src) { }); } +template +inline typename std::enable_if< + IsSomeString::value && !std::is_same::value, + Tgt>::type +to(Src const& src) { + return to(StringPiece(src.data(), src.size())); +} + template inline typename std::enable_if::value, Tgt>::type @@ -1489,7 +1529,7 @@ Expected> tryTo(StringPiece* src) { template Tgt to(StringPiece* src) { - Tgt result; + Tgt result{}; using Error = detail::ParseToError; return parseTo(*src, result) .thenOrThrow( @@ -1506,7 +1546,8 @@ Tgt to(StringPiece* src) { template typename std::enable_if< - std::is_enum::value && !std::is_same::value, + std::is_enum::value && !std::is_same::value && + !std::is_convertible::value, Expected>::type tryTo(const Src& value) { using I = typename std::underlying_type::type; @@ -1515,8 +1556,9 @@ tryTo(const Src& value) { template typename std::enable_if< - std::is_enum::value && !std::is_same::value, - Tgt>::type + !std::is_convertible::valuea && + std::is_enum::value && !std::is_same::value, + Expected>::type tryTo(const Src& value) { using I = typename std::underlying_type::type; return tryTo(value).then([](I i) { return static_cast(i); }); @@ -1524,7 +1566,8 @@ tryTo(const Src& value) { template typename std::enable_if< - std::is_enum::value && !std::is_same::value, + std::is_enum::value && !std::is_same::value && + !std::is_convertible::value, Tgt>::type to(const Src& value) { return to(static_cast::type>(value)); @@ -1532,8 +1575,10 @@ to(const Src& value) { template typename std::enable_if< - std::is_enum::value && !std::is_same::value, Tgt>::type -to(const Src & value) { + !std::is_convertible::value && std::is_enum::value && + !std::is_same::value, + Tgt>::type +to(const Src& value) { return static_cast(to::type>(value)); }