1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UTIL_INTEGER_DIVISION_H_
6 #define UTIL_INTEGER_DIVISION_H_
7 
8 #include <type_traits>
9 
10 namespace openscreen {
11 
12 // Returns CEIL(num ÷ denom). |denom| must not equal zero. This function is
13 // compatible with any integer-like type, including the integer-based
14 // std::chrono duration types.
15 //
16 // Optimization note: See DividePositivesRoundingUp().
17 template <typename Integer>
DivideRoundingUp(Integer num,Integer denom)18 constexpr auto DivideRoundingUp(Integer num, Integer denom) {
19   if (denom < Integer{0}) {
20     num *= -1;
21     denom *= -1;
22   }
23   if (num < Integer{0}) {
24     return num / denom;
25   }
26   return (num + denom - Integer{1}) / denom;
27 }
28 
29 // Same as DivideRoundingUp(), except is more-efficient for hot code paths that
30 // know |num| is always greater or equal to zero, and |denom| is always greater
31 // than zero.
32 template <typename Integer>
DividePositivesRoundingUp(Integer num,Integer denom)33 constexpr Integer DividePositivesRoundingUp(Integer num, Integer denom) {
34   return DivideRoundingUp<typename std::make_unsigned<Integer>::type>(num,
35                                                                       denom);
36 }
37 
38 // Divides |num| by |denom|, and rounds to the nearest integer (exactly halfway
39 // between integers will round to the higher integer). This function is
40 // compatible with any integer-like type, including the integer-based
41 // std::chrono duration types.
42 //
43 // Optimization note: See DividePositivesRoundingNearest().
44 template <typename Integer>
DivideRoundingNearest(Integer num,Integer denom)45 constexpr auto DivideRoundingNearest(Integer num, Integer denom) {
46   if (denom < Integer{0}) {
47     num *= -1;
48     denom *= -1;
49   }
50   if (num < Integer{0}) {
51     return (num - ((denom - Integer{1}) / 2)) / denom;
52   }
53   return (num + (denom / 2)) / denom;
54 }
55 
56 // Same as DivideRoundingNearest(), except is more-efficient for hot code paths
57 // that know |num| is always greater or equal to zero, and |denom| is always
58 // greater than zero.
59 template <typename Integer>
DividePositivesRoundingNearest(Integer num,Integer denom)60 constexpr Integer DividePositivesRoundingNearest(Integer num, Integer denom) {
61   return DivideRoundingNearest<typename std::make_unsigned<Integer>::type>(
62       num, denom);
63 }
64 
65 }  // namespace openscreen
66 
67 #endif  // UTIL_INTEGER_DIVISION_H_
68