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