/src/libreoffice/include/o3tl/unit_conversion.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #pragma once |
11 | | |
12 | | #include <o3tl/safeint.hxx> |
13 | | #include <sal/types.h> |
14 | | |
15 | | #include <array> |
16 | | #include <cassert> |
17 | | #include <concepts> |
18 | | #include <numeric> |
19 | | #include <utility> |
20 | | #include <type_traits> |
21 | | |
22 | | namespace o3tl |
23 | | { |
24 | | // Length units |
25 | | enum class Length |
26 | | { |
27 | | mm100 = 0, // 1/100th mm |
28 | | mm10, // 1/10 mm, corresponds to MapUnit::Map10thMM |
29 | | mm, // millimeter |
30 | | cm, // centimeter |
31 | | m, // meter |
32 | | km, // kilometer |
33 | | emu, // English Metric Unit: 1/360000 cm, 1/914400 in |
34 | | twip, // "Twentieth of a point" aka "dxa": 1/20 pt |
35 | | pt, // Point: 1/72 in |
36 | | pc, // Pica: 1/6 in, corresponds to FieldUnit::PICA and MeasureUnit::PICA |
37 | | in1000, // 1/1000 in, corresponds to MapUnit::Map1000thInch |
38 | | in100, // 1/100 in, corresponds to MapUnit::Map100thInch |
39 | | in10, // 1/10 in, corresponds to MapUnit::Map10thInch |
40 | | in, // inch |
41 | | ft, // foot |
42 | | mi, // mile |
43 | | master, // PPT Master Unit: 1/576 in |
44 | | px, // "pixel" unit: 15 twip (96 ppi), corresponds to MeasureUnit::PIXEL |
45 | | ch, // "char" unit: 210 twip (14 px), corresponds to FieldUnit::CHAR |
46 | | line, // "line" unit: 312 twip, corresponds to FieldUnit::LINE |
47 | | count, // <== add new units above this last entry |
48 | | invalid = -1 |
49 | | }; |
50 | | |
51 | | // If other categories of units would be needed (like time), a separate scoped enum |
52 | | // should be created, respective conversion array prepared in detail namespace, and |
53 | | // respective md(NewUnit, NewUnit) overload introduced, which would allow using |
54 | | // o3tl::convert(), o3tl::convertSaturate() and o3tl::getConversionMulDiv() with the |
55 | | // new category in a type-safe way, without mixing unrelated units. |
56 | | |
57 | | namespace detail |
58 | | { |
59 | | // Common utilities |
60 | | |
61 | | // A special function to avoid compiler warning comparing signed and unsigned values |
62 | | template <typename I> constexpr bool isBetween(I n, sal_Int64 min, sal_Int64 max) |
63 | 1.36M | { |
64 | 1.36M | assert(max > 0 && min < 0); |
65 | | if constexpr (std::is_signed_v<I>) |
66 | 1.36M | return n >= min && n <= max; |
67 | | else |
68 | | return n <= sal_uInt64(max); |
69 | 1.36M | } bool o3tl::detail::isBetween<long>(long, long, long) Line | Count | Source | 63 | 1.36M | { | 64 | 1.36M | assert(max > 0 && min < 0); | 65 | | if constexpr (std::is_signed_v<I>) | 66 | 1.36M | return n >= min && n <= max; | 67 | | else | 68 | | return n <= sal_uInt64(max); | 69 | 1.36M | } |
Unexecuted instantiation: bool o3tl::detail::isBetween<int>(int, long, long) |
70 | | |
71 | | // Ensure correct rounding for both positive and negative integers |
72 | | template <std::integral I> constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d) |
73 | 167M | { |
74 | 167M | assert(m > 0 && d > 0); |
75 | 167M | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); |
76 | | // coverity[dead_error_line] - suppress warning for template |
77 | 167M | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; |
78 | 167M | } _ZN4o3tl6detail6MulDivITkNSt3__18integralElEElT_ll Line | Count | Source | 73 | 4.63M | { | 74 | 4.63M | assert(m > 0 && d > 0); | 75 | 4.63M | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 4.63M | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 4.63M | } |
_ZN4o3tl6detail6MulDivITkNSt3__18integralEiEElT_ll Line | Count | Source | 73 | 154M | { | 74 | 154M | assert(m > 0 && d > 0); | 75 | 154M | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 154M | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 154M | } |
_ZN4o3tl6detail6MulDivITkNSt3__18integralEtEElT_ll Line | Count | Source | 73 | 200k | { | 74 | 200k | assert(m > 0 && d > 0); | 75 | 200k | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 200k | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 200k | } |
_ZN4o3tl6detail6MulDivITkNSt3__18integralEsEElT_ll Line | Count | Source | 73 | 196k | { | 74 | 196k | assert(m > 0 && d > 0); | 75 | 196k | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 196k | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 196k | } |
_ZN4o3tl6detail6MulDivITkNSt3__18integralEmEElT_ll Line | Count | Source | 73 | 477k | { | 74 | 477k | assert(m > 0 && d > 0); | 75 | 477k | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 477k | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 477k | } |
_ZN4o3tl6detail6MulDivITkNSt3__18integralEjEElT_ll Line | Count | Source | 73 | 7.62M | { | 74 | 7.62M | assert(m > 0 && d > 0); | 75 | 7.62M | assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)); | 76 | | // coverity[dead_error_line] - suppress warning for template | 77 | 7.62M | return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d; | 78 | 7.62M | } |
Unexecuted instantiation: _ZN4o3tl6detail6MulDivITkNSt3__18integralEaEElT_ll |
79 | | template <std::floating_point F> constexpr double MulDiv(F f, sal_Int64 m, sal_Int64 d) |
80 | 10.2M | { |
81 | 10.2M | assert(m > 0 && d > 0); |
82 | 10.2M | return f * (double(m) / d); |
83 | 10.2M | } _ZN4o3tl6detail6MulDivITkNSt3__114floating_pointEdEEdT_ll Line | Count | Source | 80 | 10.2M | { | 81 | | assert(m > 0 && d > 0); | 82 | 10.2M | return f * (double(m) / d); | 83 | 10.2M | } |
Unexecuted instantiation: _ZN4o3tl6detail6MulDivITkNSt3__114floating_pointEfEEdT_ll |
84 | | |
85 | | template <std::integral I> |
86 | | constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d, bool& bOverflow, sal_Int64 nDefault) |
87 | 1.28M | { |
88 | 1.28M | if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m)) |
89 | 1 | { |
90 | 1 | bOverflow = true; |
91 | 1 | return nDefault; |
92 | 1 | } |
93 | 1.28M | bOverflow = false; |
94 | 1.28M | return MulDiv(n, m, d); |
95 | 1.28M | } |
96 | | |
97 | | template <std::integral I> constexpr sal_Int64 MulDivSaturate(I n, sal_Int64 m, sal_Int64 d) |
98 | 71.9k | { |
99 | 71.9k | if (sal_Int64 d_2 = d / 2; !isBetween(n, (SAL_MIN_INT64 + d_2) / m, (SAL_MAX_INT64 - d_2) / m)) |
100 | 12 | { |
101 | 12 | if (n >= 0) |
102 | 12 | { |
103 | 12 | if (m > d && std::make_unsigned_t<I>(n) > sal_uInt64(SAL_MAX_INT64 / m * d - d_2)) |
104 | 0 | return SAL_MAX_INT64; // saturate |
105 | | // coverity[ tainted_data_return : SUPPRESS ] 2024.6.1 |
106 | 12 | return saturating_add<sal_uInt64>(n, d_2) / d * m; // divide before multiplication |
107 | 12 | } |
108 | | else if constexpr (std::is_signed_v<I>) // n < 0; don't compile for unsigned n |
109 | 0 | { |
110 | 0 | if (m > d && n < SAL_MIN_INT64 / m * d + d_2) |
111 | 0 | return SAL_MIN_INT64; // saturate |
112 | 0 | return saturating_sub<sal_Int64>(n, d_2) / d * m; // divide before multiplication |
113 | 0 | } |
114 | 12 | } |
115 | 71.9k | return MulDiv(n, m, d); |
116 | 71.9k | } Unexecuted instantiation: _ZN4o3tl6detail14MulDivSaturateITkNSt3__18integralElEElT_ll Unexecuted instantiation: _ZN4o3tl6detail14MulDivSaturateITkNSt3__18integralEiEElT_ll _ZN4o3tl6detail14MulDivSaturateITkNSt3__18integralElEElT_ll Line | Count | Source | 98 | 71.9k | { | 99 | 71.9k | if (sal_Int64 d_2 = d / 2; !isBetween(n, (SAL_MIN_INT64 + d_2) / m, (SAL_MAX_INT64 - d_2) / m)) | 100 | 12 | { | 101 | 12 | if (n >= 0) | 102 | 12 | { | 103 | 12 | if (m > d && std::make_unsigned_t<I>(n) > sal_uInt64(SAL_MAX_INT64 / m * d - d_2)) | 104 | 0 | return SAL_MAX_INT64; // saturate | 105 | | // coverity[ tainted_data_return : SUPPRESS ] 2024.6.1 | 106 | 12 | return saturating_add<sal_uInt64>(n, d_2) / d * m; // divide before multiplication | 107 | 12 | } | 108 | | else if constexpr (std::is_signed_v<I>) // n < 0; don't compile for unsigned n | 109 | 0 | { | 110 | 0 | if (m > d && n < SAL_MIN_INT64 / m * d + d_2) | 111 | 0 | return SAL_MIN_INT64; // saturate | 112 | 0 | return saturating_sub<sal_Int64>(n, d_2) / d * m; // divide before multiplication | 113 | 0 | } | 114 | 12 | } | 115 | 71.9k | return MulDiv(n, m, d); | 116 | 71.9k | } |
|
117 | | |
118 | | template <class M, class N> constexpr std::common_type_t<M, N> asserting_gcd(M m, N n) |
119 | 0 | { |
120 | 0 | auto ret = std::gcd(m, n); |
121 | 0 | assert(ret != 0); |
122 | 0 | return ret; |
123 | 0 | } |
124 | | |
125 | | // Packs integral multiplier and divisor for conversion from one unit to another |
126 | | struct m_and_d |
127 | | { |
128 | | sal_Int64 m; // multiplier |
129 | | sal_Int64 d; // divisor |
130 | | constexpr m_and_d(sal_Int64 _m, sal_Int64 _d) |
131 | | : m(_m / asserting_gcd(_m, _d)) // make sure to use smallest quotients here because |
132 | | , d(_d / asserting_gcd(_m, _d)) // they will be multiplied when building final table |
133 | 0 | { |
134 | 0 | assert(_m > 0 && _d > 0); |
135 | 0 | } |
136 | | }; |
137 | | |
138 | | // Resulting static array N x N of all quotients to convert between all units. The |
139 | | // quotients are minimal to allow largest range of converted numbers without overflow. |
140 | | // Maybe o3tl::enumarray could be used here, but it's not constexpr yet. |
141 | | template <int N> constexpr auto prepareMDArray(const m_and_d (&mdBase)[N]) |
142 | 0 | { |
143 | 0 | std::array<std::array<sal_Int64, N>, N> a{}; |
144 | 0 | for (int i = 0; i < N; ++i) |
145 | 0 | { |
146 | 0 | a[i][i] = 1; |
147 | 0 | for (int j = 0; j < i; ++j) |
148 | 0 | { |
149 | 0 | assert(mdBase[i].m < SAL_MAX_INT64 / mdBase[j].d); |
150 | 0 | assert(mdBase[i].d < SAL_MAX_INT64 / mdBase[j].m); |
151 | 0 | const sal_Int64 m = mdBase[i].m * mdBase[j].d, d = mdBase[i].d * mdBase[j].m; |
152 | 0 | const sal_Int64 g = asserting_gcd(m, d); |
153 | 0 | a[i][j] = m / g; |
154 | 0 | a[j][i] = d / g; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | return a; |
158 | 0 | } |
159 | | |
160 | | // A generic template used for fundamental arithmetic types |
161 | 6 | template <typename U> constexpr sal_Int64 md(U i, U /*j*/) { return i; }long o3tl::detail::md<int>(int, int) Line | Count | Source | 161 | 6 | template <typename U> constexpr sal_Int64 md(U i, U /*j*/) { return i; } |
Unexecuted instantiation: long o3tl::detail::md<long>(long, long) |
162 | | |
163 | | // Length units implementation |
164 | | |
165 | | // Array of conversion quotients for mm, used to build final conversion table. Entries |
166 | | // are { multiplier, divider } to convert respective unit *to* mm. Order of elements |
167 | | // corresponds to order in o3tl::Length enum (Length::count and Length::invalid omitted). |
168 | | constexpr m_and_d mdBaseLen[] = { |
169 | | { 1, 100 }, // mm100 => mm |
170 | | { 1, 10 }, // mm10 => mm |
171 | | { 1, 1 }, // mm => mm |
172 | | { 10, 1 }, // cm => mm |
173 | | { 1000, 1 }, // m => mm |
174 | | { 1000000, 1 }, // km => mm |
175 | | { 1, 36000 }, // emu => mm |
176 | | { 254, 10 * 1440 }, // twip => mm |
177 | | { 254, 10 * 72 }, // pt => mm |
178 | | { 254, 10 * 6 }, // pc => mm |
179 | | { 254, 10000 }, // in1000 => mm |
180 | | { 254, 1000 }, // in100 => mm |
181 | | { 254, 100 }, // in10 => mm |
182 | | { 254, 10 }, // in => mm |
183 | | { 254 * 12, 10 }, // ft => mm |
184 | | { 254 * 12 * 5280, 10 }, // mi => mm |
185 | | { 254, 10 * 576 }, // master => mm |
186 | | { 254 * 15, 10 * 1440 }, // px => mm |
187 | | { 254 * 210, 10 * 1440 }, // ch => mm |
188 | | { 254 * 312, 10 * 1440 }, // line => mm |
189 | | }; |
190 | | static_assert(std::size(mdBaseLen) == static_cast<int>(Length::count), |
191 | | "mdBaseL must have an entry for each unit in o3tl::Length"); |
192 | | |
193 | | // The resulting multipliers and divisors array |
194 | | constexpr auto aLengthMDArray = prepareMDArray(mdBaseLen); |
195 | | |
196 | | // an overload taking Length |
197 | | constexpr sal_Int64 md(Length i, Length j) |
198 | 400M | { |
199 | 400M | const int nI = static_cast<int>(i), nJ = static_cast<int>(j); |
200 | 400M | assert(nI >= 0 && o3tl::make_unsigned(nI) < aLengthMDArray.size()); |
201 | 400M | assert(nJ >= 0 && o3tl::make_unsigned(nJ) < aLengthMDArray.size()); |
202 | 400M | return aLengthMDArray[nI][nJ]; |
203 | 400M | } |
204 | | |
205 | | // here might go overloads of md() taking other units ... |
206 | | } |
207 | | |
208 | | // Unchecked conversion. Takes a number value, multiplier and divisor |
209 | | template <typename N> constexpr auto convert(N n, sal_Int64 mul, sal_Int64 div) |
210 | 176M | { |
211 | 176M | return detail::MulDiv(n, mul, div); |
212 | 176M | } auto o3tl::convert<long>(long, long, long) Line | Count | Source | 210 | 3.27M | { | 211 | 3.27M | return detail::MulDiv(n, mul, div); | 212 | 3.27M | } |
auto o3tl::convert<int>(int, long, long) Line | Count | Source | 210 | 154M | { | 211 | 154M | return detail::MulDiv(n, mul, div); | 212 | 154M | } |
auto o3tl::convert<double>(double, long, long) Line | Count | Source | 210 | 10.2M | { | 211 | 10.2M | return detail::MulDiv(n, mul, div); | 212 | 10.2M | } |
Unexecuted instantiation: auto o3tl::convert<float>(float, long, long) auto o3tl::convert<unsigned short>(unsigned short, long, long) Line | Count | Source | 210 | 200k | { | 211 | 200k | return detail::MulDiv(n, mul, div); | 212 | 200k | } |
auto o3tl::convert<short>(short, long, long) Line | Count | Source | 210 | 196k | { | 211 | 196k | return detail::MulDiv(n, mul, div); | 212 | 196k | } |
auto o3tl::convert<unsigned long>(unsigned long, long, long) Line | Count | Source | 210 | 477k | { | 211 | 477k | return detail::MulDiv(n, mul, div); | 212 | 477k | } |
auto o3tl::convert<unsigned int>(unsigned int, long, long) Line | Count | Source | 210 | 7.62M | { | 211 | 7.62M | return detail::MulDiv(n, mul, div); | 212 | 7.62M | } |
Unexecuted instantiation: auto o3tl::convert<signed char>(signed char, long, long) |
213 | | |
214 | | // Unchecked conversion. Takes a number value and units defined in this header |
215 | | template <typename N, typename U> constexpr auto convert(N n, U from, U to) |
216 | 171M | { |
217 | 171M | return convert(n, detail::md(from, to), detail::md(to, from)); |
218 | 171M | } auto o3tl::convert<long, o3tl::Length>(long, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 2.80M | { | 217 | 2.80M | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 2.80M | } |
auto o3tl::convert<int, o3tl::Length>(int, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 154M | { | 217 | 154M | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 154M | } |
auto o3tl::convert<double, o3tl::Length>(double, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 6.18M | { | 217 | 6.18M | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 6.18M | } |
Unexecuted instantiation: auto o3tl::convert<float, o3tl::Length>(float, o3tl::Length, o3tl::Length) Unexecuted instantiation: auto o3tl::convert<long, int>(long, int, int) auto o3tl::convert<unsigned short, o3tl::Length>(unsigned short, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 200k | { | 217 | 200k | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 200k | } |
auto o3tl::convert<short, o3tl::Length>(short, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 196k | { | 217 | 196k | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 196k | } |
auto o3tl::convert<unsigned long, o3tl::Length>(unsigned long, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 477k | { | 217 | 477k | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 477k | } |
auto o3tl::convert<unsigned int, o3tl::Length>(unsigned int, o3tl::Length, o3tl::Length) Line | Count | Source | 216 | 7.62M | { | 217 | 7.62M | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 7.62M | } |
Unexecuted instantiation: auto o3tl::convert<signed char, o3tl::Length>(signed char, o3tl::Length, o3tl::Length) auto o3tl::convert<int, int>(int, int, int) Line | Count | Source | 216 | 3 | { | 217 | 3 | return convert(n, detail::md(from, to), detail::md(to, from)); | 218 | 3 | } |
|
219 | | |
220 | | // Convert to twips - for convenience as we do this a lot |
221 | | template <typename N> constexpr auto toTwips(N number, Length from) |
222 | 4.93M | { |
223 | 4.93M | return convert(number, from, Length::twip); |
224 | 4.93M | } auto o3tl::toTwips<double>(double, o3tl::Length) Line | Count | Source | 222 | 181k | { | 223 | 181k | return convert(number, from, Length::twip); | 224 | 181k | } |
auto o3tl::toTwips<long>(long, o3tl::Length) Line | Count | Source | 222 | 139k | { | 223 | 139k | return convert(number, from, Length::twip); | 224 | 139k | } |
auto o3tl::toTwips<unsigned int>(unsigned int, o3tl::Length) Line | Count | Source | 222 | 3.03M | { | 223 | 3.03M | return convert(number, from, Length::twip); | 224 | 3.03M | } |
auto o3tl::toTwips<int>(int, o3tl::Length) Line | Count | Source | 222 | 1.45M | { | 223 | 1.45M | return convert(number, from, Length::twip); | 224 | 1.45M | } |
auto o3tl::toTwips<short>(short, o3tl::Length) Line | Count | Source | 222 | 113k | { | 223 | 113k | return convert(number, from, Length::twip); | 224 | 113k | } |
auto o3tl::toTwips<unsigned short>(unsigned short, o3tl::Length) Line | Count | Source | 222 | 9.37k | { | 223 | 9.37k | return convert(number, from, Length::twip); | 224 | 9.37k | } |
Unexecuted instantiation: auto o3tl::toTwips<Point>(Point, o3tl::Length) Unexecuted instantiation: auto o3tl::toTwips<Size>(Size, o3tl::Length) Unexecuted instantiation: auto o3tl::toTwips<tools::Rectangle>(tools::Rectangle, o3tl::Length) auto o3tl::toTwips<unsigned long>(unsigned long, o3tl::Length) Line | Count | Source | 222 | 257 | { | 223 | 257 | return convert(number, from, Length::twip); | 224 | 257 | } |
|
225 | | |
226 | | // Returns nDefault if intermediate multiplication overflows sal_Int64 (only for integral types). |
227 | | // On return, bOverflow indicates if overflow happened. nDefault is returned when overflow occurs. |
228 | | template <typename N, typename U> |
229 | | constexpr auto convert(N n, U from, U to, bool& bOverflow, sal_Int64 nDefault = 0) |
230 | 1.28M | { |
231 | 1.28M | return detail::MulDiv(n, detail::md(from, to), detail::md(to, from), bOverflow, nDefault); |
232 | 1.28M | } |
233 | | |
234 | | // Conversion with saturation (only for integral types). For too large input returns SAL_MAX_INT64. |
235 | | // When intermediate multiplication would overflow, but the end result is in sal_Int64 range, the |
236 | | // precision is decreased because of inversion of multiplication and division. |
237 | | template <typename N, typename U> constexpr auto convertSaturate(N n, U from, U to) |
238 | 71.9k | { |
239 | 71.9k | return detail::MulDivSaturate(n, detail::md(from, to), detail::md(to, from)); |
240 | 71.9k | } Unexecuted instantiation: auto o3tl::convertSaturate<int, o3tl::Length>(int, o3tl::Length, o3tl::Length) auto o3tl::convertSaturate<long, o3tl::Length>(long, o3tl::Length, o3tl::Length) Line | Count | Source | 238 | 71.9k | { | 239 | 71.9k | return detail::MulDivSaturate(n, detail::md(from, to), detail::md(to, from)); | 240 | 71.9k | } |
Unexecuted instantiation: auto o3tl::convertSaturate<int, long>(int, long, long) |
241 | | |
242 | | // Conversion with saturation (only for integral types), optimized for return types smaller than |
243 | | // sal_Int64. In this case, it's easier to clamp input values to known bounds, than to do some |
244 | | // preprocessing to handle too large input values, just to clamp the result anyway. Use it like: |
245 | | // |
246 | | // sal_Int32 n = convertNarrowing<sal_Int32, o3tl::Length::mm100, o3tl::Length::emu>(m); |
247 | | template <std::integral Out, auto from, auto to, std::integral N> |
248 | | requires(sizeof(Out) < sizeof(sal_Int64)) constexpr Out convertNarrowing(N n) |
249 | 685k | { |
250 | 685k | constexpr sal_Int64 nMin = convertSaturate(std::numeric_limits<Out>::min(), to, from); |
251 | 685k | constexpr sal_Int64 nMax = convertSaturate(std::numeric_limits<Out>::max(), to, from); |
252 | 685k | if (static_cast<sal_Int64>(n) > nMax) |
253 | 0 | return std::numeric_limits<Out>::max(); |
254 | 685k | if (static_cast<sal_Int64>(n) < nMin) |
255 | 0 | return std::numeric_limits<Out>::min(); |
256 | 685k | return convert(n, from, to); |
257 | 685k | } _ZN4o3tl16convertNarrowingITkNSt3__18integralEiTnDaLNS_6LengthE6ETnDaLS2_0ETkNS1_8integralElQltstT_Lm8EEES3_T2_ Line | Count | Source | 249 | 203k | { | 250 | 203k | constexpr sal_Int64 nMin = convertSaturate(std::numeric_limits<Out>::min(), to, from); | 251 | 203k | constexpr sal_Int64 nMax = convertSaturate(std::numeric_limits<Out>::max(), to, from); | 252 | 203k | if (static_cast<sal_Int64>(n) > nMax) | 253 | 0 | return std::numeric_limits<Out>::max(); | 254 | 203k | if (static_cast<sal_Int64>(n) < nMin) | 255 | 0 | return std::numeric_limits<Out>::min(); | 256 | 203k | return convert(n, from, to); | 257 | 203k | } |
_ZN4o3tl16convertNarrowingITkNSt3__18integralEiTnDaLl127ETnDaLl360ETkNS1_8integralEiQltstT_Lm8EEES2_T2_ Line | Count | Source | 249 | 482k | { | 250 | 482k | constexpr sal_Int64 nMin = convertSaturate(std::numeric_limits<Out>::min(), to, from); | 251 | 482k | constexpr sal_Int64 nMax = convertSaturate(std::numeric_limits<Out>::max(), to, from); | 252 | 482k | if (static_cast<sal_Int64>(n) > nMax) | 253 | 0 | return std::numeric_limits<Out>::max(); | 254 | 482k | if (static_cast<sal_Int64>(n) < nMin) | 255 | 0 | return std::numeric_limits<Out>::min(); | 256 | 482k | return convert(n, from, to); | 257 | 482k | } |
|
258 | | |
259 | | // Return a pair { multiplier, divisor } for a given conversion |
260 | | template <typename U> constexpr std::pair<sal_Int64, sal_Int64> getConversionMulDiv(U from, U to) |
261 | 27.0M | { |
262 | 27.0M | return { detail::md(from, to), detail::md(to, from) }; |
263 | 27.0M | } |
264 | | } |
265 | | |
266 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |