16e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim/* 26e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * 36e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * Copyright (C) 2015 The Android Open Source Project 46e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * 56e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * Licensed under the Apache License, Version 2.0 (the "License"); 66e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * you may not use this file except in compliance with the License. 76e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * You may obtain a copy of the License at 86e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * 96e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * http://www.apache.org/licenses/LICENSE-2.0 106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * 116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * Unless required by applicable law or agreed to in writing, software 126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * distributed under the License is distributed on an "AS IS" BASIS, 136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * See the License for the specific language governing permissions and 156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim * limitations under the License. 166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim */ 176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Functions for safe arithmetic (guarded against overflow) on integer types. 196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#ifndef __dng_safe_arithmetic__ 216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#define __dng_safe_arithmetic__ 226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include <cstddef> 246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include <cstdint> 256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include <limits> 266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_exceptions.h" 286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 29c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#ifndef __has_builtin 30c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#define __has_builtin(x) 0 // Compatibility with non-Clang compilers. 31c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 32c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 33c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#if !defined(DNG_HAS_INT128) && defined(__SIZEOF_INT128__) 34c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#define DNG_HAS_INT128 35c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 36c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// If the result of adding arg1 and arg2 will fit in an int32_t (without 386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// under-/overflow), stores this result in *result and returns true. Otherwise, 396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// returns false and leaves *result unchanged. 406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeInt32Add(std::int32_t arg1, std::int32_t arg2, std::int32_t *result); 416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of adding arg1 and arg2 if it will fit in the result type 436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// (without under-/overflow). Otherwise, throws a dng_exception with error code 446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// dng_error_unknown. 456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int32_t SafeInt32Add(std::int32_t arg1, std::int32_t arg2); 466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2); 476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// If the result of adding arg1 and arg2 will fit in a uint32_t (without 496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// wraparound), stores this result in *result and returns true. Otherwise, 506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// returns false and leaves *result unchanged. 516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2, 526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result); 536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 54c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Returns the result of adding arg1 and arg2 if it will fit in the result type 556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// (without wraparound). Otherwise, throws a dng_exception with error code 566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// dng_error_unknown. 576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2); 58c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2); 596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// If the subtraction of arg2 from arg1 will not result in an int32_t under- or 616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// overflow, stores this result in *result and returns true. Otherwise, 626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// returns false and leaves *result unchanged. 636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result); 646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of subtracting arg2 from arg1 if this operation will not 666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// result in an int32_t under- or overflow. Otherwise, throws a dng_exception 676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// with error code dng_error_unknown. 686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2); 696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 70c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Returns the result of subtracting arg2 from arg1 if this operation will not 71c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// result in wraparound. Otherwise, throws a dng_exception with error code 72c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// dng_error_unknown. 73c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2); 74c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 75c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Returns the result of multiplying arg1 and arg2 if it will fit in a int32_t 76c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// (without overflow). Otherwise, throws a dng_exception with error code 77c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// dng_error_unknown. 78c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2); 79c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// If the result of multiplying arg1, ..., argn will fit in a uint32_t (without 816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// wraparound), stores this result in *result and returns true. Otherwise, 826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// returns false and leaves *result unchanged. 836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result); 856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3, 866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result); 876e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3, 886e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg4, std::uint32_t *result); 896e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of multiplying arg1, ..., argn if it will fit in a 916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// uint32_t (without wraparound). Otherwise, throws a dng_exception with error 926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// code dng_error_unknown. 936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2); 946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg3); 966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg3, std::uint32_t arg4); 986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of multiplying arg1 and arg2 if it will fit in a size_t 1006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// (without overflow). Otherwise, throws a dng_exception with error code 1016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// dng_error_unknown. 1026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2); 1036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 104c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienernamespace dng_internal { 105c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 106c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Internal function used as fallback for SafeInt64Mult() if other optimized 107c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// computation is not supported. Don't call this function directly. 108c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2); 109c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 110c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Internal function used as optimization for SafeInt64Mult() if Clang 111c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// __builtin_smull_overflow is supported. Don't call this function directly. 112c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#if __has_builtin(__builtin_smull_overflow) 113c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerinline std::int64_t SafeInt64MultByClang(std::int64_t arg1, std::int64_t arg2) { 114c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener std::int64_t result; 115c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#if (__WORDSIZE == 64) && !defined(__APPLE__) 116c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener if (__builtin_smull_overflow(arg1, arg2, &result)) { 117c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#else 118c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener if (__builtin_smulll_overflow(arg1, arg2, &result)) { 119c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 120c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Arithmetic overflow"); 121c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 122c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 123c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return result; 124c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 125c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 126c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 127c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Internal function used as optimization for SafeInt64Mult() if __int128 type 128c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// is supported. Don't call this function directly. 129c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#ifdef DNG_HAS_INT128 130c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerinline std::int64_t SafeInt64MultByInt128(std::int64_t arg1, 131c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener std::int64_t arg2) { 13255625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener const __int128 kInt64Max = 13355625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener static_cast<__int128>(std::numeric_limits<std::int64_t>::max()); 13455625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener const __int128 kInt64Min = 13555625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener static_cast<__int128>(std::numeric_limits<std::int64_t>::min()); 136c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener __int128 result = static_cast<__int128>(arg1) * static_cast<__int128>(arg2); 13755625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener if (result > kInt64Max || result < kInt64Min) { 138c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Arithmetic overflow"); 139c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 140c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return static_cast<std::int64_t>(result); 141c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 142c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 143c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 144c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} // namespace dng_internal 145c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 1466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of multiplying arg1 and arg2 if it will fit in an int64_t 1476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// (without overflow). Otherwise, throws a dng_exception with error code 1486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// dng_error_unknown. 149c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerinline std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) { 150c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#if __has_builtin(__builtin_smull_overflow) 151c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return dng_internal::SafeInt64MultByClang(arg1, arg2); 152c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#elif defined(DNG_HAS_INT128) 153c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return dng_internal::SafeInt64MultByInt128(arg1, arg2); 154c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#else 155c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return dng_internal::SafeInt64MultSlow(arg1, arg2); 156c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener#endif 157c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 1586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of dividing arg1 by arg2; if the result is not an integer, 1606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// rounds up to the next integer. If arg2 is zero, throws a dng_exception with 1616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// error code dng_error_unknown. 1626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// The function is safe against wraparound and will return the correct result 1636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// for all combinations of arg1 and arg2. 1646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2); 1656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Finds the smallest integer multiple of 'multiple_of' that is greater than or 1676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// equal to 'val'. If this value will fit in a uint32_t, stores it in *result 1686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// and returns true. Otherwise, or if 'multiple_of' is zero, returns false and 1696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// leaves *result unchanged. 1706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of, 1716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result); 1726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 173c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Returns the smallest integer multiple of 'multiple_of' that is greater than 174c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// or equal to 'val'. If the result will not fit in a std::uint32_t or if 175c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// 'multiple_of' is zero, throws a dng_exception with error code 176c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// dng_error_unknown. 177c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint32_t RoundUpUint32ToMultiple(std::uint32_t val, 178c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener std::uint32_t multiple_of); 179c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 1806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// If the uint32_t value val will fit in a int32_t, converts it to a int32_t and 1816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// stores it in *result. Otherwise, returns false and leaves *result unchanged. 1826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result); 1836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 184c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// Returns the result of converting val to an int32_t if it can be converted 185c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// without overflow. Otherwise, throws a dng_exception with error code 186c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener// dng_error_unknown. 187c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t ConvertUint32ToInt32(std::uint32_t val); 188c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 1896e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Converts a value of the unsigned integer type TSrc to the unsigned integer 1906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// type TDest. If the value in 'src' cannot be converted to the type TDest 1916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// without truncation, throws a dng_exception with error code dng_error_unknown. 1926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// 1936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Note: Though this function is typically used where TDest is a narrower type 1946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// than TSrc, it is designed to work also if TDest is wider than from TSrc or 1956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// identical to TSrc. This is useful in situations where the width of the types 1966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// involved can change depending on the architecture -- for example, the 1976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// conversion from size_t to uint32_t may either be narrowing, identical or even 1986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// widening (though the latter admittedly happens only on architectures that 1996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// aren't relevant to us). 2006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimtemplate <class TSrc, class TDest> 2016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstatic void ConvertUnsigned(TSrc src, TDest *dest) { 2026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim static_assert(std::numeric_limits<TSrc>::is_integer && 2036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim !std::numeric_limits<TSrc>::is_signed && 2046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::numeric_limits<TDest>::is_integer && 2056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim !std::numeric_limits<TDest>::is_signed, 2066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim "TSrc and TDest must be unsigned integer types"); 2076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2086e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim const TDest converted = static_cast<TDest>(src); 2096e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // Convert back to TSrc to check whether truncation occurred in the 2116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // conversion to TDest. 2126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (static_cast<TSrc>(converted) != src) { 2136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Overflow in unsigned integer conversion"); 2146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 2156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *dest = converted; 2176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 2186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 21955625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener// Returns the result of converting val to the result type using truncation if 22055625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener// val is in range of the result type values. Otherwise, throws a dng_exception 22155625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Kriener// with error code dng_error_unknown. 222c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t ConvertDoubleToInt32(double val); 22355625cf05f4345dcab5d9d92b83bb8b5606debabFlorian Krienerstd::uint32_t ConvertDoubleToUint32(double val); 224c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 2251754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener// Returns the result of converting val to float. If val is outside of 2261754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener// [-FLT_MAX, FLT_MAX], -infinity and infinity is returned respectively. NaN is 2271754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener// returned as NaN. 2281754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Krienerfloat ConvertDoubleToFloat(double val); 2291754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener 2306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#endif // __dng_safe_arithmetic__ 231