LCOV - code coverage report
Current view: top level - gcore - gdal_priv_templates.hpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 320 355 90.1 %
Date: 2025-05-31 00:00:17 Functions: 353 355 99.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Inline C++ templates
       5             :  * Author:   Phil Vachon, <philippe at cowpig.ca>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2009, Phil Vachon, <philippe at cowpig.ca>
       9             :  * Copyright (c) 2025, Even Rouault, <even.rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #ifndef GDAL_PRIV_TEMPLATES_HPP_INCLUDED
      15             : #define GDAL_PRIV_TEMPLATES_HPP_INCLUDED
      16             : 
      17             : #include "cpl_port.h"
      18             : 
      19             : #include <algorithm>
      20             : #include <cmath>
      21             : #include <cstdint>
      22             : #include <limits>
      23             : #include <type_traits>
      24             : 
      25             : #include "cpl_float.h"
      26             : 
      27             : /************************************************************************/
      28             : /*                        GDALGetDataLimits()                           */
      29             : /************************************************************************/
      30             : /**
      31             :  * Compute the limits of values that can be placed in Tout in terms of
      32             :  * Tin. Usually used for output clamping, when the output data type's
      33             :  * limits are stable relative to the input type (i.e. no roundoff error).
      34             :  *
      35             :  * @param tMaxValue the returned maximum value
      36             :  * @param tMinValue the returned minimum value
      37             :  */
      38             : 
      39             : template <class Tin, class Tout>
      40   381691393 : inline void GDALGetDataLimits(Tin &tMaxValue, Tin &tMinValue)
      41             : {
      42   381691393 :     tMaxValue = cpl::NumericLimits<Tin>::max();
      43   383763503 :     tMinValue = cpl::NumericLimits<Tin>::lowest();
      44             : 
      45             :     // Compute the actual minimum value of Tout in terms of Tin.
      46             :     if constexpr (cpl::NumericLimits<Tout>::is_signed &&
      47             :                   cpl::NumericLimits<Tout>::is_integer)
      48             :     {
      49             :         // the minimum value is less than zero
      50             :         // cppcheck-suppress knownConditionTrueFalse
      51             :         if constexpr (cpl::NumericLimits<Tout>::digits <
      52             :                           cpl::NumericLimits<Tin>::digits ||
      53             :                       !cpl::NumericLimits<Tin>::is_integer)
      54             :         {
      55             :             // Tout is smaller than Tin, so we need to clamp values in input
      56             :             // to the range of Tout's min/max values
      57             :             if constexpr (cpl::NumericLimits<Tin>::is_signed)
      58             :             {
      59    85151937 :                 tMinValue =
      60    85151997 :                     static_cast<Tin>(cpl::NumericLimits<Tout>::lowest());
      61             :             }
      62    85668090 :             tMaxValue = static_cast<Tin>(cpl::NumericLimits<Tout>::max());
      63             :         }
      64             :     }
      65             :     else if constexpr (cpl::NumericLimits<Tout>::is_integer)
      66             :     {
      67             :         // the output is unsigned, so we just need to determine the max
      68             :         /* coverity[same_on_both_sides] */
      69             :         if constexpr (cpl::NumericLimits<Tout>::digits <=
      70             :                       cpl::NumericLimits<Tin>::digits)
      71             :         {
      72             :             // Tout is smaller than Tin, so we need to clamp the input values
      73             :             // to the range of Tout's max
      74   147822442 :             tMaxValue = static_cast<Tin>(cpl::NumericLimits<Tout>::max());
      75             :         }
      76   149127488 :         tMinValue = 0;
      77             :     }
      78   383890213 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                          GDALClampValue()                            */
      82             : /************************************************************************/
      83             : /**
      84             :  * Clamp values of type T to a specified range
      85             :  *
      86             :  * @param tValue the value
      87             :  * @param tMax the max value
      88             :  * @param tMin the min value
      89             :  */
      90             : template <class T>
      91   382460115 : inline T GDALClampValue(const T tValue, const T tMax, const T tMin)
      92             : {
      93   382460115 :     return tValue > tMax ? tMax : tValue < tMin ? tMin : tValue;
      94             : }
      95             : 
      96             : /************************************************************************/
      97             : /*                          GDALClampDoubleValue()                            */
      98             : /************************************************************************/
      99             : /**
     100             :  * Clamp double values to a specified range, this uses the same
     101             :  * argument ordering as std::clamp, returns TRUE if the value was clamped.
     102             :  *
     103             :  * @param tValue the value
     104             :  * @param tMin the min value
     105             :  * @param tMax the max value
     106             :  *
     107             :  */
     108             : template <class T2, class T3>
     109         269 : inline bool GDALClampDoubleValue(double &tValue, const T2 tMin, const T3 tMax)
     110             : {
     111         269 :     const double tMin2{static_cast<double>(tMin)};
     112         269 :     const double tMax2{static_cast<double>(tMax)};
     113         269 :     if (tValue > tMax2 || tValue < tMin2)
     114             :     {
     115          26 :         tValue = tValue > tMax2 ? tMax2 : tValue < tMin2 ? tMin2 : tValue;
     116          26 :         return true;
     117             :     }
     118             :     else
     119             :     {
     120         243 :         return false;
     121             :     }
     122             : }
     123             : 
     124             : /************************************************************************/
     125             : /*                         GDALIsValueInRange()                         */
     126             : /************************************************************************/
     127             : /**
     128             :  * Returns whether a value is in the type range.
     129             :  * NaN is considered not to be in type range.
     130             :  *
     131             :  * @param dfValue the value
     132             :  * @return whether the value is in the type range.
     133             :  */
     134      151526 : template <class T> inline bool GDALIsValueInRange(double dfValue)
     135             : {
     136      302982 :     return dfValue >= static_cast<double>(cpl::NumericLimits<T>::lowest()) &&
     137      302966 :            dfValue <= static_cast<double>(cpl::NumericLimits<T>::max());
     138             : }
     139             : 
     140          26 : template <> inline bool GDALIsValueInRange<double>(double dfValue)
     141             : {
     142          26 :     return !CPLIsNan(dfValue);
     143             : }
     144             : 
     145       42251 : template <> inline bool GDALIsValueInRange<float>(double dfValue)
     146             : {
     147       84325 :     return CPLIsInf(dfValue) ||
     148       41960 :            (dfValue >= -std::numeric_limits<float>::max() &&
     149       84244 :             dfValue <= std::numeric_limits<float>::max());
     150             : }
     151             : 
     152           1 : template <> inline bool GDALIsValueInRange<GFloat16>(double dfValue)
     153             : {
     154           3 :     return CPLIsInf(dfValue) ||
     155           2 :            (dfValue >= -cpl::NumericLimits<GFloat16>::max() &&
     156           2 :             dfValue <= cpl::NumericLimits<GFloat16>::max());
     157             : }
     158             : 
     159       16899 : template <> inline bool GDALIsValueInRange<int64_t>(double dfValue)
     160             : {
     161             :     // Values in the range [INT64_MAX - 1023, INT64_MAX - 1]
     162             :     // get converted to a double that once cast to int64_t is
     163             :     // INT64_MAX + 1, hence the < strict comparison.
     164             :     return dfValue >=
     165       33797 :                static_cast<double>(cpl::NumericLimits<int64_t>::lowest()) &&
     166       33797 :            dfValue < static_cast<double>(cpl::NumericLimits<int64_t>::max());
     167             : }
     168             : 
     169        8914 : template <> inline bool GDALIsValueInRange<uint64_t>(double dfValue)
     170             : {
     171             :     // Values in the range [UINT64_MAX - 2047, UINT64_MAX - 1]
     172             :     // get converted to a double that once cast to uint64_t is
     173             :     // UINT64_MAX + 1, hence the < strict comparison.
     174       17825 :     return dfValue >= 0 &&
     175       17825 :            dfValue < static_cast<double>(cpl::NumericLimits<uint64_t>::max());
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                         GDALIsValueExactAs()                         */
     180             : /************************************************************************/
     181             : /**
     182             :  * Returns whether a value can be exactly represented on type T.
     183             :  *
     184             :  * That is static_cast\<double\>(static_cast\<T\>(dfValue)) is legal and is
     185             :  * equal to dfValue.
     186             :  *
     187             :  * Note: for T=float or double, a NaN input leads to true
     188             :  *
     189             :  * @param dfValue the value
     190             :  * @return whether the value can be exactly represented on type T.
     191             :  */
     192        5170 : template <class T> inline bool GDALIsValueExactAs(double dfValue)
     193             : {
     194       10270 :     return GDALIsValueInRange<T>(dfValue) &&
     195       10252 :            static_cast<double>(static_cast<T>(dfValue)) == dfValue;
     196             : }
     197             : 
     198         141 : template <> inline bool GDALIsValueExactAs<float>(double dfValue)
     199             : {
     200         277 :     return CPLIsNan(dfValue) ||
     201         136 :            (GDALIsValueInRange<float>(dfValue) &&
     202         273 :             static_cast<double>(static_cast<float>(dfValue)) == dfValue);
     203             : }
     204             : 
     205           0 : template <> inline bool GDALIsValueExactAs<GFloat16>(double dfValue)
     206             : {
     207           0 :     return CPLIsNan(dfValue) ||
     208           0 :            (GDALIsValueInRange<GFloat16>(dfValue) &&
     209           0 :             static_cast<double>(static_cast<GFloat16>(dfValue)) == dfValue);
     210             : }
     211             : 
     212          16 : template <> inline bool GDALIsValueExactAs<double>(double)
     213             : {
     214          16 :     return true;
     215             : }
     216             : 
     217             : /************************************************************************/
     218             : /*                          GDALCopyWord()                              */
     219             : /************************************************************************/
     220             : 
     221             : // Integer input and output: clamp the input
     222             : 
     223             : template <class Tin, class Tout> struct sGDALCopyWord
     224             : {
     225   207733325 :     static inline void f(const Tin tValueIn, Tout &tValueOut)
     226             :     {
     227             :         Tin tMaxVal, tMinVal;
     228   207733325 :         GDALGetDataLimits<Tin, Tout>(tMaxVal, tMinVal);
     229   208648225 :         tValueOut =
     230   208226325 :             static_cast<Tout>(GDALClampValue(tValueIn, tMaxVal, tMinVal));
     231   208648225 :     }
     232             : };
     233             : 
     234             : // Integer input and floating point output: simply convert
     235             : 
     236             : template <class Tin> struct sGDALCopyWord<Tin, GFloat16>
     237             : {
     238      248152 :     static inline void f(const Tin tValueIn, GFloat16 &hfValueOut)
     239             :     {
     240      248152 :         hfValueOut = static_cast<GFloat16>(tValueIn);
     241      248152 :     }
     242             : };
     243             : 
     244             : template <class Tin> struct sGDALCopyWord<Tin, float>
     245             : {
     246    11480489 :     static inline void f(const Tin tValueIn, float &fValueOut)
     247             :     {
     248    11480489 :         fValueOut = static_cast<float>(tValueIn);
     249    11480489 :     }
     250             : };
     251             : 
     252             : template <class Tin> struct sGDALCopyWord<Tin, double>
     253             : {
     254    79842391 :     static inline void f(const Tin tValueIn, double &dfValueOut)
     255             :     {
     256    79842391 :         dfValueOut = static_cast<double>(tValueIn);
     257    79842391 :     }
     258             : };
     259             : 
     260             : // Floating point input and output, converting between identical types: simply copy
     261             : 
     262             : template <> struct sGDALCopyWord<GFloat16, GFloat16>
     263             : {
     264             :     static inline void f(const GFloat16 hfValueIn, GFloat16 &hfValueOut)
     265             :     {
     266             :         hfValueOut = hfValueIn;
     267             :     }
     268             : };
     269             : 
     270             : template <> struct sGDALCopyWord<float, float>
     271             : {
     272             :     static inline void f(const float fValueIn, float &fValueOut)
     273             :     {
     274             :         fValueOut = fValueIn;
     275             :     }
     276             : };
     277             : 
     278             : template <> struct sGDALCopyWord<double, double>
     279             : {
     280             :     static inline void f(const double dfValueIn, double &dfValueOut)
     281             :     {
     282             :         dfValueOut = dfValueIn;
     283             :     }
     284             : };
     285             : 
     286             : // Floating point input and output, converting to a larger type: use implicit conversion
     287             : 
     288             : template <> struct sGDALCopyWord<GFloat16, float>
     289             : {
     290        2605 :     static inline void f(const GFloat16 hfValueIn, float &dfValueOut)
     291             :     {
     292        2605 :         dfValueOut = hfValueIn;
     293        2605 :     }
     294             : };
     295             : 
     296             : template <> struct sGDALCopyWord<GFloat16, double>
     297             : {
     298      162074 :     static inline void f(const GFloat16 hfValueIn, double &dfValueOut)
     299             :     {
     300      162074 :         dfValueOut = hfValueIn;
     301      162074 :     }
     302             : };
     303             : 
     304             : template <> struct sGDALCopyWord<float, double>
     305             : {
     306    46829600 :     static inline void f(const float fValueIn, double &dfValueOut)
     307             :     {
     308    46829600 :         dfValueOut = fValueIn;
     309    46829600 :     }
     310             : };
     311             : 
     312             : // Floating point input and out, converting to a smaller type: ensure overflow results in infinity
     313             : 
     314             : template <> struct sGDALCopyWord<float, GFloat16>
     315             : {
     316         183 :     static inline void f(const float fValueIn, GFloat16 &hfValueOut)
     317             :     {
     318         183 :         if (fValueIn > cpl::NumericLimits<GFloat16>::max())
     319             :         {
     320           2 :             hfValueOut = cpl::NumericLimits<GFloat16>::infinity();
     321           2 :             return;
     322             :         }
     323         181 :         if (fValueIn < -cpl::NumericLimits<GFloat16>::max())
     324             :         {
     325           1 :             hfValueOut = -cpl::NumericLimits<GFloat16>::infinity();
     326           1 :             return;
     327             :         }
     328             : 
     329         180 :         hfValueOut = static_cast<GFloat16>(fValueIn);
     330             :     }
     331             : };
     332             : 
     333             : template <> struct sGDALCopyWord<double, GFloat16>
     334             : {
     335         575 :     static inline void f(const double dfValueIn, GFloat16 &hfValueOut)
     336             :     {
     337         575 :         if (dfValueIn > cpl::NumericLimits<GFloat16>::max())
     338             :         {
     339           0 :             hfValueOut = cpl::NumericLimits<GFloat16>::infinity();
     340           0 :             return;
     341             :         }
     342         575 :         if (dfValueIn < -cpl::NumericLimits<GFloat16>::max())
     343             :         {
     344           0 :             hfValueOut = -cpl::NumericLimits<GFloat16>::infinity();
     345           0 :             return;
     346             :         }
     347             : 
     348         575 :         hfValueOut = static_cast<GFloat16>(dfValueIn);
     349             :     }
     350             : };
     351             : 
     352             : template <> struct sGDALCopyWord<double, float>
     353             : {
     354     2339680 :     static inline void f(const double dfValueIn, float &fValueOut)
     355             :     {
     356     2339680 :         if (dfValueIn > std::numeric_limits<float>::max())
     357             :         {
     358          49 :             fValueOut = std::numeric_limits<float>::infinity();
     359          49 :             return;
     360             :         }
     361     2338540 :         if (dfValueIn < -std::numeric_limits<float>::max())
     362             :         {
     363           0 :             fValueOut = -std::numeric_limits<float>::infinity();
     364          54 :             return;
     365             :         }
     366             : 
     367     2339220 :         fValueOut = static_cast<float>(dfValueIn);
     368             :     }
     369             : };
     370             : 
     371             : // Floating point input to a small unsigned integer type: nan becomes zero, otherwise round and clamp
     372             : 
     373             : template <class Tout> struct sGDALCopyWord<GFloat16, Tout>
     374             : {
     375        1377 :     static inline void f(const GFloat16 hfValueIn, Tout &tValueOut)
     376             :     {
     377        1377 :         if (CPLIsNan(hfValueIn))
     378             :         {
     379           0 :             tValueOut = 0;
     380           0 :             return;
     381             :         }
     382             :         GFloat16 hfMaxVal, hfMinVal;
     383        1377 :         GDALGetDataLimits<GFloat16, Tout>(hfMaxVal, hfMinVal);
     384        1377 :         tValueOut = static_cast<Tout>(
     385        2754 :             GDALClampValue(hfValueIn + GFloat16(0.5f), hfMaxVal, hfMinVal));
     386             :     }
     387             : };
     388             : 
     389             : template <class Tout> struct sGDALCopyWord<float, Tout>
     390             : {
     391     4232930 :     static inline void f(const float fValueIn, Tout &tValueOut)
     392             :     {
     393     4232930 :         if (CPLIsNan(fValueIn))
     394             :         {
     395           0 :             tValueOut = 0;
     396           0 :             return;
     397             :         }
     398             :         float fMaxVal, fMinVal;
     399     4232930 :         GDALGetDataLimits<float, Tout>(fMaxVal, fMinVal);
     400     4232890 :         tValueOut = static_cast<Tout>(
     401     4232880 :             GDALClampValue(fValueIn + 0.5f, fMaxVal, fMinVal));
     402             :     }
     403             : };
     404             : 
     405             : template <class Tout> struct sGDALCopyWord<double, Tout>
     406             : {
     407    85944826 :     static inline void f(const double dfValueIn, Tout &tValueOut)
     408             :     {
     409    85944826 :         if (CPLIsNan(dfValueIn))
     410             :         {
     411           0 :             tValueOut = 0;
     412           0 :             return;
     413             :         }
     414             :         double dfMaxVal, dfMinVal;
     415    86080026 :         GDALGetDataLimits<double, Tout>(dfMaxVal, dfMinVal);
     416    86384826 :         tValueOut = static_cast<Tout>(
     417    84423426 :             GDALClampValue(dfValueIn + 0.5, dfMaxVal, dfMinVal));
     418             :     }
     419             : };
     420             : 
     421             : // Floating point input to a large unsigned integer type: nan becomes zero, otherwise round and clamp.
     422             : // Avoid roundoff while clamping.
     423             : 
     424             : template <> struct sGDALCopyWord<GFloat16, std::uint64_t>
     425             : {
     426         168 :     static inline void f(const GFloat16 hfValueIn, std::uint64_t &nValueOut)
     427             :     {
     428         168 :         if (!(hfValueIn > 0))
     429             :         {
     430           3 :             nValueOut = 0;
     431             :         }
     432         165 :         else if (CPLIsInf(hfValueIn))
     433             :         {
     434           1 :             nValueOut = cpl::NumericLimits<std::uint64_t>::max();
     435             :         }
     436             :         else
     437             :         {
     438         164 :             nValueOut = static_cast<std::uint64_t>(hfValueIn + GFloat16(0.5f));
     439             :         }
     440         168 :     }
     441             : };
     442             : 
     443             : template <> struct sGDALCopyWord<float, unsigned int>
     444             : {
     445        1155 :     static inline void f(const float fValueIn, unsigned int &nValueOut)
     446             :     {
     447        1155 :         if (!(fValueIn > 0))
     448             :         {
     449          34 :             nValueOut = 0;
     450             :         }
     451        1121 :         else if (fValueIn >=
     452        1121 :                  static_cast<float>(cpl::NumericLimits<unsigned int>::max()))
     453             :         {
     454          20 :             nValueOut = cpl::NumericLimits<unsigned int>::max();
     455             :         }
     456             :         else
     457             :         {
     458        1101 :             nValueOut = static_cast<unsigned int>(fValueIn + 0.5f);
     459             :         }
     460        1155 :     }
     461             : };
     462             : 
     463             : template <> struct sGDALCopyWord<float, std::uint64_t>
     464             : {
     465         168 :     static inline void f(const float fValueIn, std::uint64_t &nValueOut)
     466             :     {
     467         168 :         if (!(fValueIn > 0))
     468             :         {
     469           3 :             nValueOut = 0;
     470             :         }
     471         165 :         else if (fValueIn >=
     472         165 :                  static_cast<float>(cpl::NumericLimits<std::uint64_t>::max()))
     473             :         {
     474           2 :             nValueOut = cpl::NumericLimits<std::uint64_t>::max();
     475             :         }
     476             :         else
     477             :         {
     478         163 :             nValueOut = static_cast<std::uint64_t>(fValueIn + 0.5f);
     479             :         }
     480         168 :     }
     481             : };
     482             : 
     483             : template <> struct sGDALCopyWord<double, std::uint64_t>
     484             : {
     485         606 :     static inline void f(const double dfValueIn, std::uint64_t &nValueOut)
     486             :     {
     487         606 :         if (!(dfValueIn > 0))
     488             :         {
     489         165 :             nValueOut = 0;
     490             :         }
     491         441 :         else if (dfValueIn >
     492         441 :                  static_cast<double>(cpl::NumericLimits<uint64_t>::max()))
     493             :         {
     494           4 :             nValueOut = cpl::NumericLimits<uint64_t>::max();
     495             :         }
     496             :         else
     497             :         {
     498         437 :             nValueOut = static_cast<std::uint64_t>(dfValueIn + 0.5);
     499             :         }
     500         606 :     }
     501             : };
     502             : 
     503             : // Floating point input to a very large unsigned integer type: nan becomes zero, otherwise round and clamp.
     504             : // Avoid infinity while clamping when the maximum integer is too large for the floating-point type.
     505             : // Avoid roundoff while clamping.
     506             : 
     507             : template <> struct sGDALCopyWord<GFloat16, unsigned short>
     508             : {
     509        1165 :     static inline void f(const GFloat16 hfValueIn, unsigned short &nValueOut)
     510             :     {
     511        1165 :         if (!(hfValueIn > 0))
     512             :         {
     513          44 :             nValueOut = 0;
     514             :         }
     515        1121 :         else if (CPLIsInf(hfValueIn))
     516             :         {
     517          10 :             nValueOut = cpl::NumericLimits<unsigned short>::max();
     518             :         }
     519             :         else
     520             :         {
     521        1111 :             nValueOut = static_cast<unsigned short>(hfValueIn + GFloat16(0.5f));
     522             :         }
     523        1165 :     }
     524             : };
     525             : 
     526             : template <> struct sGDALCopyWord<GFloat16, unsigned int>
     527             : {
     528        1155 :     static inline void f(const GFloat16 hfValueIn, unsigned int &nValueOut)
     529             :     {
     530        1155 :         if (!(hfValueIn > 0))
     531             :         {
     532          34 :             nValueOut = 0;
     533             :         }
     534        1121 :         else if (CPLIsInf(hfValueIn))
     535             :         {
     536           0 :             nValueOut = cpl::NumericLimits<unsigned int>::max();
     537             :         }
     538             :         else
     539             :         {
     540        1121 :             nValueOut = static_cast<unsigned int>(hfValueIn + GFloat16(0.5f));
     541             :         }
     542        1155 :     }
     543             : };
     544             : 
     545             : // Floating point input to a small signed integer type: nan becomes zero, otherwise round and clamp.
     546             : // Rounding for signed integers is different than for the unsigned integers above.
     547             : 
     548             : template <> struct sGDALCopyWord<GFloat16, signed char>
     549             : {
     550         233 :     static inline void f(const GFloat16 hfValueIn, signed char &nValueOut)
     551             :     {
     552         233 :         if (CPLIsNan(hfValueIn))
     553             :         {
     554           0 :             nValueOut = 0;
     555           0 :             return;
     556             :         }
     557             :         GFloat16 hfMaxVal, hfMinVal;
     558         233 :         GDALGetDataLimits<GFloat16, signed char>(hfMaxVal, hfMinVal);
     559         233 :         GFloat16 hfValue = hfValueIn >= GFloat16(0.0f)
     560         163 :                                ? hfValueIn + GFloat16(0.5f)
     561         233 :                                : hfValueIn - GFloat16(0.5f);
     562         233 :         nValueOut = static_cast<signed char>(
     563         466 :             GDALClampValue(hfValue, hfMaxVal, hfMinVal));
     564             :     }
     565             : };
     566             : 
     567             : template <> struct sGDALCopyWord<float, signed char>
     568             : {
     569         317 :     static inline void f(const float fValueIn, signed char &nValueOut)
     570             :     {
     571         317 :         if (CPLIsNan(fValueIn))
     572             :         {
     573           0 :             nValueOut = 0;
     574           0 :             return;
     575             :         }
     576             :         float fMaxVal, fMinVal;
     577         317 :         GDALGetDataLimits<float, signed char>(fMaxVal, fMinVal);
     578         317 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     579         317 :         nValueOut =
     580         317 :             static_cast<signed char>(GDALClampValue(fValue, fMaxVal, fMinVal));
     581             :     }
     582             : };
     583             : 
     584             : template <> struct sGDALCopyWord<float, short>
     585             : {
     586     2932640 :     static inline void f(const float fValueIn, short &nValueOut)
     587             :     {
     588     2932640 :         if (CPLIsNan(fValueIn))
     589             :         {
     590           0 :             nValueOut = 0;
     591           0 :             return;
     592             :         }
     593             :         float fMaxVal, fMinVal;
     594     2932640 :         GDALGetDataLimits<float, short>(fMaxVal, fMinVal);
     595     2932640 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     596     2932640 :         nValueOut =
     597     2932640 :             static_cast<short>(GDALClampValue(fValue, fMaxVal, fMinVal));
     598             :     }
     599             : };
     600             : 
     601             : template <> struct sGDALCopyWord<double, signed char>
     602             : {
     603         465 :     static inline void f(const double dfValueIn, signed char &nValueOut)
     604             :     {
     605         465 :         if (CPLIsNan(dfValueIn))
     606             :         {
     607           0 :             nValueOut = 0;
     608           0 :             return;
     609             :         }
     610             :         double dfMaxVal, dfMinVal;
     611         465 :         GDALGetDataLimits<double, signed char>(dfMaxVal, dfMinVal);
     612         465 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     613         465 :         nValueOut = static_cast<signed char>(
     614         465 :             GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     615             :     }
     616             : };
     617             : 
     618             : template <> struct sGDALCopyWord<double, short>
     619             : {
     620     5106180 :     static inline void f(const double dfValueIn, short &nValueOut)
     621             :     {
     622     5106180 :         if (CPLIsNan(dfValueIn))
     623             :         {
     624           0 :             nValueOut = 0;
     625           0 :             return;
     626             :         }
     627             :         double dfMaxVal, dfMinVal;
     628     5106180 :         GDALGetDataLimits<double, short>(dfMaxVal, dfMinVal);
     629     5106090 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     630     5106020 :         nValueOut =
     631     5106090 :             static_cast<short>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     632             :     }
     633             : };
     634             : 
     635             : template <> struct sGDALCopyWord<double, int>
     636             : {
     637    77083100 :     static inline void f(const double dfValueIn, int &nValueOut)
     638             :     {
     639    77083100 :         if (CPLIsNan(dfValueIn))
     640             :         {
     641           0 :             nValueOut = 0;
     642           0 :             return;
     643             :         }
     644             :         double dfMaxVal, dfMinVal;
     645    77083100 :         GDALGetDataLimits<double, int>(dfMaxVal, dfMinVal);
     646    77083100 :         double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     647    77083100 :         nValueOut =
     648    77083100 :             static_cast<int>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     649             :     }
     650             : };
     651             : 
     652             : // Floating point input to a large signed integer type: nan becomes zero, otherwise round and clamp.
     653             : // Rounding for signed integers is different than for the unsigned integers above.
     654             : // Avoid roundoff while clamping.
     655             : 
     656             : template <> struct sGDALCopyWord<GFloat16, short>
     657             : {
     658        1349 :     static inline void f(const GFloat16 hfValueIn, short &nValueOut)
     659             :     {
     660        1349 :         if (CPLIsNan(hfValueIn))
     661             :         {
     662           0 :             nValueOut = 0;
     663             :         }
     664        1349 :         else if (hfValueIn >=
     665        1349 :                  static_cast<GFloat16>(cpl::NumericLimits<short>::max()))
     666             :         {
     667          32 :             nValueOut = cpl::NumericLimits<short>::max();
     668             :         }
     669        1317 :         else if (hfValueIn <=
     670        1317 :                  static_cast<GFloat16>(cpl::NumericLimits<short>::lowest()))
     671             :         {
     672          42 :             nValueOut = cpl::NumericLimits<short>::lowest();
     673             :         }
     674             :         else
     675             :         {
     676        2550 :             nValueOut = static_cast<short>(hfValueIn > GFloat16(0.0f)
     677        1275 :                                                ? hfValueIn + GFloat16(0.5f)
     678        1397 :                                                : hfValueIn - GFloat16(0.5f));
     679             :         }
     680        1349 :     }
     681             : };
     682             : 
     683             : template <> struct sGDALCopyWord<float, int>
     684             : {
     685   153604000 :     static inline void f(const float fValueIn, int &nValueOut)
     686             :     {
     687   153604000 :         if (CPLIsNan(fValueIn))
     688             :         {
     689           0 :             nValueOut = 0;
     690             :         }
     691   156586000 :         else if (fValueIn >= static_cast<float>(cpl::NumericLimits<int>::max()))
     692             :         {
     693         160 :             nValueOut = cpl::NumericLimits<int>::max();
     694             :         }
     695   152691000 :         else if (fValueIn <=
     696   154764000 :                  static_cast<float>(cpl::NumericLimits<int>::lowest()))
     697             :         {
     698           0 :             nValueOut = cpl::NumericLimits<int>::lowest();
     699             :         }
     700             :         else
     701             :         {
     702   156318000 :             nValueOut = static_cast<int>(fValueIn > 0.0f ? fValueIn + 0.5f
     703      120987 :                                                          : fValueIn - 0.5f);
     704             :         }
     705   156197000 :     }
     706             : };
     707             : 
     708             : template <> struct sGDALCopyWord<float, std::int64_t>
     709             : {
     710         238 :     static inline void f(const float fValueIn, std::int64_t &nValueOut)
     711             :     {
     712         238 :         if (CPLIsNan(fValueIn))
     713             :         {
     714           1 :             nValueOut = 0;
     715             :         }
     716         237 :         else if (fValueIn >=
     717         237 :                  static_cast<float>(cpl::NumericLimits<std::int64_t>::max()))
     718             :         {
     719           2 :             nValueOut = cpl::NumericLimits<std::int64_t>::max();
     720             :         }
     721         235 :         else if (fValueIn <=
     722         235 :                  static_cast<float>(cpl::NumericLimits<std::int64_t>::lowest()))
     723             :         {
     724           2 :             nValueOut = cpl::NumericLimits<std::int64_t>::lowest();
     725             :         }
     726             :         else
     727             :         {
     728         466 :             nValueOut = static_cast<std::int64_t>(
     729         233 :                 fValueIn > 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f);
     730             :         }
     731         238 :     }
     732             : };
     733             : 
     734             : template <> struct sGDALCopyWord<double, std::int64_t>
     735             : {
     736         690 :     static inline void f(const double dfValueIn, std::int64_t &nValueOut)
     737             :     {
     738         690 :         if (CPLIsNan(dfValueIn))
     739             :         {
     740           1 :             nValueOut = 0;
     741             :         }
     742         689 :         else if (dfValueIn >=
     743         689 :                  static_cast<double>(cpl::NumericLimits<std::int64_t>::max()))
     744             :         {
     745           6 :             nValueOut = cpl::NumericLimits<std::int64_t>::max();
     746             :         }
     747         683 :         else if (dfValueIn <=
     748         683 :                  static_cast<double>(cpl::NumericLimits<std::int64_t>::min()))
     749             :         {
     750           4 :             nValueOut = cpl::NumericLimits<std::int64_t>::min();
     751             :         }
     752             :         else
     753             :         {
     754        1358 :             nValueOut = static_cast<std::int64_t>(
     755         679 :                 dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5);
     756             :         }
     757         690 :     }
     758             : };
     759             : 
     760             : // Floating point input to a very large signed integer type: nan becomes zero, otherwise round and clamp.
     761             : // Rounding for signed integers is different than for the unsigned integers above.
     762             : // Avoid infinity while clamping when the maximum integer is too large for the floating-point type.
     763             : // Avoid roundoff while clamping.
     764             : 
     765             : template <> struct sGDALCopyWord<GFloat16, int>
     766             : {
     767        1339 :     static inline void f(const GFloat16 hfValueIn, int &nValueOut)
     768             :     {
     769        1339 :         if (CPLIsNan(hfValueIn))
     770             :         {
     771           0 :             nValueOut = 0;
     772             :         }
     773        1339 :         else if (CPLIsInf(hfValueIn))
     774             :         {
     775           0 :             nValueOut = hfValueIn > GFloat16(0.0f)
     776           0 :                             ? cpl::NumericLimits<int>::max()
     777           0 :                             : cpl::NumericLimits<int>::lowest();
     778             :         }
     779             :         else
     780             :         {
     781        2678 :             nValueOut = static_cast<int>(hfValueIn > GFloat16(0.0f)
     782        1339 :                                              ? hfValueIn + GFloat16(0.5f)
     783        1493 :                                              : hfValueIn - GFloat16(0.5f));
     784             :         }
     785        1339 :     }
     786             : };
     787             : 
     788             : template <> struct sGDALCopyWord<GFloat16, std::int64_t>
     789             : {
     790         238 :     static inline void f(const GFloat16 hfValueIn, std::int64_t &nValueOut)
     791             :     {
     792         238 :         if (CPLIsNan(hfValueIn))
     793             :         {
     794           1 :             nValueOut = 0;
     795             :         }
     796         237 :         else if (CPLIsInf(hfValueIn))
     797             :         {
     798           4 :             nValueOut = hfValueIn > GFloat16(0.0f)
     799           2 :                             ? cpl::NumericLimits<std::int64_t>::max()
     800           1 :                             : cpl::NumericLimits<std::int64_t>::lowest();
     801             :         }
     802             :         else
     803             :         {
     804         235 :             nValueOut = static_cast<std::int64_t>(
     805         235 :                 hfValueIn > GFloat16(0.0f) ? hfValueIn + GFloat16(0.5f)
     806         306 :                                            : hfValueIn - GFloat16(0.5f));
     807             :         }
     808         238 :     }
     809             : };
     810             : 
     811             : /**
     812             :  * Copy a single word, optionally rounding if appropriate (i.e. going
     813             :  * from the float to the integer case). Note that this is the function
     814             :  * you should specialize if you're adding a new data type.
     815             :  *
     816             :  * @param tValueIn value of type Tin; the input value to be converted
     817             :  * @param tValueOut value of type Tout; the output value
     818             :  */
     819             : 
     820             : template <class Tin, class Tout>
     821   708898366 : inline void GDALCopyWord(const Tin tValueIn, Tout &tValueOut)
     822             : {
     823             :     if constexpr (std::is_same<Tin, Tout>::value)
     824    28297123 :         tValueOut = tValueIn;
     825             :     else
     826   680601243 :         sGDALCopyWord<Tin, Tout>::f(tValueIn, tValueOut);
     827   707390026 : }
     828             : 
     829             : /************************************************************************/
     830             : /*                         GDALCopy4Words()                             */
     831             : /************************************************************************/
     832             : /**
     833             :  * Copy 4 packed words to 4 packed words, optionally rounding if appropriate
     834             :  * (i.e. going from the float to the integer case).
     835             :  *
     836             :  * @param pValueIn pointer to 4 input values of type Tin.
     837             :  * @param pValueOut pointer to 4 output values of type Tout.
     838             :  */
     839             : 
     840             : template <class Tin, class Tout>
     841         128 : inline void GDALCopy4Words(const Tin *pValueIn, Tout *const pValueOut)
     842             : {
     843         128 :     GDALCopyWord(pValueIn[0], pValueOut[0]);
     844         128 :     GDALCopyWord(pValueIn[1], pValueOut[1]);
     845         128 :     GDALCopyWord(pValueIn[2], pValueOut[2]);
     846         128 :     GDALCopyWord(pValueIn[3], pValueOut[3]);
     847         128 : }
     848             : 
     849             : /************************************************************************/
     850             : /*                         GDALCopy8Words()                             */
     851             : /************************************************************************/
     852             : /**
     853             :  * Copy 8 packed words to 8 packed words, optionally rounding if appropriate
     854             :  * (i.e. going from the float to the integer case).
     855             :  *
     856             :  * @param pValueIn pointer to 8 input values of type Tin.
     857             :  * @param pValueOut pointer to 8 output values of type Tout.
     858             :  */
     859             : 
     860             : template <class Tin, class Tout>
     861    17795265 : inline void GDALCopy8Words(const Tin *pValueIn, Tout *const pValueOut)
     862             : {
     863    17795265 :     GDALCopy4Words(pValueIn, pValueOut);
     864    17800365 :     GDALCopy4Words(pValueIn + 4, pValueOut + 4);
     865    17797665 : }
     866             : 
     867             : // Needs SSE2
     868             : #if defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2) ||               \
     869             :     defined(USE_NEON_OPTIMIZATIONS)
     870             : 
     871             : #ifdef USE_NEON_OPTIMIZATIONS
     872             : #include "include_sse2neon.h"
     873             : #else
     874             : #include <emmintrin.h>
     875             : #endif
     876             : 
     877    38505215 : static inline void GDALCopyXMMToInt32(const __m128i xmm, void *pDest)
     878             : {
     879    38505215 :     int n32 = _mm_cvtsi128_si32(xmm);  // Extract lower 32 bit word
     880    38505215 :     memcpy(pDest, &n32, sizeof(n32));
     881    38505215 : }
     882             : 
     883    89082151 : static inline void GDALCopyXMMToInt64(const __m128i xmm, void *pDest)
     884             : {
     885             :     _mm_storel_epi64(reinterpret_cast<__m128i *>(pDest), xmm);
     886    89082151 : }
     887             : 
     888             : #if __SSSE3__
     889             : #include <tmmintrin.h>
     890             : #endif
     891             : 
     892             : #if defined(__SSE4_1__) || defined(__AVX__)
     893             : #include <smmintrin.h>
     894             : #endif
     895             : 
     896             : template <>
     897    32217602 : inline void GDALCopy4Words(const float *pValueIn, GByte *const pValueOut)
     898             : {
     899    32217602 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     900             : 
     901             :     // The following clamping would be useless due to the final saturating
     902             :     // packing if we could guarantee the input range in [INT_MIN,INT_MAX]
     903    32217602 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     904    32217602 :     const __m128 xmm_max = _mm_set1_ps(255);
     905    32217602 :     xmm = _mm_add_ps(xmm, p0d5);
     906    64444104 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     907             : 
     908    32225402 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     909             : 
     910             : #if defined(__SSSE3__) || defined(USE_NEON_OPTIMIZATIONS)
     911             :     xmm_i = _mm_shuffle_epi8(
     912             :         xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) | (12 << 24)));
     913             : #else
     914    32228702 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);   // Pack int32 to int16
     915    32230502 :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);  // Pack int16 to uint8
     916             : #endif
     917    32230502 :     GDALCopyXMMToInt32(xmm_i, pValueOut);
     918    32205802 : }
     919             : 
     920             : template <>
     921     3363400 : inline void GDALCopy4Words(const float *pValueIn, GInt16 *const pValueOut)
     922             : {
     923     3363400 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     924             : 
     925     3363400 :     const __m128 xmm_min = _mm_set1_ps(-32768);
     926     3363400 :     const __m128 xmm_max = _mm_set1_ps(32767);
     927     6726800 :     xmm = _mm_min_ps(_mm_max_ps(xmm, xmm_min), xmm_max);
     928             : 
     929     3363400 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     930     3363400 :     const __m128 m0d5 = _mm_set1_ps(-0.5f);
     931     3363400 :     const __m128 mask = _mm_cmpge_ps(xmm, p0d5);
     932             :     // f >= 0.5f ? f + 0.5f : f - 0.5f
     933    13453600 :     xmm = _mm_add_ps(
     934             :         xmm, _mm_or_ps(_mm_and_ps(mask, p0d5), _mm_andnot_ps(mask, m0d5)));
     935             : 
     936     3363400 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     937             : 
     938     3363400 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     939     3363400 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     940     3363400 : }
     941             : 
     942             : template <>
     943           1 : inline void GDALCopy4Words(const float *pValueIn, GUInt16 *const pValueOut)
     944             : {
     945           1 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     946             : 
     947           1 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     948           1 :     const __m128 xmm_max = _mm_set1_ps(65535);
     949           1 :     xmm = _mm_add_ps(xmm, p0d5);
     950           2 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     951             : 
     952           1 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     953             : 
     954             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
     955             :     xmm_i = _mm_packus_epi32(xmm_i, xmm_i);  // Pack int32 to uint16
     956             : #else
     957             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
     958           2 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
     959           1 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     960             :     // Translate back to uint16 range (actually -32768==32768 in int16)
     961           1 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
     962             : #endif
     963           1 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     964           1 : }
     965             : 
     966             : #ifdef __AVX2__
     967             : 
     968             : #include <immintrin.h>
     969             : 
     970             : template <>
     971             : inline void GDALCopy8Words(const float *pValueIn, GByte *const pValueOut)
     972             : {
     973             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     974             : 
     975             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     976             :     const __m256 ymm_max = _mm256_set1_ps(255);
     977             :     ymm = _mm256_add_ps(ymm, p0d5);
     978             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     979             : 
     980             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
     981             : 
     982             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
     983             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
     984             : 
     985             :     __m128i xmm_i = _mm256_castsi256_si128(ymm_i);
     986             :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);
     987             :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     988             : }
     989             : 
     990             : template <>
     991             : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
     992             : {
     993             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     994             : 
     995             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     996             :     const __m256 ymm_max = _mm256_set1_ps(65535);
     997             :     ymm = _mm256_add_ps(ymm, p0d5);
     998             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     999             : 
    1000             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
    1001             : 
    1002             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
    1003             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
    1004             : 
    1005             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut),
    1006             :                      _mm256_castsi256_si128(ymm_i));
    1007             : }
    1008             : #else
    1009             : template <>
    1010     7758691 : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
    1011             : {
    1012     7758691 :     __m128 xmm = _mm_loadu_ps(pValueIn);
    1013    15517402 :     __m128 xmm1 = _mm_loadu_ps(pValueIn + 4);
    1014             : 
    1015     7758691 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
    1016     7758691 :     const __m128 xmm_max = _mm_set1_ps(65535);
    1017     7758691 :     xmm = _mm_add_ps(xmm, p0d5);
    1018     7758691 :     xmm1 = _mm_add_ps(xmm1, p0d5);
    1019    15520702 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
    1020    15517002 :     xmm1 = _mm_min_ps(_mm_max_ps(xmm1, p0d5), xmm_max);
    1021             : 
    1022     7759911 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
    1023     7761671 :     __m128i xmm1_i = _mm_cvttps_epi32(xmm1);
    1024             : 
    1025             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
    1026             :     xmm_i = _mm_packus_epi32(xmm_i, xmm1_i);  // Pack int32 to uint16
    1027             : #else
    1028             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
    1029    15523302 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
    1030    15523302 :     xmm1_i = _mm_add_epi32(xmm1_i, _mm_set1_epi32(-32768));
    1031     7759161 :     xmm_i = _mm_packs_epi32(xmm_i, xmm1_i);  // Pack int32 to int16
    1032             :     // Translate back to uint16 range (actually -32768==32768 in int16)
    1033    15518302 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
    1034             : #endif
    1035             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut), xmm_i);
    1036     7759161 : }
    1037             : #endif
    1038             : 
    1039             : #ifdef notdef_because_slightly_slower_than_default_implementation
    1040             : template <>
    1041             : inline void GDALCopy4Words(const double *pValueIn, float *const pValueOut)
    1042             : {
    1043             :     __m128d float_posmax = _mm_set1_pd(std::numeric_limits<float>::max());
    1044             :     __m128d float_negmax = _mm_set1_pd(-std::numeric_limits<float>::max());
    1045             :     __m128d float_posinf = _mm_set1_pd(std::numeric_limits<float>::infinity());
    1046             :     __m128d float_neginf = _mm_set1_pd(-std::numeric_limits<float>::infinity());
    1047             :     __m128d val01 = _mm_loadu_pd(pValueIn);
    1048             :     __m128d val23 = _mm_loadu_pd(pValueIn + 2);
    1049             :     __m128d mask_max = _mm_cmpge_pd(val01, float_posmax);
    1050             :     __m128d mask_max23 = _mm_cmpge_pd(val23, float_posmax);
    1051             :     val01 = _mm_or_pd(_mm_and_pd(mask_max, float_posinf),
    1052             :                       _mm_andnot_pd(mask_max, val01));
    1053             :     val23 = _mm_or_pd(_mm_and_pd(mask_max23, float_posinf),
    1054             :                       _mm_andnot_pd(mask_max23, val23));
    1055             :     __m128d mask_min = _mm_cmple_pd(val01, float_negmax);
    1056             :     __m128d mask_min23 = _mm_cmple_pd(val23, float_negmax);
    1057             :     val01 = _mm_or_pd(_mm_and_pd(mask_min, float_neginf),
    1058             :                       _mm_andnot_pd(mask_min, val01));
    1059             :     val23 = _mm_or_pd(_mm_and_pd(mask_min23, float_neginf),
    1060             :                       _mm_andnot_pd(mask_min23, val23));
    1061             :     __m128 val01_s = _mm_cvtpd_ps(val01);
    1062             :     __m128 val23_s = _mm_cvtpd_ps(val23);
    1063             :     __m128i val01_i = _mm_castps_si128(val01_s);
    1064             :     __m128i val23_i = _mm_castps_si128(val23_s);
    1065             :     GDALCopyXMMToInt64(val01_i, pValueOut);
    1066             :     GDALCopyXMMToInt64(val23_i, pValueOut + 2);
    1067             : }
    1068             : #endif
    1069             : 
    1070             : #endif  //  defined(__x86_64) || defined(_M_X64)
    1071             : 
    1072             : #endif  // GDAL_PRIV_TEMPLATES_HPP_INCLUDED

Generated by: LCOV version 1.14