LCOV - code coverage report
Current view: top level - gcore - gdal_priv_templates.hpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 203 224 90.6 %
Date: 2024-05-04 12:52:34 Functions: 307 316 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #ifndef GDAL_PRIV_TEMPLATES_HPP_INCLUDED
      31             : #define GDAL_PRIV_TEMPLATES_HPP_INCLUDED
      32             : 
      33             : #include "cpl_port.h"
      34             : 
      35             : #include <cstdint>
      36             : #include <limits>
      37             : 
      38             : /************************************************************************/
      39             : /*                        GDALGetDataLimits()                           */
      40             : /************************************************************************/
      41             : /**
      42             :  * Compute the limits of values that can be placed in Tout in terms of
      43             :  * Tin. Usually used for output clamping, when the output data type's
      44             :  * limits are stable relative to the input type (i.e. no roundoff error).
      45             :  *
      46             :  * @param tMaxValue the returned maximum value
      47             :  * @param tMinValue the returned minimum value
      48             :  */
      49             : 
      50             : template <class Tin, class Tout>
      51   270247668 : inline void GDALGetDataLimits(Tin &tMaxValue, Tin &tMinValue)
      52             : {
      53   270247668 :     tMaxValue = std::numeric_limits<Tin>::max();
      54   269676138 :     tMinValue = std::numeric_limits<Tin>::min();
      55             : 
      56             :     // Compute the actual minimum value of Tout in terms of Tin.
      57             :     if constexpr (std::numeric_limits<Tout>::is_signed &&
      58             :                   std::numeric_limits<Tout>::is_integer)
      59             :     {
      60             :         // the minimum value is less than zero
      61             :         if constexpr (std::numeric_limits<Tout>::digits <
      62             :                           std::numeric_limits<Tin>::digits ||
      63             :                       !std::numeric_limits<Tin>::is_integer)
      64             :         {
      65             :             // Tout is smaller than Tin, so we need to clamp values in input
      66             :             // to the range of Tout's min/max values
      67             :             if (std::numeric_limits<Tin>::is_signed)
      68             :             {
      69    78394145 :                 tMinValue = static_cast<Tin>(std::numeric_limits<Tout>::min());
      70             :             }
      71    78750534 :             tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
      72             :         }
      73             :     }
      74             :     else if constexpr (std::numeric_limits<Tout>::is_integer)
      75             :     {
      76             :         // the output is unsigned, so we just need to determine the max
      77             :         /* coverity[same_on_both_sides] */
      78             :         if constexpr (std::numeric_limits<Tout>::digits <=
      79             :                       std::numeric_limits<Tin>::digits)
      80             :         {
      81             :             // Tout is smaller than Tin, so we need to clamp the input values
      82             :             // to the range of Tout's max
      83   129332308 :             tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
      84             :         }
      85   130854203 :         tMinValue = 0;
      86             :     }
      87   268649068 : }
      88             : 
      89             : /************************************************************************/
      90             : /*                          GDALClampValue()                            */
      91             : /************************************************************************/
      92             : /**
      93             :  * Clamp values of type T to a specified range
      94             :  *
      95             :  * @param tValue the value
      96             :  * @param tMax the max value
      97             :  * @param tMin the min value
      98             :  */
      99             : template <class T>
     100   268743921 : inline T GDALClampValue(const T tValue, const T tMax, const T tMin)
     101             : {
     102   268743921 :     return tValue > tMax ? tMax : tValue < tMin ? tMin : tValue;
     103             : }
     104             : 
     105             : /************************************************************************/
     106             : /*                          GDALClampDoubleValue()                            */
     107             : /************************************************************************/
     108             : /**
     109             :  * Clamp double values to a specified range, this uses the same
     110             :  * argument ordering as std::clamp, returns TRUE if the value was clamped.
     111             :  *
     112             :  * @param tValue the value
     113             :  * @param tMin the min value
     114             :  * @param tMax the max value
     115             :  *
     116             :  */
     117             : template <class T2, class T3>
     118         155 : inline bool GDALClampDoubleValue(double &tValue, const T2 tMin, const T3 tMax)
     119             : {
     120         155 :     const double tMin2{static_cast<double>(tMin)};
     121         155 :     const double tMax2{static_cast<double>(tMax)};
     122         155 :     if (tValue > tMax2 || tValue < tMin2)
     123             :     {
     124          22 :         tValue = tValue > tMax2 ? tMax2 : tValue < tMin2 ? tMin2 : tValue;
     125          22 :         return true;
     126             :     }
     127             :     else
     128             :     {
     129         133 :         return false;
     130             :     }
     131             : }
     132             : 
     133             : /************************************************************************/
     134             : /*                         GDALIsValueInRange()                         */
     135             : /************************************************************************/
     136             : /**
     137             :  * Returns whether a value is in the type range.
     138             :  * NaN is considered not to be in type range.
     139             :  *
     140             :  * @param dfValue the value
     141             :  * @return whether the value is in the type range.
     142             :  */
     143      105225 : template <class T> inline bool GDALIsValueInRange(double dfValue)
     144             : {
     145      210426 :     return dfValue >= static_cast<double>(std::numeric_limits<T>::lowest()) &&
     146      210426 :            dfValue <= static_cast<double>(std::numeric_limits<T>::max());
     147             : }
     148             : 
     149           3 : template <> inline bool GDALIsValueInRange<double>(double dfValue)
     150             : {
     151           3 :     return !CPLIsNan(dfValue);
     152             : }
     153             : 
     154       41595 : template <> inline bool GDALIsValueInRange<float>(double dfValue)
     155             : {
     156       41185 :     return CPLIsInf(dfValue) ||
     157       41266 :            (dfValue >= -std::numeric_limits<float>::max() &&
     158      124522 :             dfValue <= std::numeric_limits<float>::max());
     159             : }
     160             : 
     161             : /************************************************************************/
     162             : /*                          GDALCopyWord()                              */
     163             : /************************************************************************/
     164             : 
     165             : template <class Tin, class Tout> struct sGDALCopyWord
     166             : {
     167   117440814 :     static inline void f(const Tin tValueIn, Tout &tValueOut)
     168             :     {
     169             :         Tin tMaxVal, tMinVal;
     170   117440814 :         GDALGetDataLimits<Tin, Tout>(tMaxVal, tMinVal);
     171   117440714 :         tValueOut =
     172   117423914 :             static_cast<Tout>(GDALClampValue(tValueIn, tMaxVal, tMinVal));
     173   117440714 :     }
     174             : };
     175             : 
     176             : template <class Tin> struct sGDALCopyWord<Tin, float>
     177             : {
     178    12302717 :     static inline void f(const Tin tValueIn, float &fValueOut)
     179             :     {
     180    12302717 :         fValueOut = static_cast<float>(tValueIn);
     181    12302717 :     }
     182             : };
     183             : 
     184             : template <class Tin> struct sGDALCopyWord<Tin, double>
     185             : {
     186    62778742 :     static inline void f(const Tin tValueIn, double &dfValueOut)
     187             :     {
     188    62778742 :         dfValueOut = static_cast<double>(tValueIn);
     189    62778742 :     }
     190             : };
     191             : 
     192             : template <> struct sGDALCopyWord<double, double>
     193             : {
     194     6753460 :     static inline void f(const double dfValueIn, double &dfValueOut)
     195             :     {
     196     6753460 :         dfValueOut = dfValueIn;
     197     6753460 :     }
     198             : };
     199             : 
     200             : template <> struct sGDALCopyWord<float, float>
     201             : {
     202     7838140 :     static inline void f(const float fValueIn, float &fValueOut)
     203             :     {
     204     7838140 :         fValueOut = fValueIn;
     205     7838140 :     }
     206             : };
     207             : 
     208             : template <> struct sGDALCopyWord<float, double>
     209             : {
     210    46436300 :     static inline void f(const float fValueIn, double &dfValueOut)
     211             :     {
     212    46436300 :         dfValueOut = fValueIn;
     213    46436300 :     }
     214             : };
     215             : 
     216             : template <> struct sGDALCopyWord<double, float>
     217             : {
     218     2305620 :     static inline void f(const double dfValueIn, float &fValueOut)
     219             :     {
     220     2305620 :         if (dfValueIn > std::numeric_limits<float>::max())
     221             :         {
     222          44 :             fValueOut = std::numeric_limits<float>::infinity();
     223          44 :             return;
     224             :         }
     225     2305580 :         if (dfValueIn < -std::numeric_limits<float>::max())
     226             :         {
     227          46 :             fValueOut = -std::numeric_limits<float>::infinity();
     228          46 :             return;
     229             :         }
     230             : 
     231     2305530 :         fValueOut = static_cast<float>(dfValueIn);
     232             :     }
     233             : };
     234             : 
     235             : template <class Tout> struct sGDALCopyWord<float, Tout>
     236             : {
     237     3745760 :     static inline void f(const float fValueIn, Tout &tValueOut)
     238             :     {
     239     3745760 :         if (CPLIsNan(fValueIn))
     240             :         {
     241           0 :             tValueOut = 0;
     242           0 :             return;
     243             :         }
     244             :         float fMaxVal, fMinVal;
     245     3745760 :         GDALGetDataLimits<float, Tout>(fMaxVal, fMinVal);
     246     3745690 :         tValueOut = static_cast<Tout>(
     247     3745670 :             GDALClampValue(fValueIn + 0.5f, fMaxVal, fMinVal));
     248             :     }
     249             : };
     250             : 
     251             : template <> struct sGDALCopyWord<float, short>
     252             : {
     253     2928220 :     static inline void f(const float fValueIn, short &nValueOut)
     254             :     {
     255     2928220 :         if (CPLIsNan(fValueIn))
     256             :         {
     257           0 :             nValueOut = 0;
     258           0 :             return;
     259             :         }
     260             :         float fMaxVal, fMinVal;
     261     2928220 :         GDALGetDataLimits<float, short>(fMaxVal, fMinVal);
     262     2928220 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     263     2928220 :         nValueOut =
     264     2928220 :             static_cast<short>(GDALClampValue(fValue, fMaxVal, fMinVal));
     265             :     }
     266             : };
     267             : 
     268             : template <> struct sGDALCopyWord<float, signed char>
     269             : {
     270         221 :     static inline void f(const float fValueIn, signed char &nValueOut)
     271             :     {
     272         221 :         if (CPLIsNan(fValueIn))
     273             :         {
     274           0 :             nValueOut = 0;
     275           0 :             return;
     276             :         }
     277             :         float fMaxVal, fMinVal;
     278         221 :         GDALGetDataLimits<float, signed char>(fMaxVal, fMinVal);
     279         221 :         float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
     280         221 :         nValueOut =
     281         221 :             static_cast<signed char>(GDALClampValue(fValue, fMaxVal, fMinVal));
     282             :     }
     283             : };
     284             : 
     285             : template <class Tout> struct sGDALCopyWord<double, Tout>
     286             : {
     287    70332083 :     static inline void f(const double dfValueIn, Tout &tValueOut)
     288             :     {
     289    70332083 :         if (CPLIsNan(dfValueIn))
     290             :         {
     291           0 :             tValueOut = 0;
     292           0 :             return;
     293             :         }
     294             :         double dfMaxVal, dfMinVal;
     295    70332083 :         GDALGetDataLimits<double, Tout>(dfMaxVal, dfMinVal);
     296    69492983 :         tValueOut = static_cast<Tout>(
     297    68809783 :             GDALClampValue(dfValueIn + 0.5, dfMaxVal, dfMinVal));
     298             :     }
     299             : };
     300             : 
     301             : template <> struct sGDALCopyWord<double, int>
     302             : {
     303    70358200 :     static inline void f(const double dfValueIn, int &nValueOut)
     304             :     {
     305    70358200 :         if (CPLIsNan(dfValueIn))
     306             :         {
     307           0 :             nValueOut = 0;
     308           0 :             return;
     309             :         }
     310             :         double dfMaxVal, dfMinVal;
     311    70358200 :         GDALGetDataLimits<double, int>(dfMaxVal, dfMinVal);
     312    70358200 :         double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     313    70358200 :         nValueOut =
     314    70358200 :             static_cast<int>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     315             :     }
     316             : };
     317             : 
     318             : template <> struct sGDALCopyWord<double, std::int64_t>
     319             : {
     320         589 :     static inline void f(const double dfValueIn, std::int64_t &nValueOut)
     321             :     {
     322         589 :         if (CPLIsNan(dfValueIn))
     323             :         {
     324           0 :             nValueOut = 0;
     325           0 :             return;
     326             :         }
     327             :         double dfMaxVal, dfMinVal;
     328         589 :         GDALGetDataLimits<double, std::int64_t>(dfMaxVal, dfMinVal);
     329         589 :         double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     330         589 :         nValueOut = static_cast<std::int64_t>(
     331         589 :             GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     332             :     }
     333             : };
     334             : 
     335             : template <> struct sGDALCopyWord<double, short>
     336             : {
     337     5102140 :     static inline void f(const double dfValueIn, short &nValueOut)
     338             :     {
     339     5102140 :         if (CPLIsNan(dfValueIn))
     340             :         {
     341           0 :             nValueOut = 0;
     342           0 :             return;
     343             :         }
     344             :         double dfMaxVal, dfMinVal;
     345     5102140 :         GDALGetDataLimits<double, short>(dfMaxVal, dfMinVal);
     346     5102140 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     347     5102140 :         nValueOut =
     348     5102140 :             static_cast<short>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     349             :     }
     350             : };
     351             : 
     352             : template <> struct sGDALCopyWord<double, signed char>
     353             : {
     354         441 :     static inline void f(const double dfValueIn, signed char &nValueOut)
     355             :     {
     356         441 :         if (CPLIsNan(dfValueIn))
     357             :         {
     358           0 :             nValueOut = 0;
     359           0 :             return;
     360             :         }
     361             :         double dfMaxVal, dfMinVal;
     362         441 :         GDALGetDataLimits<double, signed char>(dfMaxVal, dfMinVal);
     363         441 :         double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
     364         441 :         nValueOut = static_cast<signed char>(
     365         441 :             GDALClampValue(dfValue, dfMaxVal, dfMinVal));
     366             :     }
     367             : };
     368             : 
     369             : // Roundoff occurs for Float32 -> int32 for max/min. Overload GDALCopyWord
     370             : // specifically for this case.
     371             : template <> struct sGDALCopyWord<float, int>
     372             : {
     373   134016000 :     static inline void f(const float fValueIn, int &nValueOut)
     374             :     {
     375   134016000 :         if (fValueIn >= static_cast<float>(std::numeric_limits<int>::max()))
     376             :         {
     377          32 :             nValueOut = std::numeric_limits<int>::max();
     378             :         }
     379   132209000 :         else if (fValueIn <=
     380   135685000 :                  static_cast<float>(std::numeric_limits<int>::min()))
     381             :         {
     382           0 :             nValueOut = std::numeric_limits<int>::min();
     383             :         }
     384             :         else
     385             :         {
     386   134993000 :             nValueOut = static_cast<int>(fValueIn > 0.0f ? fValueIn + 0.5f
     387      121179 :                                                          : fValueIn - 0.5f);
     388             :         }
     389   134872000 :     }
     390             : };
     391             : 
     392             : // Roundoff occurs for Float32 -> uint32 for max. Overload GDALCopyWord
     393             : // specifically for this case.
     394             : template <> struct sGDALCopyWord<float, unsigned int>
     395             : {
     396         540 :     static inline void f(const float fValueIn, unsigned int &nValueOut)
     397             :     {
     398         540 :         if (fValueIn >=
     399         540 :             static_cast<float>(std::numeric_limits<unsigned int>::max()))
     400             :         {
     401          20 :             nValueOut = std::numeric_limits<unsigned int>::max();
     402             :         }
     403         520 :         else if (fValueIn <=
     404         520 :                  static_cast<float>(std::numeric_limits<unsigned int>::min()))
     405             :         {
     406          42 :             nValueOut = std::numeric_limits<unsigned int>::min();
     407             :         }
     408             :         else
     409             :         {
     410         478 :             nValueOut = static_cast<unsigned int>(fValueIn + 0.5f);
     411             :         }
     412         540 :     }
     413             : };
     414             : 
     415             : // Roundoff occurs for Float32 -> std::int64_t for max/min. Overload
     416             : // GDALCopyWord specifically for this case.
     417             : template <> struct sGDALCopyWord<float, std::int64_t>
     418             : {
     419         222 :     static inline void f(const float fValueIn, std::int64_t &nValueOut)
     420             :     {
     421         222 :         if (fValueIn >=
     422         222 :             static_cast<float>(std::numeric_limits<std::int64_t>::max()))
     423             :         {
     424           0 :             nValueOut = std::numeric_limits<std::int64_t>::max();
     425             :         }
     426         222 :         else if (fValueIn <=
     427         222 :                  static_cast<float>(std::numeric_limits<std::int64_t>::min()))
     428             :         {
     429           0 :             nValueOut = std::numeric_limits<std::int64_t>::min();
     430             :         }
     431             :         else
     432             :         {
     433         444 :             nValueOut = static_cast<std::int64_t>(
     434         222 :                 fValueIn > 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f);
     435             :         }
     436         222 :     }
     437             : };
     438             : 
     439             : // Roundoff occurs for Float32 -> std::uint64_t for max. Overload GDALCopyWord
     440             : // specifically for this case.
     441             : template <> struct sGDALCopyWord<float, std::uint64_t>
     442             : {
     443         152 :     static inline void f(const float fValueIn, std::uint64_t &nValueOut)
     444             :     {
     445         152 :         if (fValueIn >=
     446         152 :             static_cast<float>(std::numeric_limits<std::uint64_t>::max()))
     447             :         {
     448           0 :             nValueOut = std::numeric_limits<std::uint64_t>::max();
     449             :         }
     450         152 :         else if (fValueIn <=
     451         152 :                  static_cast<float>(std::numeric_limits<std::uint64_t>::min()))
     452             :         {
     453           0 :             nValueOut = std::numeric_limits<std::uint64_t>::min();
     454             :         }
     455             :         else
     456             :         {
     457         152 :             nValueOut = static_cast<std::uint64_t>(fValueIn + 0.5f);
     458             :         }
     459         152 :     }
     460             : };
     461             : 
     462             : /**
     463             :  * Copy a single word, optionally rounding if appropriate (i.e. going
     464             :  * from the float to the integer case). Note that this is the function
     465             :  * you should specialize if you're adding a new data type.
     466             :  *
     467             :  * @param tValueIn value of type Tin; the input value to be converted
     468             :  * @param tValueOut value of type Tout; the output value
     469             :  */
     470             : 
     471             : template <class Tin, class Tout>
     472   541449181 : inline void GDALCopyWord(const Tin tValueIn, Tout &tValueOut)
     473             : {
     474   541449181 :     sGDALCopyWord<Tin, Tout>::f(tValueIn, tValueOut);
     475   541186701 : }
     476             : 
     477             : /************************************************************************/
     478             : /*                         GDALCopy4Words()                             */
     479             : /************************************************************************/
     480             : /**
     481             :  * Copy 4 packed words to 4 packed words, optionally rounding if appropriate
     482             :  * (i.e. going from the float to the integer case).
     483             :  *
     484             :  * @param pValueIn pointer to 4 input values of type Tin.
     485             :  * @param pValueOut pointer to 4 output values of type Tout.
     486             :  */
     487             : 
     488             : template <class Tin, class Tout>
     489          16 : inline void GDALCopy4Words(const Tin *pValueIn, Tout *const pValueOut)
     490             : {
     491          16 :     GDALCopyWord(pValueIn[0], pValueOut[0]);
     492          16 :     GDALCopyWord(pValueIn[1], pValueOut[1]);
     493          16 :     GDALCopyWord(pValueIn[2], pValueOut[2]);
     494          16 :     GDALCopyWord(pValueIn[3], pValueOut[3]);
     495          16 : }
     496             : 
     497             : /************************************************************************/
     498             : /*                         GDALCopy8Words()                             */
     499             : /************************************************************************/
     500             : /**
     501             :  * Copy 8 packed words to 8 packed words, optionally rounding if appropriate
     502             :  * (i.e. going from the float to the integer case).
     503             :  *
     504             :  * @param pValueIn pointer to 8 input values of type Tin.
     505             :  * @param pValueOut pointer to 8 output values of type Tout.
     506             :  */
     507             : 
     508             : template <class Tin, class Tout>
     509    13031190 : inline void GDALCopy8Words(const Tin *pValueIn, Tout *const pValueOut)
     510             : {
     511    13031190 :     GDALCopy4Words(pValueIn, pValueOut);
     512    13031690 :     GDALCopy4Words(pValueIn + 4, pValueOut + 4);
     513    13031390 : }
     514             : 
     515             : // Needs SSE2
     516             : #if defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2)
     517             : 
     518             : #include <emmintrin.h>
     519             : 
     520    31996105 : static inline void GDALCopyXMMToInt32(const __m128i xmm, void *pDest)
     521             : {
     522    31996105 :     int n32 = _mm_cvtsi128_si32(xmm);  // Extract lower 32 bit word
     523    31996105 :     memcpy(pDest, &n32, sizeof(n32));
     524    31996105 : }
     525             : 
     526    73833095 : static inline void GDALCopyXMMToInt64(const __m128i xmm, void *pDest)
     527             : {
     528             :     _mm_storel_epi64(reinterpret_cast<__m128i *>(pDest), xmm);
     529    73833095 : }
     530             : 
     531             : #if __SSSE3__
     532             : #include <tmmintrin.h>
     533             : #endif
     534             : 
     535             : #if __SSE4_1__
     536             : #include <smmintrin.h>
     537             : #endif
     538             : 
     539             : template <>
     540    25851302 : inline void GDALCopy4Words(const float *pValueIn, GByte *const pValueOut)
     541             : {
     542    25851302 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     543             : 
     544             :     // The following clamping would be useless due to the final saturating
     545             :     // packing if we could guarantee the input range in [INT_MIN,INT_MAX]
     546    25851302 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     547    25851302 :     const __m128 xmm_max = _mm_set1_ps(255);
     548    25851302 :     xmm = _mm_add_ps(xmm, p0d5);
     549    51703404 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     550             : 
     551    25854002 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     552             : 
     553             : #if __SSSE3__
     554             :     xmm_i = _mm_shuffle_epi8(
     555             :         xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) | (12 << 24)));
     556             : #else
     557    25849902 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);   // Pack int32 to int16
     558    25853102 :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);  // Pack int16 to uint8
     559             : #endif
     560    25853102 :     GDALCopyXMMToInt32(xmm_i, pValueOut);
     561    25854302 : }
     562             : 
     563             : template <>
     564      202562 : inline void GDALCopy4Words(const float *pValueIn, GInt16 *const pValueOut)
     565             : {
     566      202562 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     567             : 
     568      202562 :     const __m128 xmm_min = _mm_set1_ps(-32768);
     569      202562 :     const __m128 xmm_max = _mm_set1_ps(32767);
     570      405124 :     xmm = _mm_min_ps(_mm_max_ps(xmm, xmm_min), xmm_max);
     571             : 
     572      202562 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     573      202562 :     const __m128 m0d5 = _mm_set1_ps(-0.5f);
     574      202562 :     const __m128 mask = _mm_cmpge_ps(xmm, p0d5);
     575             :     // f >= 0.5f ? f + 0.5f : f - 0.5f
     576      810248 :     xmm = _mm_add_ps(
     577             :         xmm, _mm_or_ps(_mm_and_ps(mask, p0d5), _mm_andnot_ps(mask, m0d5)));
     578             : 
     579      202562 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     580             : 
     581      202562 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     582      202562 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     583      202562 : }
     584             : 
     585             : template <>
     586           1 : inline void GDALCopy4Words(const float *pValueIn, GUInt16 *const pValueOut)
     587             : {
     588           1 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     589             : 
     590           1 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     591           1 :     const __m128 xmm_max = _mm_set1_ps(65535);
     592           1 :     xmm = _mm_add_ps(xmm, p0d5);
     593           2 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     594             : 
     595           1 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     596             : 
     597             : #if __SSE4_1__
     598             :     xmm_i = _mm_packus_epi32(xmm_i, xmm_i);  // Pack int32 to uint16
     599             : #else
     600             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
     601           2 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
     602           1 :     xmm_i = _mm_packs_epi32(xmm_i, xmm_i);  // Pack int32 to int16
     603             :     // Translate back to uint16 range (actually -32768==32768 in int16)
     604           1 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
     605             : #endif
     606           1 :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     607           1 : }
     608             : 
     609             : #ifdef __AVX2__
     610             : 
     611             : #include <immintrin.h>
     612             : 
     613             : template <>
     614             : inline void GDALCopy8Words(const float *pValueIn, GByte *const pValueOut)
     615             : {
     616             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     617             : 
     618             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     619             :     const __m256 ymm_max = _mm256_set1_ps(255);
     620             :     ymm = _mm256_add_ps(ymm, p0d5);
     621             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     622             : 
     623             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
     624             : 
     625             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
     626             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
     627             : 
     628             :     __m128i xmm_i = _mm256_castsi256_si128(ymm_i);
     629             :     xmm_i = _mm_packus_epi16(xmm_i, xmm_i);
     630             :     GDALCopyXMMToInt64(xmm_i, pValueOut);
     631             : }
     632             : 
     633             : template <>
     634             : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
     635             : {
     636             :     __m256 ymm = _mm256_loadu_ps(pValueIn);
     637             : 
     638             :     const __m256 p0d5 = _mm256_set1_ps(0.5f);
     639             :     const __m256 ymm_max = _mm256_set1_ps(65535);
     640             :     ymm = _mm256_add_ps(ymm, p0d5);
     641             :     ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
     642             : 
     643             :     __m256i ymm_i = _mm256_cvttps_epi32(ymm);
     644             : 
     645             :     ymm_i = _mm256_packus_epi32(ymm_i, ymm_i);  // Pack int32 to uint16
     646             :     ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2));  // AVX2
     647             : 
     648             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut),
     649             :                      _mm256_castsi256_si128(ymm_i));
     650             : }
     651             : #else
     652             : template <>
     653     7711511 : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
     654             : {
     655     7711511 :     __m128 xmm = _mm_loadu_ps(pValueIn);
     656    15423002 :     __m128 xmm1 = _mm_loadu_ps(pValueIn + 4);
     657             : 
     658     7711511 :     const __m128 p0d5 = _mm_set1_ps(0.5f);
     659     7711511 :     const __m128 xmm_max = _mm_set1_ps(65535);
     660     7711511 :     xmm = _mm_add_ps(xmm, p0d5);
     661     7711511 :     xmm1 = _mm_add_ps(xmm1, p0d5);
     662    15453202 :     xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
     663    15469502 :     xmm1 = _mm_min_ps(_mm_max_ps(xmm1, p0d5), xmm_max);
     664             : 
     665     7722511 :     __m128i xmm_i = _mm_cvttps_epi32(xmm);
     666     7744661 :     __m128i xmm1_i = _mm_cvttps_epi32(xmm1);
     667             : 
     668             : #if __SSE4_1__
     669             :     xmm_i = _mm_packus_epi32(xmm_i, xmm1_i);  // Pack int32 to uint16
     670             : #else
     671             :     // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
     672    15489302 :     xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
     673    15489302 :     xmm1_i = _mm_add_epi32(xmm1_i, _mm_set1_epi32(-32768));
     674     7756691 :     xmm_i = _mm_packs_epi32(xmm_i, xmm1_i);  // Pack int32 to int16
     675             :     // Translate back to uint16 range (actually -32768==32768 in int16)
     676    15513402 :     xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
     677             : #endif
     678             :     _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut), xmm_i);
     679     7756691 : }
     680             : #endif
     681             : 
     682             : #ifdef notdef_because_slightly_slower_than_default_implementation
     683             : template <>
     684             : inline void GDALCopy4Words(const double *pValueIn, float *const pValueOut)
     685             : {
     686             :     __m128d float_posmax = _mm_set1_pd(std::numeric_limits<float>::max());
     687             :     __m128d float_negmax = _mm_set1_pd(-std::numeric_limits<float>::max());
     688             :     __m128d float_posinf = _mm_set1_pd(std::numeric_limits<float>::infinity());
     689             :     __m128d float_neginf = _mm_set1_pd(-std::numeric_limits<float>::infinity());
     690             :     __m128d val01 = _mm_loadu_pd(pValueIn);
     691             :     __m128d val23 = _mm_loadu_pd(pValueIn + 2);
     692             :     __m128d mask_max = _mm_cmpge_pd(val01, float_posmax);
     693             :     __m128d mask_max23 = _mm_cmpge_pd(val23, float_posmax);
     694             :     val01 = _mm_or_pd(_mm_and_pd(mask_max, float_posinf),
     695             :                       _mm_andnot_pd(mask_max, val01));
     696             :     val23 = _mm_or_pd(_mm_and_pd(mask_max23, float_posinf),
     697             :                       _mm_andnot_pd(mask_max23, val23));
     698             :     __m128d mask_min = _mm_cmple_pd(val01, float_negmax);
     699             :     __m128d mask_min23 = _mm_cmple_pd(val23, float_negmax);
     700             :     val01 = _mm_or_pd(_mm_and_pd(mask_min, float_neginf),
     701             :                       _mm_andnot_pd(mask_min, val01));
     702             :     val23 = _mm_or_pd(_mm_and_pd(mask_min23, float_neginf),
     703             :                       _mm_andnot_pd(mask_min23, val23));
     704             :     __m128 val01_s = _mm_cvtpd_ps(val01);
     705             :     __m128 val23_s = _mm_cvtpd_ps(val23);
     706             :     __m128i val01_i = _mm_castps_si128(val01_s);
     707             :     __m128i val23_i = _mm_castps_si128(val23_s);
     708             :     GDALCopyXMMToInt64(val01_i, pValueOut);
     709             :     GDALCopyXMMToInt64(val23_i, pValueOut + 2);
     710             : }
     711             : #endif
     712             : 
     713             : #endif  //  defined(__x86_64) || defined(_M_X64)
     714             : 
     715             : #endif  // GDAL_PRIV_TEMPLATES_HPP_INCLUDED

Generated by: LCOV version 1.14