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