/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ /** * Some arithmetic functions that seem to pop up or get hand-rolled a lot. * So far they are all focused on integer division. */ #pragma once #include <stdint.h> #include <cmath> #include <limits> #include <type_traits> namespace folly { namespace detail { template <typename T> inline constexpr T divFloorBranchless(T num, T denom) { … } template <typename T> inline constexpr T divFloorBranchful(T num, T denom) { … } template <typename T> inline constexpr T divCeilBranchless(T num, T denom) { … } template <typename T> inline constexpr T divCeilBranchful(T num, T denom) { … } template <typename T> inline constexpr T divRoundAwayBranchless(T num, T denom) { … } template <typename T> inline constexpr T divRoundAwayBranchful(T num, T denom) { … } IdivResultType; } // namespace detail #if defined(__arm__) && !FOLLY_AARCH64 constexpr auto kIntegerDivisionGivesRemainder = false; #else constexpr auto kIntegerDivisionGivesRemainder = …; #endif /** * Returns num/denom, rounded toward negative infinity. Put another way, * returns the largest integral value that is less than or equal to the * exact (not rounded) fraction num/denom. * * The matching remainder (num - divFloor(num, denom) * denom) can be * negative only if denom is negative, unlike in truncating division. * Note that for unsigned types this is the same as the normal integer * division operator. divFloor is equivalent to python's integral division * operator //. * * This function undergoes the same integer promotion rules as a * built-in operator, except that we don't allow bool -> int promotion. * This function is undefined if denom == 0. It is also undefined if the * result type T is a signed type, num is std::numeric_limits<T>::min(), * and denom is equal to -1 after conversion to the result type. */ template <typename N, typename D> inline constexpr detail::IdivResultType<N, D> divFloor(N num, D denom) { … } /** * Returns num/denom, rounded toward positive infinity. Put another way, * returns the smallest integral value that is greater than or equal to * the exact (not rounded) fraction num/denom. * * This function undergoes the same integer promotion rules as a * built-in operator, except that we don't allow bool -> int promotion. * This function is undefined if denom == 0. It is also undefined if the * result type T is a signed type, num is std::numeric_limits<T>::min(), * and denom is equal to -1 after conversion to the result type. */ template <typename N, typename D> inline constexpr detail::IdivResultType<N, D> divCeil(N num, D denom) { … } /** * Returns num/denom, rounded toward zero. If num and denom are non-zero * and have different signs (so the unrounded fraction num/denom is * negative), returns divCeil, otherwise returns divFloor. If T is an * unsigned type then this is always equal to divFloor. * * Note that this is the same as the normal integer division operator, * at least since C99 (before then the rounding for negative results was * implementation defined). This function is here for completeness and * as a place to hang this comment. * * This function undergoes the same integer promotion rules as a * built-in operator, except that we don't allow bool -> int promotion. * This function is undefined if denom == 0. It is also undefined if the * result type T is a signed type, num is std::numeric_limits<T>::min(), * and denom is equal to -1 after conversion to the result type. */ template <typename N, typename D> inline constexpr detail::IdivResultType<N, D> divTrunc(N num, D denom) { … } /** * Returns num/denom, rounded away from zero. If num and denom are * non-zero and have different signs (so the unrounded fraction num/denom * is negative), returns divFloor, otherwise returns divCeil. If T is * an unsigned type then this is always equal to divCeil. * * This function undergoes the same integer promotion rules as a * built-in operator, except that we don't allow bool -> int promotion. * This function is undefined if denom == 0. It is also undefined if the * result type T is a signed type, num is std::numeric_limits<T>::min(), * and denom is equal to -1 after conversion to the result type. */ template <typename N, typename D> inline constexpr detail::IdivResultType<N, D> divRoundAway(N num, D denom) { … } // clang-format off // Disabling clang-formatting for midpoint to retain 1:1 correlation // with LLVM // midpoint // // mimic: std::numeric::midpoint, C++20 // from: // https://github.com/llvm/llvm-project/blob/llvmorg-11.0.0/libcxx/include/numeric, // Apache 2.0 with LLVM exceptions template <class _Tp> constexpr std::enable_if_t< std::is_integral<_Tp>::value && !std::is_same<bool, _Tp>::value && !std::is_null_pointer<_Tp>::value, _Tp> midpoint(_Tp __a, _Tp __b) noexcept { … } template <class _TPtr> constexpr std::enable_if_t< std::is_pointer<_TPtr>::value && std::is_object<std::remove_pointer_t<_TPtr>>::value && !std::is_void<std::remove_pointer_t<_TPtr>>::value && (sizeof(std::remove_pointer_t<_TPtr>) > 0), _TPtr> midpoint(_TPtr __a, _TPtr __b) noexcept { … } template <class _Fp> constexpr std::enable_if_t<std::is_floating_point<_Fp>::value, _Fp> midpoint( _Fp __a, _Fp __b) noexcept { … } // clang-format on } // namespace folly