Commit cf93e807 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot 1

constexpr_abs

Summary:
[Folly] `constexpr_abs`.

Is `constexpr`.

Works over integral and floating types.

If given an integral type, the return type is the usigned version of that integral type, thereby avoiding the undefined behavior of `std::abs(std::numeric_limits<int>::min())`.

Reviewed By: simpkins

Differential Revision: D3654072

fbshipit-source-id: 24fefc0c3b055f78ba3e07472c38fb9c550e0f31
parent b26ef8ac
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <type_traits>
namespace folly { namespace folly {
...@@ -31,6 +32,49 @@ constexpr T constexpr_min(T a, T b) { ...@@ -31,6 +32,49 @@ constexpr T constexpr_min(T a, T b) {
return a < b ? a : b; return a < b ? a : b;
} }
namespace detail {
template <typename T, typename = void>
struct constexpr_abs_helper {};
template <typename T>
struct constexpr_abs_helper<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type> {
static constexpr T go(T t) {
return t < static_cast<T>(0) ? -t : t;
}
};
template <typename T>
struct constexpr_abs_helper<
T,
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value &&
std::is_unsigned<T>::value>::type> {
static constexpr T go(T t) {
return t;
}
};
template <typename T>
struct constexpr_abs_helper<
T,
typename std::enable_if<
std::is_integral<T>::value && !std::is_same<T, bool>::value &&
std::is_signed<T>::value>::type> {
static constexpr typename std::make_unsigned<T>::type go(T t) {
return t < static_cast<T>(0) ? -t : t;
}
};
}
template <typename T>
constexpr auto constexpr_abs(T t)
-> decltype(detail::constexpr_abs_helper<T>::go(t)) {
return detail::constexpr_abs_helper<T>::go(t);
}
#ifdef _MSC_VER #ifdef _MSC_VER
constexpr size_t constexpr_strlen_internal(const char* s, size_t len) { constexpr size_t constexpr_strlen_internal(const char* s, size_t len) {
return *s == '\0' ? len : constexpr_strlen_internal(s + 1, len + 1); return *s == '\0' ? len : constexpr_strlen_internal(s + 1, len + 1);
......
/*
* Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/portability/Constexpr.h>
#include <gtest/gtest.h>
namespace {
class ConstexprTest : public testing::Test {};
}
TEST_F(ConstexprTest, constexpr_abs_unsigned) {
constexpr auto v = uint32_t(17);
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17, a);
EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_signed_positive) {
constexpr auto v = int32_t(17);
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17, a);
EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_signed_negative) {
constexpr auto v = int32_t(-17);
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17, a);
EXPECT_TRUE((std::is_same<const uint32_t, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_float_positive) {
constexpr auto v = 17.5f;
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17.5, a);
EXPECT_TRUE((std::is_same<const float, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_float_negative) {
constexpr auto v = -17.5f;
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17.5, a);
EXPECT_TRUE((std::is_same<const float, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_double_positive) {
constexpr auto v = 17.5;
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17.5, a);
EXPECT_TRUE((std::is_same<const double, decltype(a)>::value));
}
TEST_F(ConstexprTest, constexpr_abs_double_negative) {
constexpr auto v = -17.5;
constexpr auto a = folly::constexpr_abs(v);
EXPECT_EQ(17.5, a);
EXPECT_TRUE((std::is_same<const double, decltype(a)>::value));
}
...@@ -237,6 +237,10 @@ portability_time_test_SOURCES = ../portability/test/TimeTest.cpp ...@@ -237,6 +237,10 @@ portability_time_test_SOURCES = ../portability/test/TimeTest.cpp
portability_time_test_LDADD = libfollytestmain.la portability_time_test_LDADD = libfollytestmain.la
TESTS += portability_time_test TESTS += portability_time_test
portability_constexpr_test_SOURCES = ../portability/test/ConstexprTest.cpp
portability_constexpr_test_LDADD = libfollytestmain.la
TESTS += portability_constexpr_test
try_test_SOURCES = TryTest.cpp try_test_SOURCES = TryTest.cpp
try_test_LDADD = libfollytestmain.la try_test_LDADD = libfollytestmain.la
TESTS += try_test TESTS += try_test
......
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