Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(379)

Side by Side Diff: mojo/services/media/common/cpp/ratio.cc

Issue 1952673003: Motown: Rename Ratio and LinearFunction classes (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 #include <limits>
6 #include <utility>
7
8 #include "mojo/public/cpp/environment/logging.h"
9 #include "mojo/services/media/common/cpp/ratio.h"
10
11 namespace mojo {
12 namespace media {
13
14 namespace {
15
16 // Calculates the greatest common denominator (factor) of two values.
17 template <typename T>
18 T BinaryGcd(T a, T b) {
19 if (a == 0) {
20 return b;
21 }
22
23 if (b == 0) {
24 return a;
25 }
26
27 // Remove and count the common factors of 2.
28 uint8_t twos;
29 for (twos = 0; ((a | b) & 1) == 0; ++twos) {
30 a >>= 1;
31 b >>= 1;
32 }
33
34 // Get rid of the non-common factors of 2 in a. a is non-zero, so this
35 // terminates.
36 while ((a & 1) == 0) {
37 a >>= 1;
38 }
39
40 do {
41 // Get rid of the non-common factors of 2 in b. b is non-zero, so this
42 // terminates.
43 while ((b & 1) == 0) {
44 b >>= 1;
45 }
46
47 // Apply the Euclid subtraction method.
48 if (a > b) {
49 std::swap(a, b);
50 }
51
52 b = b - a;
53 } while (b != 0);
54
55 // Multiply in the common factors of two.
56 return a << twos;
57 }
58
59 // Reduces the ration of *numerator and *denominator.
60 template <typename T>
61 void ReduceRatio(T* numerator, T* denominator) {
62 MOJO_DCHECK(numerator != nullptr);
63 MOJO_DCHECK(denominator != nullptr);
64 MOJO_DCHECK(*denominator != 0);
65
66 T gcd = BinaryGcd(*numerator, *denominator);
67
68 if (gcd == 0) {
69 *denominator = 1;
70 return;
71 }
72
73 if (gcd == 1) {
74 return;
75 }
76
77 *numerator = *numerator / gcd;
78 *denominator = *denominator / gcd;
79 }
80
81 template void ReduceRatio<uint64_t>(uint64_t* numerator, uint64_t* denominator);
82 template void ReduceRatio<uint32_t>(uint32_t* numerator, uint32_t* denominator);
83
84 // Scales a uint64_t value by the ratio of two uint32_t values. If round_up is
85 // true, the result is rounded up rather than down. overflow is set to indicate
86 // overflow.
87 uint64_t ScaleUInt64(uint64_t value,
88 uint32_t numerator,
89 uint32_t denominator,
90 bool round_up,
91 bool* overflow) {
92 MOJO_DCHECK(denominator != 0u);
93 MOJO_DCHECK(overflow != nullptr);
94
95 constexpr uint64_t kLow32Bits = 0xffffffffu;
96 constexpr uint64_t kHigh32Bits = kLow32Bits << 32u;
97
98 // high and low are the product of the numerator and the high and low halves
99 // (respectively) of value.
100 uint64_t high = numerator * (value >> 32u);
101 uint64_t low = numerator * (value & kLow32Bits);
102 // Ignoring overflow and remainder, the result we want is:
103 // ((high << 32) + low) / denominator.
104
105 // Move the high end of low into the low end of high.
106 high += low >> 32u;
107 low = low & kLow32Bits;
108 // Ignoring overflow and remainder, the result we want is still:
109 // ((high << 32) + low) / denominator.
110
111 // When we divide high by denominator, there'll be a remainder. Make
112 // that the high end of low, which is currently all zeroes.
113 low |= (high % denominator) << 32u;
114
115 // Determine if we need to round up when we're done:
116 round_up = round_up && (low % denominator) != 0;
117
118 // Do the division.
119 high /= denominator;
120 low /= denominator;
121
122 // If high's top 32 bits aren't all zero, we have overflow.
123 if (high & kHigh32Bits) {
124 *overflow = true;
125 return 0;
126 }
127
128 uint64_t result = (high << 32u) | low;
129 if (round_up) {
130 if (result == std::numeric_limits<int64_t>::max()) {
131 *overflow = true;
132 return 0;
133 }
134 ++result;
135 }
136
137 *overflow = false;
138 return result;
139 }
140
141 } // namespace
142
143 // static
144 void Ratio::Reduce(uint32_t* numerator, uint32_t* denominator) {
145 ReduceRatio(numerator, denominator);
146 }
147
148 // static
149 void Ratio::Product(uint32_t a_numerator,
150 uint32_t a_denominator,
151 uint32_t b_numerator,
152 uint32_t b_denominator,
153 uint32_t* product_numerator,
154 uint32_t* product_denominator,
155 bool exact) {
156 MOJO_DCHECK(a_denominator != 0);
157 MOJO_DCHECK(b_denominator != 0);
158 MOJO_DCHECK(product_numerator != nullptr);
159 MOJO_DCHECK(product_denominator != nullptr);
160
161 uint64_t numerator = static_cast<uint64_t>(a_numerator) * b_numerator;
162 uint64_t denominator = static_cast<uint64_t>(a_denominator) * b_denominator;
163
164 ReduceRatio(&numerator, &denominator);
165
166 if (numerator > std::numeric_limits<uint32_t>::max() ||
167 denominator > std::numeric_limits<uint32_t>::max()) {
168 MOJO_DCHECK(!exact);
169
170 do {
171 numerator >>= 1;
172 denominator >>= 1;
173 } while (numerator > std::numeric_limits<uint32_t>::max() ||
174 denominator > std::numeric_limits<uint32_t>::max());
175
176 if (denominator == 0) {
177 // Product is larger than we can represent. Return the largest value we
178 // can represent.
179 *product_numerator = std::numeric_limits<uint32_t>::max();
180 *product_denominator = 1;
181 return;
182 }
183 }
184
185 *product_numerator = static_cast<uint32_t>(numerator);
186 *product_denominator = static_cast<uint32_t>(denominator);
187 }
188
189 // static
190 int64_t Ratio::Scale(int64_t value, uint32_t numerator, uint32_t denominator) {
191 static constexpr uint64_t abs_of_min_int64 =
192 static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1;
193
194 MOJO_DCHECK(denominator != 0u);
195
196 bool overflow;
197
198 uint64_t abs_result;
199
200 if (value >= 0) {
201 abs_result = ScaleUInt64(static_cast<uint64_t>(value), numerator,
202 denominator, false, &overflow);
203 } else if (value == std::numeric_limits<int64_t>::min()) {
204 abs_result = ScaleUInt64(abs_of_min_int64, numerator, denominator,
205 true, &overflow);
206 } else {
207 abs_result = ScaleUInt64(static_cast<uint64_t>(-value), numerator,
208 denominator, true, &overflow);
209 }
210
211 if (overflow) {
212 return Ratio::kOverflow;
213 }
214
215 // Make sure we won't overflow when we cast to int64_t.
216 if (abs_result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
217 if (value < 0 && abs_result == abs_of_min_int64) {
218 return std::numeric_limits<int64_t>::min();
219 }
220 return Ratio::kOverflow;
221 }
222
223 return value >= 0 ? static_cast<int64_t>(abs_result)
224 : -static_cast<int64_t>(abs_result);
225 }
226
227 } // namespace media
228 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/media/common/cpp/ratio.h ('k') | mojo/services/media/common/cpp/timeline_function.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698