Commit 5ec7c712 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

to_signed and to_unsigned

Summary:
[Folly] `to_signed` and `to_unsigned`, for casting a value to the signed or unsigned version of the value's type.

And use them in time conversion functions.

Reviewed By: markw65

Differential Revision: D7020215

fbshipit-source-id: 47a6aeeea487cd7d59d23e7ded40cc66dcc57c52
parent 1ea94b5e
......@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
......@@ -364,4 +365,20 @@ using MoveOnly = moveonly_::MoveOnly;
template <bool B>
using Bool = std::integral_constant<bool, B>;
template <typename T>
constexpr auto to_signed(T const& t) -> typename std::make_signed<T>::type {
using S = typename std::make_signed<T>::type;
// note: static_cast<S>(t) would be more straightforward, but it would also be
// implementation-defined behavior and that is typically to be avoided; the
// following code optimized into the same thing, though
constexpr auto const s = std::numeric_limits<S>::max();
return s < t ? -static_cast<S>(~t) + S{-1} : static_cast<S>(t);
}
template <typename T>
constexpr auto to_unsigned(T const& t) -> typename std::make_unsigned<T>::type {
using U = typename std::make_unsigned<T>::type;
return static_cast<U>(t);
}
} // namespace folly
......@@ -283,8 +283,7 @@ struct CheckOverflowToDuration {
constexpr auto maxCount = std::numeric_limits<typename Tgt::rep>::max();
constexpr auto maxSeconds = maxCount / Tgt::period::den;
auto unsignedSeconds =
static_cast<typename std::make_unsigned<Seconds>::type>(seconds);
auto unsignedSeconds = to_unsigned(seconds);
if (LIKELY(unsignedSeconds < maxSeconds)) {
return ConversionCode::SUCCESS;
}
......@@ -297,8 +296,7 @@ struct CheckOverflowToDuration {
if (subseconds <= 0) {
return ConversionCode::SUCCESS;
}
if (static_cast<typename std::make_unsigned<Subseconds>::type>(
subseconds) <= maxSubseconds) {
if (to_unsigned(subseconds) <= maxSubseconds) {
return ConversionCode::SUCCESS;
}
}
......@@ -307,8 +305,7 @@ struct CheckOverflowToDuration {
return ConversionCode::NEGATIVE_OVERFLOW;
} else {
constexpr auto minCount =
static_cast<typename std::make_signed<typename Tgt::rep>::type>(
std::numeric_limits<typename Tgt::rep>::lowest());
to_signed(std::numeric_limits<typename Tgt::rep>::lowest());
constexpr auto minSeconds = (minCount / Tgt::period::den);
if (LIKELY(seconds >= minSeconds)) {
return ConversionCode::SUCCESS;
......
......@@ -119,3 +119,29 @@ TEST_F(UtilityTest, MoveOnly) {
std::is_nothrow_move_constructible<FooBar>::value,
"Should have noexcept move constructor");
}
TEST_F(UtilityTest, to_signed) {
{
constexpr auto actual = folly::to_signed(int32_t(-12));
EXPECT_TRUE(std::is_signed<decltype(actual)>::value);
EXPECT_EQ(-12, actual);
}
{
constexpr auto actual = folly::to_signed(uint32_t(-12));
EXPECT_TRUE(std::is_signed<decltype(actual)>::value);
EXPECT_EQ(-12, actual);
}
}
TEST_F(UtilityTest, to_unsigned) {
{
constexpr auto actual = folly::to_unsigned(int32_t(-12));
EXPECT_TRUE(!std::is_signed<decltype(actual)>::value);
EXPECT_EQ(-12, actual);
}
{
constexpr auto actual = folly::to_unsigned(uint32_t(-12));
EXPECT_TRUE(!std::is_signed<decltype(actual)>::value);
EXPECT_EQ(-12, actual);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment