From: Yedidya Feldblum Date: Tue, 9 Aug 2016 02:46:27 +0000 (-0700) Subject: constexpr_abs X-Git-Tag: v2016.08.15.00~35 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cf93e8078003574f8b48d411383098d52ba0c642;p=folly.git 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::min())`. Reviewed By: simpkins Differential Revision: D3654072 fbshipit-source-id: 24fefc0c3b055f78ba3e07472c38fb9c550e0f31 --- diff --git a/folly/portability/Constexpr.h b/folly/portability/Constexpr.h index 3625e265..16b6458f 100755 --- a/folly/portability/Constexpr.h +++ b/folly/portability/Constexpr.h @@ -18,6 +18,7 @@ #include #include +#include namespace folly { @@ -31,6 +32,49 @@ constexpr T constexpr_min(T a, T b) { return a < b ? a : b; } +namespace detail { + +template +struct constexpr_abs_helper {}; + +template +struct constexpr_abs_helper< + T, + typename std::enable_if::value>::type> { + static constexpr T go(T t) { + return t < static_cast(0) ? -t : t; + } +}; + +template +struct constexpr_abs_helper< + T, + typename std::enable_if< + std::is_integral::value && !std::is_same::value && + std::is_unsigned::value>::type> { + static constexpr T go(T t) { + return t; + } +}; + +template +struct constexpr_abs_helper< + T, + typename std::enable_if< + std::is_integral::value && !std::is_same::value && + std::is_signed::value>::type> { + static constexpr typename std::make_unsigned::type go(T t) { + return t < static_cast(0) ? -t : t; + } +}; +} + +template +constexpr auto constexpr_abs(T t) + -> decltype(detail::constexpr_abs_helper::go(t)) { + return detail::constexpr_abs_helper::go(t); +} + #ifdef _MSC_VER constexpr size_t constexpr_strlen_internal(const char* s, size_t len) { return *s == '\0' ? len : constexpr_strlen_internal(s + 1, len + 1); diff --git a/folly/portability/test/ConstexprTest.cpp b/folly/portability/test/ConstexprTest.cpp new file mode 100644 index 00000000..1bf74382 --- /dev/null +++ b/folly/portability/test/ConstexprTest.cpp @@ -0,0 +1,73 @@ +/* + * 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 + +#include + +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::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::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::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::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::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::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::value)); +} diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index f478ab7e..447ba586 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -237,6 +237,10 @@ portability_time_test_SOURCES = ../portability/test/TimeTest.cpp portability_time_test_LDADD = libfollytestmain.la 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_LDADD = libfollytestmain.la TESTS += try_test