diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2024-09-08 16:52:39 +0500 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2024-09-09 17:46:41 +0200 |
commit | b2257d1f78d7d678b87e2c3d590aba47bfec90f0 (patch) | |
tree | aa3daf3bb486620f668cd82af03614cc81a30781 /basic/source/sbx/sbxconv.hxx | |
parent | caff013bee53216efeb49db4bcda44b55c223b58 (diff) |
Improve run-time Currency type support in Basic
Change-Id: I1e04c6022944034a30ef896b8cd24050ebe3bbd5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173042
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'basic/source/sbx/sbxconv.hxx')
-rw-r--r-- | basic/source/sbx/sbxconv.hxx | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/basic/source/sbx/sbxconv.hxx b/basic/source/sbx/sbxconv.hxx index 8f11122bd319..f32e5fc890d7 100644 --- a/basic/source/sbx/sbxconv.hxx +++ b/basic/source/sbx/sbxconv.hxx @@ -26,6 +26,7 @@ #include <basic/sbxdef.hxx> #include <o3tl/float_int_conversion.hxx> +#include <o3tl/safeint.hxx> #include <rtl/math.hxx> #include <sal/types.h> @@ -107,14 +108,76 @@ void ImpPutCurrency( SbxValues*, const sal_Int64 ); inline sal_Int64 ImpDoubleToCurrency( double d ) { - if (d > 0) - return static_cast<sal_Int64>( d * CURRENCY_FACTOR + 0.5); - else - return static_cast<sal_Int64>( d * CURRENCY_FACTOR - 0.5); + double result = d > 0 ? (d * CURRENCY_FACTOR + 0.5) : (d * CURRENCY_FACTOR - 0.5); + if (result >= double(SAL_MAX_INT64)) // double(SAL_MAX_INT64) is greater than SAL_MAX_INT64 + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return SAL_MAX_INT64; + } + if (result < double(SAL_MIN_INT64)) + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return SAL_MIN_INT64; + } + return result; +} + +template <typename I> + requires std::is_integral_v<I> +inline sal_Int64 CurFrom(I n) +{ + using ValidRange = o3tl::ValidRange<sal_Int64, SAL_MIN_INT64 / CURRENCY_FACTOR, SAL_MAX_INT64 / CURRENCY_FACTOR>; + if (ValidRange::isAbove(n)) + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return SAL_MAX_INT64; + } + if (ValidRange::isBelow(n)) + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return SAL_MIN_INT64; + } + return n * CURRENCY_FACTOR; } -inline double ImpCurrencyToDouble( const sal_Int64 r ) - { return static_cast<double>(r) / double(CURRENCY_FACTOR); } +inline double ImpCurrencyToDouble(sal_Int64 r) { return static_cast<double>(r) / CURRENCY_FACTOR; } + +template <typename I> + requires std::is_integral_v<I> +inline I CurTo(sal_Int64 cur_val) +{ + sal_Int64 i = CurTo<sal_Int64>(cur_val); + if (o3tl::ValidRange<I>::isAbove(i)) + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return std::numeric_limits<I>::max(); + } + if (o3tl::ValidRange<I>::isBelow(i)) + { + SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW); + return std::numeric_limits<I>::min(); + } + return i; +} + +template <> inline sal_Int64 CurTo<sal_Int64>(sal_Int64 cur_val) +{ + sal_Int64 i = cur_val / CURRENCY_FACTOR; + // Rounding (half-to-even) + int f = cur_val % CURRENCY_FACTOR; + if (i % 2 == 1) + { + if (f < 0) + --f; + else + ++f; + } + if (f > CURRENCY_FACTOR / 2) + ++i; + else if (f < -CURRENCY_FACTOR / 2) + --i; + return i; +} // SBXDEC.CXX |