LCOV - code coverage report
Current view: top level - gcore - gdal_priv_templates.hpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 239 254 94.1 %
Date: 2024-11-21 22:18:42 Functions: 315 324 97.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  GDAL Core
       5             :  * Purpose:  Inline C++ templates
       6             :  * Author:   Phil Vachon, <philippe at cowpig.ca>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2009, Phil Vachon, <philippe at cowpig.ca>
      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 <cmath>
      20             : #include <cstdint>
      21             : #include <limits>
      22             : 
      23             : /************************************************************************/
      24             : /*                        GDALGetDataLimits()                           */
      25             : /************************************************************************/
      26             : /**
      27             :  * Compute the limits of values that can be placed in Tout in terms of
      28             :  * Tin. Usually used for output clamping, when the output data type's
      29             :  * limits are stable relative to the input type (i.e. no roundoff error).
      30             :  *
      31             :  * @param tMaxValue the returned maximum value
      32             :  * @param tMinValue the returned minimum value
      33             :  */
      34             : 
      35             : template <class Tin, class Tout>
      36   382787770 : inline void GDALGetDataLimits(Tin &tMaxValue, Tin &tMinValue)
      37             : {
      38   382787770 :     tMaxValue = std::numeric_limits<Tin>::max();
      39   382599350 :     tMinValue = std::numeric_limits<Tin>::min();
      40             : 
      41             :     // Compute the actual minimum value of Tout in terms of Tin.
      42             :     if constexpr (std::numeric_limits<Tout>::is_signed &&
      43             :                   std::numeric_limits<Tout>::is_integer)
      44             :     {
      45             :         // the minimum value is less than zero
      46             :         if constexpr (std::numeric_limits<Tout>::digits <
      47             :                           std::numeric_limits<Tin>::digits ||
      48             :                       !std::numeric_limits<Tin>::is_integer)
      49             :         {
      50             :             // Tout is smaller than Tin, so we need to clamp values in input
      51             :             // to the range of Tout's min/max values
      52             :             if (std::numeric_limits<Tin>::is_signed)
      53             :             {
      54    78396758 :                 tMinValue = static_cast<Tin>(std::numeric_limits<Tout>::min());
      55             :             }
      56    78752990 :             tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
      57             :         }
      58             :     }
      59             :     else if constexpr (std::numeric_limits<Tout>::is_integer)
      60             :     {
      61             :         // the output is unsigned, so we just need to determine the max
      62             :         /* coverity[same_on_both_sides] */
      63             :         if constexpr (std::numeric_limits<Tout>::digits <=
      64             :                       std::numeric_limits<Tin>::digits)
      65             :         {
      66             :             // Tout is smaller than Tin, so we need to clamp the input values
      67             :             // to the range of Tout's max
      68   140570881 :             tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
      69             :         }
      70   141500745 :         tMinValue = 0;
      71             :     }
      72   380867580 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                          GDALClampValue()                            */
      76             : /************************************************************************/
      77             : /**
      78             :  * Clamp values of type T to a specified range
      79             :  *
      80             :  * @param tValue the value
      81             :  * @param tMax the max value
      82             :  * @param tMin the min value
      83             :  */
      84             : template <class T>
      85   380670292 : inline T GDALClampValue(const T tValue, const T tMax, const T tMin)
      86             : {
      87   380670292 :     return tValue > tMax ? tMax : tValue < tMin ? tMin : tValue;
      88             : }
      89             : 
      90             : /************************************************************************/
      91             : /*                          GDALClampDoubleValue()                            */
      92             : /************************************************************************/
      93             : /**
      94             :  * Clamp double values to a specified range, this uses the same
      95             :  * argument ordering as std::clamp, returns TRUE if the value was clamped.
      96             :  *
      97             :  * @param tValue the value
      98             :  * @param tMin the min value
      99             :  * @param tMax the max value
     100             :  *
     101             :  */
     102             : template <class T2, class T3>
     103         166 : inline bool GDALClampDoubleValue(double &tValue, const T2 tMin, const T3 tMax)
     104             : {
     105         166 :     const double tMin2{static_cast<double>(tMin)};
     106         166 :     const double tMax2{static_cast<double>(tMax)};
     107         166 :     if (tValue > tMax2 || tValue < tMin2)
     108             :     {
     109          22 :         tValue = tValue > tMax2 ? tMax2 : tValue < tMin2 ? tMin2 : tValue;
     110          22 :         return true;
     111             :     }
     112             :     else
     113             :     {
     114         144 :         return false;
     115             :     }
     116             : }
     117             : 
     118             : /************************************************************************/
     119             : /*                         GDALIsValueInRange()                         */
     120             : /************************************************************************/
     121             : /**
     122             :  * Returns whether a value is in the type range.
     123             :  * NaN is considered not to be in type range.
     124             :  *
     125             :  * @param dfValue the value
     126             :  * @return whether the value is in the type range.
     127             :  */
     128      122084 : template <class T> inline bool GDALIsValueInRange(double dfValue)
     129             : {
     130      244122 :     return dfValue >= static_cast<double>(std::numeric_limits<T>::lowest()) &&
     131      244122 :            dfValue <= static_cast<double>(std::numeric_limits<T>::max());
     132             : }
     133             : 
     134          20 : template <> inline bool GDALIsValueInRange<double>(double dfValue)
     135             : {
     136          20 :     return !std::isnan(dfValue);
     137             : }
     138             : 
     139        2078 : template <> inline bool GDALIsValueInRange<float>(double dfValue)
     140             : {
     141        4085 :     return std::isinf(dfValue) ||
     142        2007 :            (dfValue >= -std::numeric_limits<float>::max() &&
     143        4080 :             dfValue <= std::numeric_limits<float>::max());
     144             : }
     145             : 
     146        6814 : template <> inline bool GDALIsValueInRange<int64_t>(double dfValue)
     147             : {
     148             :     // Values in the range [INT64_MAX - 1023, INT64_MAX - 1]
     149             :     // get converted to a double that once cast to int64_t is
     150             :     // INT64_MAX + 1, hence the < strict comparison.
     151             :     return dfValue >=
     152       13627 :                static_cast<double>(std::numeric_limits<int64_t>::min()) &&
     153       13627 :            dfValue < static_cast<double>(std::numeric_limits<int64_t>::max());
     154             : }
     155             : 
     156        7981 : template <> inline bool GDALIsValueInRange<uint64_t>(double dfValue)
     157             : {
     158             :     // Values in the range [UINT64_MAX - 2047, UINT64_MAX - 1]
     159             :     // get converted to a double that once cast to uint64_t is
     160             :     // UINT64_MAX + 1, hence the < strict comparison.
     161       15959 :     return dfValue >= 0 &&
     162       15959 :            dfValue < static_cast<double>(std::numeric_limits<uint64_t>::max());
     163             : }
     164             : 
     165             : /************************************************************************/
     166             : /*                         GDALIsValueExactAs()                         */
     167             : /************************************************************************/
     168             : /**
     169             :  * Returns whether a value can be exactly represented on type T.
     170             :  *
     171             :  * That is static_cast\<double\>(static_cast\<T\>(dfValue)) is legal and is
     172             :  * equal to dfValue.
     173             :  *
     174             :  * Note: for T=float or double, a NaN input leads to true
     175             :  *
     176             :  * @param dfValue the value
     177             :  * @return whether the value can be exactly represented on type T.
     178             :  */
     179         524 : template <class T> inline bool GDALIsValueExactAs(double dfValue)
     180             : {
     181        1003 :     return GDALIsValueInRange<T>(dfValue) &&
     182        1003 :            static_cast<double>(static_cast<T>(dfValue)) == dfValue;
     183             : }
     184             : 
     185          97 : template <> inline bool GDALIsValueExactAs<float>(double dfValue)
     186             : {
     187         277 :     return std::isnan(dfValue) ||
     188          92 :            (GDALIsValueInRange<float>(dfValue) &&
     189         185 :             static_cast<double>(static_cast<float>(dfValue)) == dfValue);
     190             : }
     191             : 
     192          16 : template <> inline bool GDALIsValueExactAs<double>(double)
     193             : {
     194          16 :     return true;
     195             : }
     196             : 
     197             : /************************************************************************/
     198             : /*                          GDALCopyWord()                              */
     199             : /************************************************************************/
     200             : 
     201             : template <class Tin, class Tout> struct sGDALCopyWord
     202             : {
     203   219868286 :     static inline void f(const Tin tValueIn, Tout &tValueOut)
     204             :     {
     205             :         Tin tMaxVal, tMinVal;
     206   219868286 :         GDALGetDataLimits<Tin, Tout>(tMaxVal, tMinVal);
     207   219916686 :         tValueOut =
     208   219840786 :             static_cast<Tout>(GDALClampValue(tValueIn, tMaxVal, tMinVal));
     209   219916686 :     }
     210             : };
     211             : 
     212             : template <class Tin> struct sGDALCopyWord<Tin, float>
     213             : {
     214    10886408 :     static inline void f(const Tin tValueIn, float &fValueOut)
     215             :     {
     216    10886408 :         fValueOut = static_cast<float>(tValueIn);
     217    10886408 :     }
     218             : };
     219             : 
     220             : template <class Tin> struct sGDALCopyWord<Tin, double>
     221             : {
     222    73017288 :     static inline void f(const Tin tValueIn, double &dfValueOut)
     223             :     {
     224    73017288 :         dfValueOut = static_cast<double>(tValueIn);
     225    73017288 :     }
     226             : };
     227             : 
     228             : template <> struct sGDALCopyWord<double, double>
     229             : {
     230    10083900 :     static inline void f(const double dfValueIn, double &dfValueOut)
     231             :     {
     232    10083900 :         dfValueOut = dfValueIn;
     233    10083900 :     }
     234             : };
     235             : 
     236             : template <> struct sGDALCopyWord<float, float>
     237             : {
     238     7858220 :     static inline void f(const float fValueIn, float &fValueOut)
     239             :     {
     240     7858220 :         fValueOut = fValueIn;
     241     7858220 :     }
     242             : };
     243             : 
     244             : template <> struct sGDALCopyWord<float, double>
     245             : {
     246    46466200 :     static inline void f(const float fValueIn, double &dfValueOut)
     247             :     {
     248    46466200 :         dfValueOut = fValueIn;
     249    46466200 :     }
     250             : };
     251             : 
     252             : template <> struct sGDALCopyWord<double, float>
     253             : {
     254     2303450 :     static inline void f(const double dfValueIn, float &fValueOut)
     255             :     {
     256     2303450 :         if (dfValueIn > std::numeric_limits<float>::max())
     257             :         {
     258          48 :             fValueOut = std::numeric_limits<float>::infinity();
     259          48 :             return;
     260             :         }
     261     2303400 :         if (dfValueIn < -std::numeric_limits<float>::max())
     262             :         {
     263          52 :             fValueOut = -std::numeric_limits<float>::infinity();
     264          52 :             return;
     265             :         }
     266             : 
     267     2303350 :         fValueOut = static_cast<float>(dfValueIn);
     268             :     }
     269             : };
     270             : 
     271             : template <class Tout> struct sGDALCopyWord<float, Tout>
     272             : {
     273     3976980 :     static inline void f(const float fValueIn, Tout &tValueOut)
     274             :     {
     275     3976980 :         if (std::isnan(fValueIn))
     276             :         {
     277           0 :             tValueOut = 0;
     278           0 :             return;
     279             :         }
     280             :         float fMaxVal, fMinVal;
     281     3977270 :         GDALGetDataLimits<float, Tout>(fMaxVal, fMinVal);
     282     3977190 :         tValueOut = static_cast<Tout>(
     283     3977160 :             GDALClampValue(fValueIn + 0.5f, fMaxVal, fMinVal));
     284             :     }
     285             : };
     286             : 
     287             : template <> struct sGDALCopyWord<float, short>
     288             : {
     289     2928910 :     static inline void f(const float fValueIn, short &nValueOut)
     290             :     {
     291     2928910 :         if (std::isnan(fValueIn))
     292             :         {
     293           0 :             nValueOut = 0;
     294           0 :             return;
     295             :         }
     296             :         float fMaxVal, fMinVal;
     297     2928910 :         GDALGetDataLimits<float, short>(fMaxVal, fMinVal);
     298     2928910 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     299     2928910 :         nValueOut =
     300     2928910 :             static_cast<short>(GDALClampValue(fValue, fMaxVal, fMinVal));
     301             :     }
     302             : };
     303             : 
     304             : template <> struct sGDALCopyWord<float, signed char>
     305             : {
     306         285 :     static inline void f(const float fValueIn, signed char &nValueOut)
     307             :     {
     308         285 :         if (std::isnan(fValueIn))
     309             :         {
     310           0 :             nValueOut = 0;
     311           0 :             return;
     312             :         }
     313             :         float fMaxVal, fMinVal;
     314         285 :         GDALGetDataLimits<float, signed char>(fMaxVal, fMinVal);
     315         285 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     316         285 :         nValueOut =
     317         285 :             static_cast<signed char>(GDALClampValue(fValue, fMaxVal, fMinVal));
     318             :     }
     319             : };
     320             : 
     321             : template <class Tout> struct sGDALCopyWord<double, Tout>
     322             : {
     323    79888908 :     static inline void f(const double dfValueIn, Tout &tValueOut)
     324             :     {
     325    79888908 :         if (std::isnan(dfValueIn))
     326             :         {
     327           0 :             tValueOut = 0;
     328           0 :             return;
     329             :         }
     330             :         double dfMaxVal, dfMinVal;
     331    80789308 :         GDALGetDataLimits<double, Tout>(dfMaxVal, dfMinVal);
     332    79257208 :         tValueOut = static_cast<Tout>(
     333    78209208 :             GDALClampValue(dfValueIn + 0.5, dfMaxVal, dfMinVal));
     334             :     }
     335             : };
     336             : 
     337             : template <> struct sGDALCopyWord<double, int>
     338             : {
     339    70358300 :     static inline void f(const double dfValueIn, int &nValueOut)
     340             :     {
     341    70358300 :         if (std::isnan(dfValueIn))
     342             :         {
     343           0 :             nValueOut = 0;
     344           0 :             return;
     345             :         }
     346             :         double dfMaxVal, dfMinVal;
     347    70358300 :         GDALGetDataLimits<double, int>(dfMaxVal, dfMinVal);
     348    70358300 :         double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     349    70358300 :         nValueOut =
     350    70358300 :             static_cast<int>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     351             :     }
     352             : };
     353             : 
     354             : template <> struct sGDALCopyWord<double, std::int64_t>
     355             : {
     356         676 :     static inline void f(const double dfValueIn, std::int64_t &nValueOut)
     357             :     {
     358         676 :         if (std::isnan(dfValueIn))
     359             :         {
     360           1 :             nValueOut = 0;
     361             :         }
     362         675 :         else if (dfValueIn >=
     363         675 :                  static_cast<double>(std::numeric_limits<std::int64_t>::max()))
     364             :         {
     365           6 :             nValueOut = std::numeric_limits<std::int64_t>::max();
     366             :         }
     367         669 :         else if (dfValueIn <=
     368         669 :                  static_cast<double>(std::numeric_limits<std::int64_t>::min()))
     369             :         {
     370           4 :             nValueOut = std::numeric_limits<std::int64_t>::min();
     371             :         }
     372             :         else
     373             :         {
     374        1330 :             nValueOut = static_cast<std::int64_t>(
     375         665 :                 dfValueIn > 0.0f ? dfValueIn + 0.5f : dfValueIn - 0.5f);
     376             :         }
     377         676 :     }
     378             : };
     379             : 
     380             : template <> struct sGDALCopyWord<double, std::uint64_t>
     381             : {
     382         592 :     static inline void f(const double dfValueIn, std::uint64_t &nValueOut)
     383             :     {
     384         592 :         if (!(dfValueIn > 0))
     385             :         {
     386         164 :             nValueOut = 0;
     387             :         }
     388         428 :         else if (dfValueIn >
     389         428 :                  static_cast<double>(std::numeric_limits<uint64_t>::max()))
     390             :         {
     391           4 :             nValueOut = std::numeric_limits<uint64_t>::max();
     392             :         }
     393             :         else
     394             :         {
     395         424 :             nValueOut = static_cast<std::uint64_t>(dfValueIn + 0.5);
     396             :         }
     397         592 :     }
     398             : };
     399             : 
     400             : template <> struct sGDALCopyWord<double, short>
     401             : {
     402     5101220 :     static inline void f(const double dfValueIn, short &nValueOut)
     403             :     {
     404     5101220 :         if (std::isnan(dfValueIn))
     405             :         {
     406           0 :             nValueOut = 0;
     407           0 :             return;
     408             :         }
     409             :         double dfMaxVal, dfMinVal;
     410     5101260 :         GDALGetDataLimits<double, short>(dfMaxVal, dfMinVal);
     411     5101190 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     412     5101220 :         nValueOut =
     413     5101190 :             static_cast<short>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     414             :     }
     415             : };
     416             : 
     417             : template <> struct sGDALCopyWord<double, signed char>
     418             : {
     419         451 :     static inline void f(const double dfValueIn, signed char &nValueOut)
     420             :     {
     421         451 :         if (std::isnan(dfValueIn))
     422             :         {
     423           0 :             nValueOut = 0;
     424           0 :             return;
     425             :         }
     426             :         double dfMaxVal, dfMinVal;
     427         451 :         GDALGetDataLimits<double, signed char>(dfMaxVal, dfMinVal);
     428         451 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     429         451 :         nValueOut = static_cast<signed char>(
     430         451 :             GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     431             :     }
     432             : };
     433             : 
     434             : // Roundoff occurs for Float32 -> int32 for max/min. Overload GDALCopyWord
     435             : // specifically for this case.
     436             : template <> struct sGDALCopyWord<float, int>
     437             : {
     438      515887 :     static inline void f(const float fValueIn, int &nValueOut)
     439             :     {
     440      515887 :         if (std::isnan(fValueIn))
     441             :         {
     442           0 :             nValueOut = 0;
     443             :         }
     444      515887 :         else if (fValueIn >=
     445      515887 :                  static_cast<float>(std::numeric_limits<int>::max()))
     446             :         {
     447         160 :             nValueOut = std::numeric_limits<int>::max();
     448             :         }
     449      515727 :         else if (fValueIn <=
     450      515727 :                  static_cast<float>(std::numeric_limits<int>::min()))
     451             :         {
     452          32 :             nValueOut = std::numeric_limits<int>::min();
     453             :         }
     454             :         else
     455             :         {
     456      636562 :             nValueOut = static_cast<int>(fValueIn > 0.0f ? fValueIn + 0.5f
     457      120867 :                                                          : fValueIn - 0.5f);
     458             :         }
     459      515887 :     }
     460             : };
     461             : 
     462             : // Roundoff occurs for Float32 -> uint32 for max. Overload GDALCopyWord
     463             : // specifically for this case.
     464             : template <> struct sGDALCopyWord<float, unsigned int>
     465             : {
     466         191 :     static inline void f(const float fValueIn, unsigned int &nValueOut)
     467             :     {
     468         191 :         if (!(fValueIn > 0))
     469             :         {
     470          20 :             nValueOut = 0;
     471             :         }
     472         171 :         else if (fValueIn >=
     473         171 :                  static_cast<float>(std::numeric_limits<unsigned int>::max()))
     474             :         {
     475          20 :             nValueOut = std::numeric_limits<unsigned int>::max();
     476             :         }
     477             :         else
     478             :         {
     479         151 :             nValueOut = static_cast<unsigned int>(fValueIn + 0.5f);
     480             :         }
     481         191 :     }
     482             : };
     483             : 
     484             : // Roundoff occurs for Float32 -> std::int64_t for max/min. Overload
     485             : // GDALCopyWord specifically for this case.
     486             : template <> struct sGDALCopyWord<float, std::int64_t>
     487             : {
     488         226 :     static inline void f(const float fValueIn, std::int64_t &nValueOut)
     489             :     {
     490         226 :         if (std::isnan(fValueIn))
     491             :         {
     492           1 :             nValueOut = 0;
     493             :         }
     494         225 :         else if (fValueIn >=
     495         225 :                  static_cast<float>(std::numeric_limits<std::int64_t>::max()))
     496             :         {
     497           2 :             nValueOut = std::numeric_limits<std::int64_t>::max();
     498             :         }
     499         223 :         else if (fValueIn <=
     500         223 :                  static_cast<float>(std::numeric_limits<std::int64_t>::min()))
     501             :         {
     502           2 :             nValueOut = std::numeric_limits<std::int64_t>::min();
     503             :         }
     504             :         else
     505             :         {
     506         442 :             nValueOut = static_cast<std::int64_t>(
     507         221 :                 fValueIn > 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f);
     508             :         }
     509         226 :     }
     510             : };
     511             : 
     512             : // Roundoff occurs for Float32 -> std::uint64_t for max. Overload GDALCopyWord
     513             : // specifically for this case.
     514             : template <> struct sGDALCopyWord<float, std::uint64_t>
     515             : {
     516         156 :     static inline void f(const float fValueIn, std::uint64_t &nValueOut)
     517             :     {
     518         156 :         if (!(fValueIn > 0))
     519             :         {
     520           3 :             nValueOut = 0;
     521             :         }
     522         153 :         else if (fValueIn >=
     523         153 :                  static_cast<float>(std::numeric_limits<std::uint64_t>::max()))
     524             :         {
     525           2 :             nValueOut = std::numeric_limits<std::uint64_t>::max();
     526             :         }
     527             :         else
     528             :         {
     529         151 :             nValueOut = static_cast<std::uint64_t>(fValueIn + 0.5f);
     530             :         }
     531         156 :     }
     532             : };
     533             : 
     534             : /**
     535             :  * Copy a single word, optionally rounding if appropriate (i.e. going
     536             :  * from the float to the integer case). Note that this is the function
     537             :  * you should specialize if you're adding a new data type.
     538             :  *
     539             :  * @param tValueIn value of type Tin; the input value to be converted
     540             :  * @param tValueOut value of type Tout; the output value
     541             :  */
     542             : 
     543             : template <class Tin, class Tout>
     544   533426614 : inline void GDALCopyWord(const Tin tValueIn, Tout &tValueOut)
     545             : {
     546   533426614 :     sGDALCopyWord<Tin, Tout>::f(tValueIn, tValueOut);
     547   532983464 : }
     548             : 
     549             : /************************************************************************/
     550             : /*                         GDALCopy4Words()                             */
     551             : /************************************************************************/
     552             : /**
     553             :  * Copy 4 packed words to 4 packed words, optionally rounding if appropriate
     554             :  * (i.e. going from the float to the integer case).
     555             :  *
     556             :  * @param pValueIn pointer to 4 input values of type Tin.
     557             :  * @param pValueOut pointer to 4 output values of type Tout.
     558             :  */
     559             : 
     560             : template <class Tin, class Tout>
     561          16 : inline void GDALCopy4Words(const Tin *pValueIn, Tout *const pValueOut)
     562             : {
     563          16 :     GDALCopyWord(pValueIn[0], pValueOut[0]);
     564          16 :     GDALCopyWord(pValueIn[1], pValueOut[1]);
     565          16 :     GDALCopyWord(pValueIn[2], pValueOut[2]);
     566          16 :     GDALCopyWord(pValueIn[3], pValueOut[3]);
     567          16 : }
     568             : 
     569             : /************************************************************************/
     570             : /*                         GDALCopy8Words()                             */
     571             : /************************************************************************/
     572             : /**
     573             :  * Copy 8 packed words to 8 packed words, optionally rounding if appropriate
     574             :  * (i.e. going from the float to the integer case).
     575             :  *
     576             :  * @param pValueIn pointer to 8 input values of type Tin.
     577             :  * @param pValueOut pointer to 8 output values of type Tout.
     578             :  */
     579             : 
     580             : template <class Tin, class Tout>
     581    14784879 : inline void GDALCopy8Words(const Tin *pValueIn, Tout *const pValueOut)
     582             : {
     583    14784879 :     GDALCopy4Words(pValueIn, pValueOut);
     584    14784479 :     GDALCopy4Words(pValueIn + 4, pValueOut + 4);
     585    14784579 : }
     586             : 
     587             : // Needs SSE2
     588             : #if defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2) ||               \
     589             :     defined(USE_NEON_OPTIMIZATIONS)
     590             : 
     591             : #ifdef USE_NEON_OPTIMIZATIONS
     592             : #include "include_sse2neon.h"
     593             : #else
     594             : #include <emmintrin.h>
     595             : #endif
     596             : 
     597    32512315 : static inline void GDALCopyXMMToInt32(const __m128i xmm, void *pDest)
     598             : {
     599    32512315 :     int n32 = _mm_cvtsi128_si32(xmm);  // Extract lower 32 bit word
     600    32512315 :     memcpy(pDest, &n32, sizeof(n32));
     601    32512315 : }
     602             : 
     603    76979773 : static inline void GDALCopyXMMToInt64(const __m128i xmm, void *pDest)
     604             : {
     605             :     _mm_storel_epi64(reinterpret_cast<__m128i *>(pDest), xmm);
     606    76979773 : }
     607             : 
     608             : #if __SSSE3__
     609             : #include <tmmintrin.h>
     610             : #endif
     611             : 
     612             : #if __SSE4_1__
     613             : #include <smmintrin.h>
     614             : #endif
     615             : 
     616             : template <>
     617    26206902 : inline void GDALCopy4Words(const float *pValueIn, GByte *const pValueOut)
     618             : {
     619    26206902 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     620             : 
     621             :     // The following clamping would be useless due to the final saturating
     622             :     // packing if we could guarantee the input range in [INT_MIN,INT_MAX]
     623    26206902 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     624    26206902 :     const __m128 xmm_max = _mm_set1_ps(255);
     625    26206902 :     xmm = _mm_add_ps(xmm, p0d5);
     626    52396704 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     627             : 
     628    26208802 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     629             : 
     630             : #if __SSSE3__
     631             :     xmm_i = _mm_shuffle_epi8(
     632             :         xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) | (12 << 24)));
     633             : #else
     634    26206302 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);   // Pack int32 to int16
     635    26209202 :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);  // Pack int16 to uint8
     636             : #endif
     637    26209202 :     GDALCopyXMMToInt32(xmm_i, pValueOut);
     638    26199402 : }
     639             : 
     640             : template <>
     641     3355730 : inline void GDALCopy4Words(const float *pValueIn, GInt16 *const pValueOut)
     642             : {
     643     3355730 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     644             : 
     645     3355730 :     const __m128 xmm_min = _mm_set1_ps(-32768);
     646     3355730 :     const __m128 xmm_max = _mm_set1_ps(32767);
     647     6711460 :     xmm = _mm_min_ps(_mm_max_ps(xmm, xmm_min), xmm_max);
     648             : 
     649     3355730 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     650     3355730 :     const __m128 m0d5 = _mm_set1_ps(-0.5f);
     651     3355730 :     const __m128 mask = _mm_cmpge_ps(xmm, p0d5);
     652             :     // f >= 0.5f ? f + 0.5f : f - 0.5f
     653    13422900 :     xmm = _mm_add_ps(
     654             :         xmm, _mm_or_ps(_mm_and_ps(mask, p0d5), _mm_andnot_ps(mask, m0d5)));
     655             : 
     656     3355730 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     657             : 
     658     3355730 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     659     3355730 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     660     3355730 : }
     661             : 
     662             : template <>
     663           1 : inline void GDALCopy4Words(const float *pValueIn, GUInt16 *const pValueOut)
     664             : {
     665           1 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     666             : 
     667           1 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     668           1 :     const __m128 xmm_max = _mm_set1_ps(65535);
     669           1 :     xmm = _mm_add_ps(xmm, p0d5);
     670           2 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     671             : 
     672           1 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     673             : 
     674             : #if __SSE4_1__
     675             :     xmm_i = _mm_packus_epi32(xmm_i, xmm_i);  // Pack int32 to uint16
     676             : #else
     677             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
     678           2 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
     679           1 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     680             :     // Translate back to uint16 range (actually -32768==32768 in int16)
     681           1 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
     682             : #endif
     683           1 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     684           1 : }
     685             : 
     686             : #ifdef __AVX2__
     687             : 
     688             : #include <immintrin.h>
     689             : 
     690             : template <>
     691             : inline void GDALCopy8Words(const float *pValueIn, GByte *const pValueOut)
     692             : {
     693             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     694             : 
     695             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     696             :     const __m256 ymm_max = _mm256_set1_ps(255);
     697             :     ymm = _mm256_add_ps(ymm, p0d5);
     698             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     699             : 
     700             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
     701             : 
     702             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
     703             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
     704             : 
     705             :     __m128i xmm_i = _mm256_castsi256_si128(ymm_i);
     706             :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);
     707             :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     708             : }
     709             : 
     710             : template <>
     711             : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
     712             : {
     713             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     714             : 
     715             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     716             :     const __m256 ymm_max = _mm256_set1_ps(65535);
     717             :     ymm = _mm256_add_ps(ymm, p0d5);
     718             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     719             : 
     720             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
     721             : 
     722             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
     723             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
     724             : 
     725             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut),
     726             :                      _mm256_castsi256_si128(ymm_i));
     727             : }
     728             : #else
     729             : template <>
     730     7756701 : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
     731             : {
     732     7756701 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     733    15513402 :     __m128 xmm1 = _mm_loadu_ps(pValueIn + 4);
     734             : 
     735     7756701 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     736     7756701 :     const __m128 xmm_max = _mm_set1_ps(65535);
     737     7756701 :     xmm = _mm_add_ps(xmm, p0d5);
     738     7756701 :     xmm1 = _mm_add_ps(xmm1, p0d5);
     739    15504002 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     740    15512102 :     xmm1 = _mm_min_ps(_mm_max_ps(xmm1, p0d5), xmm_max);
     741             : 
     742     7748721 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     743     7752981 :     __m128i xmm1_i = _mm_cvttps_epi32(xmm1);
     744             : 
     745             : #if __SSE4_1__
     746             :     xmm_i = _mm_packus_epi32(xmm_i, xmm1_i);  // Pack int32 to uint16
     747             : #else
     748             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
     749    15506002 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
     750    15506002 :     xmm1_i = _mm_add_epi32(xmm1_i, _mm_set1_epi32(-32768));
     751     7763531 :     xmm_i = _mm_packs_epi32(xmm_i, xmm1_i);  // Pack int32 to int16
     752             :     // Translate back to uint16 range (actually -32768==32768 in int16)
     753    15527102 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
     754             : #endif
     755             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut), xmm_i);
     756     7763531 : }
     757             : #endif
     758             : 
     759             : #ifdef notdef_because_slightly_slower_than_default_implementation
     760             : template <>
     761             : inline void GDALCopy4Words(const double *pValueIn, float *const pValueOut)
     762             : {
     763             :     __m128d float_posmax = _mm_set1_pd(std::numeric_limits<float>::max());
     764             :     __m128d float_negmax = _mm_set1_pd(-std::numeric_limits<float>::max());
     765             :     __m128d float_posinf = _mm_set1_pd(std::numeric_limits<float>::infinity());
     766             :     __m128d float_neginf = _mm_set1_pd(-std::numeric_limits<float>::infinity());
     767             :     __m128d val01 = _mm_loadu_pd(pValueIn);
     768             :     __m128d val23 = _mm_loadu_pd(pValueIn + 2);
     769             :     __m128d mask_max = _mm_cmpge_pd(val01, float_posmax);
     770             :     __m128d mask_max23 = _mm_cmpge_pd(val23, float_posmax);
     771             :     val01 = _mm_or_pd(_mm_and_pd(mask_max, float_posinf),
     772             :                       _mm_andnot_pd(mask_max, val01));
     773             :     val23 = _mm_or_pd(_mm_and_pd(mask_max23, float_posinf),
     774             :                       _mm_andnot_pd(mask_max23, val23));
     775             :     __m128d mask_min = _mm_cmple_pd(val01, float_negmax);
     776             :     __m128d mask_min23 = _mm_cmple_pd(val23, float_negmax);
     777             :     val01 = _mm_or_pd(_mm_and_pd(mask_min, float_neginf),
     778             :                       _mm_andnot_pd(mask_min, val01));
     779             :     val23 = _mm_or_pd(_mm_and_pd(mask_min23, float_neginf),
     780             :                       _mm_andnot_pd(mask_min23, val23));
     781             :     __m128 val01_s = _mm_cvtpd_ps(val01);
     782             :     __m128 val23_s = _mm_cvtpd_ps(val23);
     783             :     __m128i val01_i = _mm_castps_si128(val01_s);
     784             :     __m128i val23_i = _mm_castps_si128(val23_s);
     785             :     GDALCopyXMMToInt64(val01_i, pValueOut);
     786             :     GDALCopyXMMToInt64(val23_i, pValueOut + 2);
     787             : }
     788             : #endif
     789             : 
     790             : #endif  //  defined(__x86_64) || defined(_M_X64)
     791             : 
     792             : #endif  // GDAL_PRIV_TEMPLATES_HPP_INCLUDED

Generated by: LCOV version 1.14