LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3375 4085 82.6 %
Date: 2026-01-31 22:56:34 Functions: 320 352 90.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Base class for format specific band class implementation.  This
       5             :  *           base class provides default implementation for many methods.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1998, Frank Warmerdam
      10             :  * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "cpl_float.h"
      17             : 
      18             : #include <cassert>
      19             : #include <climits>
      20             : #include <cmath>
      21             : #include <cstdarg>
      22             : #include <cstddef>
      23             : #include <cstdio>
      24             : #include <cstdlib>
      25             : #include <cstring>
      26             : #include <algorithm>
      27             : #include <limits>
      28             : #include <memory>
      29             : #include <new>
      30             : #include <numeric>  // std::lcm
      31             : #include <type_traits>
      32             : 
      33             : #include "cpl_conv.h"
      34             : #include "cpl_error.h"
      35             : #include "cpl_float.h"
      36             : #include "cpl_multiproc.h"
      37             : #include "cpl_progress.h"
      38             : #include "cpl_string.h"
      39             : #include "cpl_virtualmem.h"
      40             : #include "cpl_vsi.h"
      41             : #include "gdal.h"
      42             : #include "gdal_abstractbandblockcache.h"
      43             : #include "gdalantirecursion.h"
      44             : #include "gdal_rat.h"
      45             : #include "gdal_rasterband.h"
      46             : #include "gdal_priv_templates.hpp"
      47             : #include "gdal_interpolateatpoint.h"
      48             : #include "gdal_minmax_element.hpp"
      49             : #include "gdalmultidim_priv.h"
      50             : #include "gdal_thread_pool.h"
      51             : 
      52             : #ifdef USE_NEON_OPTIMIZATIONS
      53             : #include "include_sse2neon.h"
      54             : #endif
      55             : 
      56             : #if defined(__AVX2__) || defined(__FMA__)
      57             : #include <immintrin.h>
      58             : #endif
      59             : 
      60             : /************************************************************************/
      61             : /*                           GDALRasterBand()                           */
      62             : /************************************************************************/
      63             : 
      64             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      65             : 
      66     1577630 : GDALRasterBand::GDALRasterBand()
      67             :     : GDALRasterBand(
      68     1577630 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      69             : {
      70     1577630 : }
      71             : 
      72             : /** Constructor. Applications should never create GDALRasterBands directly.
      73             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      74             :  */
      75     1858830 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      76     1858830 :     : bForceCachedIO(bForceCachedIOIn)
      77             : 
      78             : {
      79     1858830 : }
      80             : 
      81             : /************************************************************************/
      82             : /*                          ~GDALRasterBand()                           */
      83             : /************************************************************************/
      84             : 
      85             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      86             :     instead destroy the GDALDataset. */
      87             : 
      88     1858820 : GDALRasterBand::~GDALRasterBand()
      89             : 
      90             : {
      91     1858820 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      92             :     {
      93         574 :         if (poBandBlockCache)
      94         511 :             poBandBlockCache->DisableDirtyBlockWriting();
      95             :     }
      96     1858820 :     GDALRasterBand::FlushCache(true);
      97             : 
      98     1858820 :     delete poBandBlockCache;
      99             : 
     100     1858820 :     if (static_cast<GIntBig>(nBlockReads) >
     101     1858820 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
     102         228 :         nBand == 1 && poDS != nullptr)
     103             :     {
     104         336 :         CPLDebug(
     105             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
     106         168 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
     107         168 :             poDS->GetDescription());
     108             :     }
     109             : 
     110     1858820 :     InvalidateMaskBand();
     111     1858820 :     nBand = -nBand;
     112             : 
     113     1858820 :     delete m_poPointsCache;
     114     1858820 : }
     115             : 
     116             : /************************************************************************/
     117             : /*                              RasterIO()                              */
     118             : /************************************************************************/
     119             : 
     120             : /**
     121             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     122             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     123             :  *                                void * pData, int nBufXSize, int nBufYSize,
     124             :  *                                GDALDataType eBufType,
     125             :  *                                GSpacing nPixelSpace,
     126             :  *                                GSpacing nLineSpace,
     127             :  *                                GDALRasterIOExtraArg* psExtraArg )
     128             :  * \brief Read/write a region of image data for this band.
     129             :  *
     130             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     131             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     132             :  * automatically takes care of data type translation if the data type
     133             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     134             :  * The method also takes care of image decimation / replication if the
     135             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     136             :  * region being accessed (nXSize x nYSize).
     137             :  *
     138             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     139             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     140             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     141             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     142             :  * Or use nLineSpace and a possibly shifted pData value.
     143             :  *
     144             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     145             :  * writing from unusually organized buffers. This is primarily used
     146             :  * for buffers containing more than one bands raster data in interleaved
     147             :  * format.
     148             :  *
     149             :  * Some formats may efficiently implement decimation into a buffer by
     150             :  * reading from lower resolution overview images. The logic of the default
     151             :  * implementation in the base class GDALRasterBand is the following one. It
     152             :  * computes a target_downscaling_factor from the window of interest and buffer
     153             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     154             :  * It then walks through overviews and will select the first one whose
     155             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     156             :  *
     157             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     158             :  * The relationship between target_downscaling_factor and the select overview
     159             :  * level is the following one:
     160             :  *
     161             :  * target_downscaling_factor  | selected_overview
     162             :  * -------------------------  | -----------------
     163             :  * ]0,       2 / 1.2]         | full resolution band
     164             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     165             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     166             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     167             :  *
     168             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     169             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     170             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     171             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     172             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     173             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     174             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     175             :  *
     176             :  * For highest performance full resolution data access, read and write
     177             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     178             :  * ReadBlock() and WriteBlock() methods.
     179             :  *
     180             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     181             :  * functions.
     182             :  *
     183             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     184             :  * write a region of data.
     185             :  *
     186             :  * @param nXOff The pixel offset to the top left corner of the region
     187             :  * of the band to be accessed. This would be zero to start from the left side.
     188             :  *
     189             :  * @param nYOff The line offset to the top left corner of the region
     190             :  * of the band to be accessed. This would be zero to start from the top.
     191             :  *
     192             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     193             :  *
     194             :  * @param nYSize The height of the region of the band to be accessed in lines.
     195             :  *
     196             :  * @param pData The buffer into which the data should be read, or from which
     197             :  * it should be written. This buffer must contain at least nBufXSize *
     198             :  * nBufYSize words of type eBufType. It is organized in left to right,
     199             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     200             :  * and nLineSpace parameters.
     201             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     202             :  * temporarily modified during the execution of this method (and eventually
     203             :  * restored back to its original content), so it is not safe to use a buffer
     204             :  * stored in a read-only section of the calling program.
     205             :  *
     206             :  * @param nBufXSize the width of the buffer image into which the desired region
     207             :  * is to be read, or from which it is to be written.
     208             :  *
     209             :  * @param nBufYSize the height of the buffer image into which the desired region
     210             :  * is to be read, or from which it is to be written.
     211             :  *
     212             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     213             :  * pixel values will automatically be translated to/from the GDALRasterBand
     214             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     215             :  * to perform data type translation.
     216             :  *
     217             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     218             :  * pData to the start of the next pixel value within a scanline. If defaulted
     219             :  * (0) the size of the datatype eBufType is used.
     220             :  *
     221             :  * @param nLineSpace The byte offset from the start of one scanline in
     222             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     223             :  * eBufType * nBufXSize is used.
     224             :  *
     225             :  * @param psExtraArg Pointer to a GDALRasterIOExtraArg
     226             :  * structure with additional arguments to specify resampling and progress
     227             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     228             :  * configuration option can also be defined to override the default resampling
     229             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     230             :  *
     231             :  * @return CE_Failure if the access fails, otherwise CE_None.
     232             :  */
     233             : 
     234             : /**
     235             :  * \brief Read/write a region of image data for this band.
     236             :  *
     237             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     238             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     239             :  * automatically takes care of data type translation if the data type
     240             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     241             :  * The method also takes care of image decimation / replication if the
     242             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     243             :  * region being accessed (nXSize x nYSize).
     244             :  *
     245             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     246             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     247             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     248             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     249             :  * Or use nLineSpace and a possibly shifted pData value.
     250             :  *
     251             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     252             :  * writing from unusually organized buffers. This is primarily used
     253             :  * for buffers containing more than one bands raster data in interleaved
     254             :  * format.
     255             :  *
     256             :  * Some formats may efficiently implement decimation into a buffer by
     257             :  * reading from lower resolution overview images. The logic of the default
     258             :  * implementation in the base class GDALRasterBand is the following one. It
     259             :  * computes a target_downscaling_factor from the window of interest and buffer
     260             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     261             :  * It then walks through overviews and will select the first one whose
     262             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     263             :  *
     264             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     265             :  * The relationship between target_downscaling_factor and the select overview
     266             :  * level is the following one:
     267             :  *
     268             :  * target_downscaling_factor  | selected_overview
     269             :  * -------------------------  | -----------------
     270             :  * ]0,       2 / 1.2]         | full resolution band
     271             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     272             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     273             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     274             :  *
     275             :  * For highest performance full resolution data access, read and write
     276             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     277             :  * ReadBlock() and WriteBlock() methods.
     278             :  *
     279             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     280             :  * functions.
     281             :  *
     282             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     283             :  * more convenient to use for most common use cases.
     284             :  *
     285             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     286             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     287             :  * instance of this dataset) concurrently from several threads.
     288             :  *
     289             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     290             :  * write a region of data.
     291             :  *
     292             :  * @param nXOff The pixel offset to the top left corner of the region
     293             :  * of the band to be accessed. This would be zero to start from the left side.
     294             :  *
     295             :  * @param nYOff The line offset to the top left corner of the region
     296             :  * of the band to be accessed. This would be zero to start from the top.
     297             :  *
     298             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     299             :  *
     300             :  * @param nYSize The height of the region of the band to be accessed in lines.
     301             :  *
     302             :  * @param[in,out] pData The buffer into which the data should be read, or from
     303             :  * which it should be written. This buffer must contain at least nBufXSize *
     304             :  * nBufYSize words of type eBufType. It is organized in left to right,
     305             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     306             :  * and nLineSpace parameters.
     307             :  *
     308             :  * @param nBufXSize the width of the buffer image into which the desired region
     309             :  * is to be read, or from which it is to be written.
     310             :  *
     311             :  * @param nBufYSize the height of the buffer image into which the desired region
     312             :  * is to be read, or from which it is to be written.
     313             :  *
     314             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     315             :  * pixel values will automatically be translated to/from the GDALRasterBand
     316             :  * data type as needed.
     317             :  *
     318             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     319             :  * pData to the start of the next pixel value within a scanline. If defaulted
     320             :  * (0) the size of the datatype eBufType is used.
     321             :  *
     322             :  * @param nLineSpace The byte offset from the start of one scanline in
     323             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     324             :  * eBufType * nBufXSize is used.
     325             :  *
     326             :  * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
     327             :  * structure with additional arguments to specify resampling and progress
     328             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     329             :  * configuration option can also be defined to override the default resampling
     330             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     331             :  *
     332             :  * @return CE_Failure if the access fails, otherwise CE_None.
     333             :  *
     334             :  * @see GDALRasterBand::ReadRaster()
     335             :  */
     336             : 
     337     4422020 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     338             :                                 int nXSize, int nYSize, void *pData,
     339             :                                 int nBufXSize, int nBufYSize,
     340             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     341             :                                 GSpacing nLineSpace,
     342             :                                 GDALRasterIOExtraArg *psExtraArg)
     343             : 
     344             : {
     345             :     GDALRasterIOExtraArg sExtraArg;
     346     4422020 :     if (psExtraArg == nullptr)
     347             :     {
     348     3823730 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     349     3823730 :         psExtraArg = &sExtraArg;
     350             :     }
     351      598291 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
     352             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     353             :     {
     354           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     355             :                     "Unhandled version of GDALRasterIOExtraArg");
     356           0 :         return CE_Failure;
     357             :     }
     358             : 
     359     4422020 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     360             :                                        nBufYSize);
     361             : 
     362     4422020 :     if (CPL_UNLIKELY(nullptr == pData))
     363             :     {
     364           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     365             :                     "The buffer into which the data should be read is null");
     366           0 :         return CE_Failure;
     367             :     }
     368             : 
     369             :     /* -------------------------------------------------------------------- */
     370             :     /*      Some size values are "noop".  Lets just return to avoid         */
     371             :     /*      stressing lower level functions.                                */
     372             :     /* -------------------------------------------------------------------- */
     373     4422020 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     374             :                      nBufYSize < 1))
     375             :     {
     376           2 :         CPLDebug("GDAL",
     377             :                  "RasterIO() skipped for odd window or buffer size.\n"
     378             :                  "  Window = (%d,%d)x%dx%d\n"
     379             :                  "  Buffer = %dx%d\n",
     380             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     381             : 
     382           2 :         return CE_None;
     383             :     }
     384             : 
     385     4422020 :     if (eRWFlag == GF_Write)
     386             :     {
     387      366961 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     388             :         {
     389           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     390             :                         "An error occurred while writing a dirty block "
     391             :                         "from GDALRasterBand::RasterIO");
     392           0 :             CPLErr eErr = eFlushBlockErr;
     393           0 :             eFlushBlockErr = CE_None;
     394           0 :             return eErr;
     395             :         }
     396      366961 :         if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
     397             :         {
     398           7 :             return CE_Failure;
     399             :         }
     400             :     }
     401             : 
     402             :     /* -------------------------------------------------------------------- */
     403             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     404             :     /*      value assuming a packed buffer.                                 */
     405             :     /* -------------------------------------------------------------------- */
     406     4422020 :     if (nPixelSpace == 0)
     407             :     {
     408     4023690 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     409             :     }
     410             : 
     411     4422020 :     if (nLineSpace == 0)
     412             :     {
     413     4011340 :         nLineSpace = nPixelSpace * nBufXSize;
     414             :     }
     415             : 
     416             :     /* -------------------------------------------------------------------- */
     417             :     /*      Do some validation of parameters.                               */
     418             :     /* -------------------------------------------------------------------- */
     419     4422020 :     if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
     420             :                      nYSize > nRasterYSize - nYOff))
     421             :     {
     422          15 :         ReportError(CE_Failure, CPLE_IllegalArg,
     423             :                     "Access window out of range in RasterIO().  Requested\n"
     424             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     425             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     426          15 :         return CE_Failure;
     427             :     }
     428             : 
     429     4422000 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     430             :     {
     431           0 :         ReportError(
     432             :             CE_Failure, CPLE_IllegalArg,
     433             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     434             :             eRWFlag);
     435           0 :         return CE_Failure;
     436             :     }
     437     4422000 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     438             :     {
     439           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     440             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     441           2 :         return CE_Failure;
     442             :     }
     443             : 
     444     4422000 :     return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     445             :                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
     446     4422000 :                             nLineSpace, psExtraArg);
     447             : }
     448             : 
     449             : /************************************************************************/
     450             : /*                          RasterIOInternal()                          */
     451             : /************************************************************************/
     452             : 
     453     4422030 : CPLErr GDALRasterBand::RasterIOInternal(
     454             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     455             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     456             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     457             : {
     458             :     /* -------------------------------------------------------------------- */
     459             :     /*      Call the format specific function.                              */
     460             :     /* -------------------------------------------------------------------- */
     461             : 
     462     4422030 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     463             : 
     464             :     CPLErr eErr;
     465     4422030 :     if (bForceCachedIO)
     466          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     467             :                                          pData, nBufXSize, nBufYSize, eBufType,
     468             :                                          nPixelSpace, nLineSpace, psExtraArg);
     469             :     else
     470             :         eErr =
     471     4422010 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     472     4422010 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     473             : 
     474     4422030 :     if (bCallLeaveReadWrite)
     475      603484 :         LeaveReadWrite();
     476             : 
     477     4422030 :     return eErr;
     478             : }
     479             : 
     480             : /************************************************************************/
     481             : /*                            GDALRasterIO()                            */
     482             : /************************************************************************/
     483             : 
     484             : /**
     485             :  * \brief Read/write a region of image data for this band.
     486             :  *
     487             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     488             :  * resolution, progress callback, etc. are needed)
     489             :  *
     490             :  * @see GDALRasterBand::RasterIO()
     491             :  */
     492             : 
     493     3407950 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     494             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     495             :                                 void *pData, int nBufXSize, int nBufYSize,
     496             :                                 GDALDataType eBufType, int nPixelSpace,
     497             :                                 int nLineSpace)
     498             : 
     499             : {
     500     3407950 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     501             : 
     502     3407950 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     503             : 
     504     3407950 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     505             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     506     3407950 :                              nLineSpace, nullptr));
     507             : }
     508             : 
     509             : /************************************************************************/
     510             : /*                           GDALRasterIOEx()                           */
     511             : /************************************************************************/
     512             : 
     513             : /**
     514             :  * \brief Read/write a region of image data for this band.
     515             :  *
     516             :  * @see GDALRasterBand::RasterIO()
     517             :  */
     518             : 
     519       41332 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     520             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     521             :                                   void *pData, int nBufXSize, int nBufYSize,
     522             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     523             :                                   GSpacing nLineSpace,
     524             :                                   GDALRasterIOExtraArg *psExtraArg)
     525             : 
     526             : {
     527       41332 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     528             : 
     529       41332 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     530             : 
     531       41332 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     532             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     533       41332 :                              nLineSpace, psExtraArg));
     534             : }
     535             : 
     536             : /************************************************************************/
     537             : /*                         GetGDTFromCppType()                          */
     538             : /************************************************************************/
     539             : 
     540             : namespace
     541             : {
     542             : template <class T> struct GetGDTFromCppType;
     543             : 
     544             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     545             :     template <> struct GetGDTFromCppType<T>                                    \
     546             :     {                                                                          \
     547             :         static constexpr GDALDataType GDT = eDT;                               \
     548             :     }
     549             : 
     550             : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
     551             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     552             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     553             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     554             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     555             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     556             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     557             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     558             : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
     559             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     560             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     561             : // Not allowed by C++ standard
     562             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     563             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     564             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     565             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     566             : }  // namespace
     567             : 
     568             : /************************************************************************/
     569             : /*                             ReadRaster()                             */
     570             : /************************************************************************/
     571             : 
     572             : // clang-format off
     573             : /** Read a region of image data for this band.
     574             :  *
     575             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     576             :  * for common use cases, like reading a whole band.
     577             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     578             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     579             :  * float, double, std::complex<float|double>.
     580             :  *
     581             :  * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
     582             :  * and can allocate memory automatically.
     583             :  *
     584             :  * To read a whole band (assuming it fits into memory), as an array of double:
     585             :  *
     586             : \code{.cpp}
     587             :  double* myArray = static_cast<double*>(
     588             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     589             :  // TODO: check here that myArray != nullptr
     590             :  const size_t nArrayEltCount =
     591             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     592             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     593             :  {
     594             :      // do something
     595             :  }
     596             :  VSIFree(myArray)
     597             : \endcode
     598             :  *
     599             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     600             :  *
     601             : \code{.cpp}
     602             :  double* myArray = static_cast<double*>(
     603             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     604             :  // TODO: check here that myArray != nullptr
     605             :  const size_t nArrayEltCount = 128 * 128;
     606             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     607             :  {
     608             :      // do something
     609             :  }
     610             :  VSIFree(myArray)
     611             : \endcode
     612             :  *
     613             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     614             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     615             :  * instance of this dataset) concurrently from several threads.
     616             :  *
     617             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     618             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     619             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     620             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     621             :  * Or use nLineSpace and a possibly shifted pData value.
     622             :  *
     623             :  * @param[out] pData The buffer into which the data should be written.
     624             :  * This buffer must contain at least nBufXSize *
     625             :  * nBufYSize words of type T. It is organized in left to right,
     626             :  * top to bottom pixel order, and fully packed.
     627             :  * The type of the buffer does not need to be the one of GetDataType(). The
     628             :  * method will perform data type translation (with potential rounding, clamping)
     629             :  * if needed.
     630             :  *
     631             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     632             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     633             :  * return in error if it is not. If set to zero, then pData is trusted to be
     634             :  * large enough.
     635             :  *
     636             :  * @param dfXOff The pixel offset to the top left corner of the region
     637             :  * of the band to be accessed. This would be zero to start from the left side.
     638             :  * Defaults to 0.
     639             :  *
     640             :  * @param dfYOff The line offset to the top left corner of the region
     641             :  * of the band to be accessed. This would be zero to start from the top.
     642             :  * Defaults to 0.
     643             :  *
     644             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     645             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     646             :  * dfXSize is set to the band width.
     647             :  *
     648             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     649             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     650             :  * dfYSize is set to the band height.
     651             :  *
     652             :  * @param nBufXSize the width of the buffer image into which the desired region
     653             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     654             :  * then nBufXSize is initialized with dfXSize.
     655             :  *
     656             :  * @param nBufYSize the height of the buffer image into which the desired region
     657             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     658             :  * then nBufYSize is initialized with dfYSize.
     659             :  *
     660             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     661             :  *
     662             :  * @param pfnProgress Progress function. May be nullptr.
     663             :  *
     664             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     665             :  *
     666             :  * @return CE_Failure if the access fails, otherwise CE_None.
     667             :  *
     668             :  * @see GDALRasterBand::RasterIO()
     669             :  * @since GDAL 3.10
     670             :  */
     671             : // clang-format on
     672             : 
     673             : template <class T>
     674          20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     675             :                                   double dfXOff, double dfYOff, double dfXSize,
     676             :                                   double dfYSize, size_t nBufXSize,
     677             :                                   size_t nBufYSize,
     678             :                                   GDALRIOResampleAlg eResampleAlg,
     679             :                                   GDALProgressFunc pfnProgress,
     680             :                                   void *pProgressData) const
     681             : {
     682          20 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     683             :     {
     684           2 :         return CE_Failure;
     685             :     }
     686             : 
     687          18 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     688             :     {
     689          16 :         dfXSize = nRasterXSize;
     690          16 :         dfYSize = nRasterYSize;
     691             :     }
     692           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     693           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     694           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     695           2 :              dfYOff + dfYSize > INT_MAX)
     696             :     {
     697           0 :         return CE_Failure;
     698             :     }
     699             : 
     700             :     GDALRasterIOExtraArg sExtraArg;
     701          18 :     sExtraArg.nVersion = 1;
     702          18 :     sExtraArg.eResampleAlg = eResampleAlg;
     703          18 :     sExtraArg.pfnProgress = pfnProgress;
     704          18 :     sExtraArg.pProgressData = pProgressData;
     705          18 :     sExtraArg.bFloatingPointWindowValidity = true;
     706          18 :     sExtraArg.dfXOff = dfXOff;
     707          18 :     sExtraArg.dfYOff = dfYOff;
     708          18 :     sExtraArg.dfXSize = dfXSize;
     709          18 :     sExtraArg.dfYSize = dfYSize;
     710          18 :     const int nXOff = static_cast<int>(dfXOff);
     711          18 :     const int nYOff = static_cast<int>(dfYOff);
     712          18 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     713          18 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     714          18 :     if (nBufXSize == 0 && nBufYSize == 0)
     715             :     {
     716          17 :         if (static_cast<int>(dfXSize) == dfXSize &&
     717          17 :             static_cast<int>(dfYSize) == dfYSize)
     718             :         {
     719          17 :             nBufXSize = static_cast<int>(dfXSize);
     720          17 :             nBufYSize = static_cast<int>(dfYSize);
     721             :         }
     722             :         else
     723             :         {
     724           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     725             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     726             :                      "dfYSize is not an integer value");
     727           0 :             return CE_Failure;
     728             :         }
     729             :     }
     730          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     731             :     {
     732           0 :         CPLDebug("GDAL",
     733             :                  "RasterIO() skipped for odd window or buffer size.\n"
     734             :                  "  Window = (%d,%d)x%dx%d\n"
     735             :                  "  Buffer = %dx%d\n",
     736             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     737             :                  static_cast<int>(nBufYSize));
     738             : 
     739           0 :         return CE_None;
     740             :     }
     741             : 
     742          18 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     743             :     {
     744           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     745             :                  "Provided array is not large enough");
     746           1 :         return CE_Failure;
     747             :     }
     748             : 
     749          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     750          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     751          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     752             : 
     753          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     754             : 
     755             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     756             :                                    static_cast<int>(nBufXSize),
     757             :                                    static_cast<int>(nBufYSize), eBufType,
     758          17 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     759             : }
     760             : 
     761             : //! @cond Doxygen_Suppress
     762             : 
     763             : #define INSTANTIATE_READ_RASTER(T)                                             \
     764             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     765             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     766             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     767             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     768             :         void *pProgressData) const;
     769             : 
     770             : INSTANTIATE_READ_RASTER(uint8_t)
     771             : INSTANTIATE_READ_RASTER(int8_t)
     772             : INSTANTIATE_READ_RASTER(uint16_t)
     773             : INSTANTIATE_READ_RASTER(int16_t)
     774             : INSTANTIATE_READ_RASTER(uint32_t)
     775             : INSTANTIATE_READ_RASTER(int32_t)
     776             : INSTANTIATE_READ_RASTER(uint64_t)
     777             : INSTANTIATE_READ_RASTER(int64_t)
     778             : INSTANTIATE_READ_RASTER(GFloat16)
     779             : INSTANTIATE_READ_RASTER(float)
     780             : INSTANTIATE_READ_RASTER(double)
     781             : // Not allowed by C++ standard
     782             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     783             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     784             : INSTANTIATE_READ_RASTER(std::complex<float>)
     785             : INSTANTIATE_READ_RASTER(std::complex<double>)
     786             : 
     787             : //! @endcond
     788             : 
     789             : /************************************************************************/
     790             : /*                             ReadRaster()                             */
     791             : /************************************************************************/
     792             : 
     793             : /** Read a region of image data for this band.
     794             :  *
     795             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     796             :  * for common use cases, like reading a whole band.
     797             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     798             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     799             :  * float, double, std::complex<float|double>.
     800             :  *
     801             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     802             :  *
     803             : \code
     804             :  std::vector<double> myArray;
     805             :  if (poBand->ReadRaster(myArray) == CE_None)
     806             :  {
     807             :      // do something
     808             :  }
     809             : \endcode
     810             :  *
     811             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     812             :  *
     813             : \code{.cpp}
     814             :  std::vector<double> myArray;
     815             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     816             :  {
     817             :      // do something
     818             :  }
     819             : \endcode
     820             :  *
     821             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     822             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     823             :  * instance of this dataset) concurrently from several threads.
     824             :  *
     825             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     826             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     827             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     828             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     829             :  * Or use nLineSpace and a possibly shifted pData value.
     830             :  *
     831             :  * @param[out] vData The vector into which the data should be written.
     832             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     833             :  * nBufYSize values. The values in the vector are organized in left to right,
     834             :  * top to bottom pixel order, and fully packed.
     835             :  * The type of the vector does not need to be the one of GetDataType(). The
     836             :  * method will perform data type translation (with potential rounding, clamping)
     837             :  * if needed.
     838             :  *
     839             :  * @param dfXOff The pixel offset to the top left corner of the region
     840             :  * of the band to be accessed. This would be zero to start from the left side.
     841             :  * Defaults to 0.
     842             :  *
     843             :  * @param dfYOff The line offset to the top left corner of the region
     844             :  * of the band to be accessed. This would be zero to start from the top.
     845             :  * Defaults to 0.
     846             :  *
     847             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     848             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     849             :  * dfXSize is set to the band width.
     850             :  *
     851             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     852             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     853             :  * dfYSize is set to the band height.
     854             :  *
     855             :  * @param nBufXSize the width of the buffer image into which the desired region
     856             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     857             :  * then nBufXSize is initialized with dfXSize.
     858             :  *
     859             :  * @param nBufYSize the height of the buffer image into which the desired region
     860             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     861             :  * then nBufYSize is initialized with dfYSize.
     862             :  *
     863             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     864             :  *
     865             :  * @param pfnProgress Progress function. May be nullptr.
     866             :  *
     867             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     868             :  *
     869             :  * @return CE_Failure if the access fails, otherwise CE_None.
     870             :  *
     871             :  * @see GDALRasterBand::RasterIO()
     872             :  * @since GDAL 3.10
     873             :  */
     874             : template <class T>
     875          22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     876             :                                   double dfYOff, double dfXSize, double dfYSize,
     877             :                                   size_t nBufXSize, size_t nBufYSize,
     878             :                                   GDALRIOResampleAlg eResampleAlg,
     879             :                                   GDALProgressFunc pfnProgress,
     880             :                                   void *pProgressData) const
     881             : {
     882          22 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     883             :     {
     884           2 :         return CE_Failure;
     885             :     }
     886             : 
     887          20 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     888             :     {
     889          13 :         dfXSize = nRasterXSize;
     890          13 :         dfYSize = nRasterYSize;
     891             :     }
     892           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     893           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     894           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     895           7 :              dfYOff + dfYSize > INT_MAX)
     896             :     {
     897           0 :         return CE_Failure;
     898             :     }
     899             : 
     900             :     GDALRasterIOExtraArg sExtraArg;
     901          20 :     sExtraArg.nVersion = 1;
     902          20 :     sExtraArg.eResampleAlg = eResampleAlg;
     903          20 :     sExtraArg.pfnProgress = pfnProgress;
     904          20 :     sExtraArg.pProgressData = pProgressData;
     905          20 :     sExtraArg.bFloatingPointWindowValidity = true;
     906          20 :     sExtraArg.dfXOff = dfXOff;
     907          20 :     sExtraArg.dfYOff = dfYOff;
     908          20 :     sExtraArg.dfXSize = dfXSize;
     909          20 :     sExtraArg.dfYSize = dfYSize;
     910          20 :     const int nXOff = static_cast<int>(dfXOff);
     911          20 :     const int nYOff = static_cast<int>(dfYOff);
     912          20 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     913          20 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     914          20 :     if (nBufXSize == 0 && nBufYSize == 0)
     915             :     {
     916          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     917          15 :             static_cast<int>(dfYSize) == dfYSize)
     918             :         {
     919          15 :             nBufXSize = static_cast<int>(dfXSize);
     920          15 :             nBufYSize = static_cast<int>(dfYSize);
     921             :         }
     922             :         else
     923             :         {
     924           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     925             :                      "nBufXSize and nBufYSize must be provided if "
     926             :                      "dfXSize or dfYSize is not an integer value");
     927           1 :             return CE_Failure;
     928             :         }
     929             :     }
     930          19 :     if (nBufXSize == 0 || nBufYSize == 0)
     931             :     {
     932           0 :         CPLDebug("GDAL",
     933             :                  "RasterIO() skipped for odd window or buffer size.\n"
     934             :                  "  Window = (%d,%d)x%dx%d\n"
     935             :                  "  Buffer = %dx%d\n",
     936             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     937             :                  static_cast<int>(nBufYSize));
     938             : 
     939           0 :         return CE_None;
     940             :     }
     941             : 
     942             :     if constexpr (SIZEOF_VOIDP < 8)
     943             :     {
     944             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     945             :         {
     946             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     947             :             return CE_Failure;
     948             :         }
     949             :     }
     950             : 
     951          19 :     if (vData.size() < nBufXSize * nBufYSize)
     952             :     {
     953             :         try
     954             :         {
     955          17 :             vData.resize(nBufXSize * nBufYSize);
     956             :         }
     957           1 :         catch (const std::exception &)
     958             :         {
     959           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     960           1 :             return CE_Failure;
     961             :         }
     962             :     }
     963             : 
     964          18 :     constexpr GSpacing nPixelSpace = sizeof(T);
     965          18 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     966          18 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     967             : 
     968          18 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     969             : 
     970             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
     971             :                                    vData.data(), static_cast<int>(nBufXSize),
     972             :                                    static_cast<int>(nBufYSize), eBufType,
     973          18 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     974             : }
     975             : 
     976             : //! @cond Doxygen_Suppress
     977             : 
     978             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     979             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     980             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     981             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     982             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     983             :         void *pProgressData) const;
     984             : 
     985             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     986             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     987             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     988             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     989             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     990             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     991             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     992             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     993             : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
     994             : INSTANTIATE_READ_RASTER_VECTOR(float)
     995             : INSTANTIATE_READ_RASTER_VECTOR(double)
     996             : // Not allowed by C++ standard
     997             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
     998             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
     999             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
    1000             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
    1001             : 
    1002             : //! @endcond
    1003             : 
    1004             : /************************************************************************/
    1005             : /*                             ReadBlock()                              */
    1006             : /************************************************************************/
    1007             : 
    1008             : /**
    1009             :  * \brief Read a block of image data efficiently.
    1010             :  *
    1011             :  * This method accesses a "natural" block from the raster band without
    1012             :  * resampling, or data type conversion.  For a more generalized, but
    1013             :  * potentially less efficient access use RasterIO().
    1014             :  *
    1015             :  * This method is the same as the C GDALReadBlock() function.
    1016             :  *
    1017             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1018             :  * block oriented data without an extra copy into an application buffer.
    1019             :  *
    1020             :  * The following code would efficiently compute a histogram of eight bit
    1021             :  * raster data.  Note that the final block may be partial ... data beyond
    1022             :  * the edge of the underlying raster band in these edge blocks is of an
    1023             :  * undetermined value.
    1024             :  *
    1025             : \code{.cpp}
    1026             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1027             : 
    1028             :  {
    1029             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1030             : 
    1031             :      CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
    1032             : 
    1033             :      int nXBlockSize, nYBlockSize;
    1034             : 
    1035             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1036             :      int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
    1037             :      int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
    1038             : 
    1039             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1040             : 
    1041             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1042             :      {
    1043             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1044             :          {
    1045             :              int        nXValid, nYValid;
    1046             : 
    1047             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1048             : 
    1049             :              // Compute the portion of the block that is valid
    1050             :              // for partial edge blocks.
    1051             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1052             : 
    1053             :              // Collect the histogram counts.
    1054             :              for( int iY = 0; iY < nYValid; iY++ )
    1055             :              {
    1056             :                  for( int iX = 0; iX < nXValid; iX++ )
    1057             :                  {
    1058             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1059             :                  }
    1060             :              }
    1061             :          }
    1062             :      }
    1063             :  }
    1064             : \endcode
    1065             :  *
    1066             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1067             :  * the left most block, 1 the next block and so forth.
    1068             :  *
    1069             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1070             :  * the top most block, 1 the next block and so forth.
    1071             :  *
    1072             :  * @param pImage the buffer into which the data will be read.  The buffer
    1073             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1074             :  * of type GetRasterDataType().
    1075             :  *
    1076             :  * @return CE_None on success or CE_Failure on an error.
    1077             :  */
    1078             : 
    1079         894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1080             : 
    1081             : {
    1082             :     /* -------------------------------------------------------------------- */
    1083             :     /*      Validate arguments.                                             */
    1084             :     /* -------------------------------------------------------------------- */
    1085         894 :     CPLAssert(pImage != nullptr);
    1086             : 
    1087         894 :     if (!InitBlockInfo())
    1088           0 :         return CE_Failure;
    1089             : 
    1090         894 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1091             :     {
    1092           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1093             :                     "Illegal nXBlockOff value (%d) in "
    1094             :                     "GDALRasterBand::ReadBlock()\n",
    1095             :                     nXBlockOff);
    1096             : 
    1097           0 :         return (CE_Failure);
    1098             :     }
    1099             : 
    1100         894 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1101             :     {
    1102           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1103             :                     "Illegal nYBlockOff value (%d) in "
    1104             :                     "GDALRasterBand::ReadBlock()\n",
    1105             :                     nYBlockOff);
    1106             : 
    1107           0 :         return (CE_Failure);
    1108             :     }
    1109             : 
    1110             :     /* -------------------------------------------------------------------- */
    1111             :     /*      Invoke underlying implementation method.                        */
    1112             :     /* -------------------------------------------------------------------- */
    1113             : 
    1114         894 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1115         894 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1116         894 :     if (bCallLeaveReadWrite)
    1117           4 :         LeaveReadWrite();
    1118         894 :     return eErr;
    1119             : }
    1120             : 
    1121             : /************************************************************************/
    1122             : /*                           GDALReadBlock()                            */
    1123             : /************************************************************************/
    1124             : 
    1125             : /**
    1126             :  * \brief Read a block of image data efficiently.
    1127             :  *
    1128             :  * @see GDALRasterBand::ReadBlock()
    1129             :  */
    1130             : 
    1131          77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1132             :                                  void *pData)
    1133             : 
    1134             : {
    1135          77 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1136             : 
    1137          77 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1138          77 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1139             : }
    1140             : 
    1141             : /************************************************************************/
    1142             : /*                             IReadBlock()                             */
    1143             : /************************************************************************/
    1144             : 
    1145             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1146             :  * ) \brief Read a block of data.
    1147             :  *
    1148             :  * Default internal implementation ... to be overridden by
    1149             :  * subclasses that support reading.
    1150             :  * @param nBlockXOff Block X Offset
    1151             :  * @param nBlockYOff Block Y Offset
    1152             :  * @param pData Pixel buffer into which to place read data.
    1153             :  * @return CE_None on success or CE_Failure on an error.
    1154             :  */
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                            IWriteBlock()                             */
    1158             : /************************************************************************/
    1159             : 
    1160             : /**
    1161             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1162             :  * Write a block of data.
    1163             :  *
    1164             :  * Default internal implementation ... to be overridden by
    1165             :  * subclasses that support writing.
    1166             :  * @param nBlockXOff Block X Offset
    1167             :  * @param nBlockYOff Block Y Offset
    1168             :  * @param pData Pixel buffer to write
    1169             :  * @return CE_None on success or CE_Failure on an error.
    1170             :  */
    1171             : 
    1172             : /**/
    1173             : /**/
    1174             : 
    1175           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1176             :                                    void * /*pData*/)
    1177             : 
    1178             : {
    1179           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1180           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1181             :                     "WriteBlock() not supported for this dataset.");
    1182             : 
    1183           0 :     return (CE_Failure);
    1184             : }
    1185             : 
    1186             : /************************************************************************/
    1187             : /*                             WriteBlock()                             */
    1188             : /************************************************************************/
    1189             : 
    1190             : /**
    1191             :  * \brief Write a block of image data efficiently.
    1192             :  *
    1193             :  * This method accesses a "natural" block from the raster band without
    1194             :  * resampling, or data type conversion.  For a more generalized, but
    1195             :  * potentially less efficient access use RasterIO().
    1196             :  *
    1197             :  * This method is the same as the C GDALWriteBlock() function.
    1198             :  *
    1199             :  * See ReadBlock() for an example of block oriented data access.
    1200             :  *
    1201             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1202             :  * the left most block, 1 the next block and so forth.
    1203             :  *
    1204             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1205             :  * the left most block, 1 the next block and so forth.
    1206             :  *
    1207             :  * @param pImage the buffer from which the data will be written.  The buffer
    1208             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1209             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1210             :  * temporarily modified during the execution of this method (and eventually
    1211             :  * restored back to its original content), so it is not safe to use a buffer
    1212             :  * stored in a read-only section of the calling program.
    1213             :  *
    1214             :  * @return CE_None on success or CE_Failure on an error.
    1215             :  */
    1216             : 
    1217        4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1218             : 
    1219             : {
    1220             :     /* -------------------------------------------------------------------- */
    1221             :     /*      Validate arguments.                                             */
    1222             :     /* -------------------------------------------------------------------- */
    1223        4883 :     CPLAssert(pImage != nullptr);
    1224             : 
    1225        4883 :     if (!InitBlockInfo())
    1226           0 :         return CE_Failure;
    1227             : 
    1228        4883 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1229             :     {
    1230           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1231             :                     "Illegal nXBlockOff value (%d) in "
    1232             :                     "GDALRasterBand::WriteBlock()\n",
    1233             :                     nXBlockOff);
    1234             : 
    1235           0 :         return (CE_Failure);
    1236             :     }
    1237             : 
    1238        4883 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1239             :     {
    1240           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1241             :                     "Illegal nYBlockOff value (%d) in "
    1242             :                     "GDALRasterBand::WriteBlock()\n",
    1243             :                     nYBlockOff);
    1244             : 
    1245           0 :         return (CE_Failure);
    1246             :     }
    1247             : 
    1248        4883 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
    1249             :     {
    1250           0 :         return CE_Failure;
    1251             :     }
    1252             : 
    1253        4883 :     if (eFlushBlockErr != CE_None)
    1254             :     {
    1255           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1256             :                     "An error occurred while writing a dirty block "
    1257             :                     "from GDALRasterBand::WriteBlock");
    1258           0 :         CPLErr eErr = eFlushBlockErr;
    1259           0 :         eFlushBlockErr = CE_None;
    1260           0 :         return eErr;
    1261             :     }
    1262             : 
    1263             :     /* -------------------------------------------------------------------- */
    1264             :     /*      Invoke underlying implementation method.                        */
    1265             :     /* -------------------------------------------------------------------- */
    1266             : 
    1267        4883 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1268        4883 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1269        4883 :     if (bCallLeaveReadWrite)
    1270        4883 :         LeaveReadWrite();
    1271             : 
    1272        4883 :     return eErr;
    1273             : }
    1274             : 
    1275             : /************************************************************************/
    1276             : /*                           GDALWriteBlock()                           */
    1277             : /************************************************************************/
    1278             : 
    1279             : /**
    1280             :  * \brief Write a block of image data efficiently.
    1281             :  *
    1282             :  * @see GDALRasterBand::WriteBlock()
    1283             :  */
    1284             : 
    1285           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1286             :                                   void *pData)
    1287             : 
    1288             : {
    1289           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1290             : 
    1291           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1292           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1293             : }
    1294             : 
    1295             : /************************************************************************/
    1296             : /*                EmitErrorMessageIfWriteNotSupported()                 */
    1297             : /************************************************************************/
    1298             : 
    1299             : /**
    1300             :  * Emit an error message if a write operation to this band is not supported.
    1301             :  *
    1302             :  * The base implementation will emit an error message if the access mode is
    1303             :  * read-only. Derived classes may implement it to provide a custom message.
    1304             :  *
    1305             :  * @param pszCaller Calling function.
    1306             :  * @return true if an error message has been emitted.
    1307             :  */
    1308      641553 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
    1309             :     const char *pszCaller) const
    1310             : {
    1311      641553 :     if (eAccess == GA_ReadOnly)
    1312             :     {
    1313           4 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1314             :                     "%s: attempt to write to dataset opened in read-only mode.",
    1315             :                     pszCaller);
    1316             : 
    1317           4 :         return true;
    1318             :     }
    1319      641549 :     return false;
    1320             : }
    1321             : 
    1322             : /************************************************************************/
    1323             : /*                         GetActualBlockSize()                         */
    1324             : /************************************************************************/
    1325             : /**
    1326             :  * \brief Fetch the actual block size for a given block offset.
    1327             :  *
    1328             :  * Handles partial blocks at the edges of the raster and returns the true
    1329             :  * number of pixels
    1330             :  *
    1331             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1332             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1333             :  * block and so forth.
    1334             :  *
    1335             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1336             :  * the top most block, 1 the next block and so forth.
    1337             :  *
    1338             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1339             :  * the x direction will be stored
    1340             :  *
    1341             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1342             :  * the y direction will be stored
    1343             :  *
    1344             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1345             :  *
    1346             :  */
    1347       46538 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1348             :                                           int *pnXValid, int *pnYValid) const
    1349             : {
    1350       93075 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1351       93072 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1352       93068 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1353       46534 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1354             :     {
    1355           6 :         return CE_Failure;
    1356             :     }
    1357             : 
    1358       46532 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1359       46532 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1360             : 
    1361       46532 :     *pnXValid = nBlockXSize;
    1362       46532 :     *pnYValid = nBlockYSize;
    1363             : 
    1364       46532 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1365             :     {
    1366       44913 :         *pnXValid = nRasterXSize - nXPixelOff;
    1367             :     }
    1368             : 
    1369       46532 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1370             :     {
    1371        3566 :         *pnYValid = nRasterYSize - nYPixelOff;
    1372             :     }
    1373             : 
    1374       46532 :     return CE_None;
    1375             : }
    1376             : 
    1377             : /************************************************************************/
    1378             : /*                       GDALGetActualBlockSize()                       */
    1379             : /************************************************************************/
    1380             : 
    1381             : /**
    1382             :  * \brief Retrieve the actual block size for a given block offset.
    1383             :  *
    1384             :  * @see GDALRasterBand::GetActualBlockSize()
    1385             :  */
    1386             : 
    1387           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1388             :                                           int nYBlockOff, int *pnXValid,
    1389             :                                           int *pnYValid)
    1390             : 
    1391             : {
    1392           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1393             : 
    1394           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1395             :     return (
    1396           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1397             : }
    1398             : 
    1399             : /************************************************************************/
    1400             : /*                   GetSuggestedBlockAccessPattern()                   */
    1401             : /************************************************************************/
    1402             : 
    1403             : /**
    1404             :  * \brief Return the suggested/most efficient access pattern to blocks
    1405             :  *        (for read operations).
    1406             :  *
    1407             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1408             :  * efficient random access (GSBAP_RANDOM) to any block.
    1409             :  * Some drivers for example decompress sequentially a compressed stream from
    1410             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1411             :  * case best performance will be achieved while reading blocks in that order.
    1412             :  * (accessing blocks in random access in such rasters typically causes the
    1413             :  * decoding to be re-initialized from the start if accessing blocks in
    1414             :  * a non-sequential order)
    1415             :  *
    1416             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1417             :  * returned by drivers that expose a somewhat artificial block size, because
    1418             :  * they can extract any part of a raster, but in a rather inefficient way.
    1419             :  *
    1420             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1421             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1422             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1423             :  * most efficient strategy is to read as many pixels as possible in the less
    1424             :  * RasterIO() operations.
    1425             :  *
    1426             :  * The return of this method is for example used to determine the swath size
    1427             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1428             :  *
    1429             :  * @since GDAL 3.6
    1430             :  */
    1431             : 
    1432             : GDALSuggestedBlockAccessPattern
    1433        2437 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1434             : {
    1435        2437 :     return GSBAP_UNKNOWN;
    1436             : }
    1437             : 
    1438             : /************************************************************************/
    1439             : /*                         GetRasterDataType()                          */
    1440             : /************************************************************************/
    1441             : 
    1442             : /**
    1443             :  * \brief Fetch the pixel data type for this band.
    1444             :  *
    1445             :  * This method is the same as the C function GDALGetRasterDataType().
    1446             :  *
    1447             :  * @return the data type of pixels for this band.
    1448             :  */
    1449             : 
    1450     8985920 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1451             : 
    1452             : {
    1453     8985920 :     return eDataType;
    1454             : }
    1455             : 
    1456             : /************************************************************************/
    1457             : /*                       GDALGetRasterDataType()                        */
    1458             : /************************************************************************/
    1459             : 
    1460             : /**
    1461             :  * \brief Fetch the pixel data type for this band.
    1462             :  *
    1463             :  * @see GDALRasterBand::GetRasterDataType()
    1464             :  */
    1465             : 
    1466      910062 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1467             : 
    1468             : {
    1469      910062 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1470             : 
    1471      910062 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1472      910062 :     return poBand->GetRasterDataType();
    1473             : }
    1474             : 
    1475             : /************************************************************************/
    1476             : /*                            GetBlockSize()                            */
    1477             : /************************************************************************/
    1478             : 
    1479             : /**
    1480             :  * \brief Fetch the "natural" block size of this band.
    1481             :  *
    1482             :  * GDAL contains a concept of the natural block size of rasters so that
    1483             :  * applications can organized data access efficiently for some file formats.
    1484             :  * The natural block size is the block size that is most efficient for
    1485             :  * accessing the format.  For many formats this is simple a whole scanline
    1486             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1487             :  *
    1488             :  * However, for tiled images this will typically be the tile size.
    1489             :  *
    1490             :  * Note that the X and Y block sizes don't have to divide the image size
    1491             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1492             :  * See ReadBlock() for an example of code dealing with these issues.
    1493             :  *
    1494             :  * This method is the same as the C function GDALGetBlockSize().
    1495             :  *
    1496             :  * @param pnXSize integer to put the X block size into or NULL.
    1497             :  *
    1498             :  * @param pnYSize integer to put the Y block size into or NULL.
    1499             :  */
    1500             : 
    1501     5559770 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1502             : 
    1503             : {
    1504     5559770 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1505             :     {
    1506           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1507           0 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1508           0 :                     nBlockYSize);
    1509           0 :         if (pnXSize != nullptr)
    1510           0 :             *pnXSize = 0;
    1511           0 :         if (pnYSize != nullptr)
    1512           0 :             *pnYSize = 0;
    1513             :     }
    1514             :     else
    1515             :     {
    1516     5559770 :         if (pnXSize != nullptr)
    1517     5559770 :             *pnXSize = nBlockXSize;
    1518     5559770 :         if (pnYSize != nullptr)
    1519     5559770 :             *pnYSize = nBlockYSize;
    1520             :     }
    1521     5559770 : }
    1522             : 
    1523             : /************************************************************************/
    1524             : /*                          GDALGetBlockSize()                          */
    1525             : /************************************************************************/
    1526             : 
    1527             : /**
    1528             :  * \brief Fetch the "natural" block size of this band.
    1529             :  *
    1530             :  * @see GDALRasterBand::GetBlockSize()
    1531             :  */
    1532             : 
    1533       41261 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1534             :                                   int *pnYSize)
    1535             : 
    1536             : {
    1537       41261 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1538             : 
    1539       41261 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1540       41261 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1541             : }
    1542             : 
    1543             : /************************************************************************/
    1544             : /*                           InitBlockInfo()                            */
    1545             : /************************************************************************/
    1546             : 
    1547             : //! @cond Doxygen_Suppress
    1548     3656100 : int GDALRasterBand::InitBlockInfo()
    1549             : 
    1550             : {
    1551     3656100 :     if (poBandBlockCache != nullptr)
    1552     3415860 :         return poBandBlockCache->IsInitOK();
    1553             : 
    1554             :     /* Do some validation of raster and block dimensions in case the driver */
    1555             :     /* would have neglected to do it itself */
    1556      240241 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1557             :     {
    1558           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1559             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1560             :                     nBlockYSize);
    1561           0 :         return FALSE;
    1562             :     }
    1563             : 
    1564      240241 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1565             :     {
    1566           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1567             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1568             :                     nRasterYSize);
    1569           0 :         return FALSE;
    1570             :     }
    1571             : 
    1572      240241 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1573      240241 :     if (nDataTypeSize == 0)
    1574             :     {
    1575           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1576           0 :         return FALSE;
    1577             :     }
    1578             : 
    1579             : #if SIZEOF_VOIDP == 4
    1580             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1581             :     {
    1582             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1583             :          * multiplication in other cases */
    1584             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1585             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1586             :         {
    1587             :             ReportError(CE_Failure, CPLE_NotSupported,
    1588             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1589             :                         nBlockYSize);
    1590             :             return FALSE;
    1591             :         }
    1592             :     }
    1593             : #endif
    1594             : 
    1595      240241 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1596      240241 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1597             : 
    1598             :     const char *pszBlockStrategy =
    1599      240241 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1600      240241 :     bool bUseArray = true;
    1601      240241 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1602             :     {
    1603      240201 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1604             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1605             :         {
    1606      240182 :             GUIntBig nBlockCount =
    1607      240182 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1608      240182 :             if (poDS != nullptr)
    1609      239978 :                 nBlockCount *= poDS->GetRasterCount();
    1610      240182 :             bUseArray = (nBlockCount < 1024 * 1024);
    1611             :         }
    1612          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1613             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1614             :         {
    1615           0 :             bUseArray = false;
    1616      240201 :         }
    1617             :     }
    1618          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1619          40 :         bUseArray = false;
    1620           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1621           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1622             :                  pszBlockStrategy);
    1623             : 
    1624      240241 :     if (bUseArray)
    1625      240170 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1626             :     else
    1627             :     {
    1628          71 :         if (nBand == 1)
    1629          26 :             CPLDebug("GDAL", "Use hashset band block cache");
    1630          71 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1631             :     }
    1632      240241 :     if (poBandBlockCache == nullptr)
    1633           0 :         return FALSE;
    1634      240241 :     return poBandBlockCache->Init();
    1635             : }
    1636             : 
    1637             : //! @endcond
    1638             : 
    1639             : /************************************************************************/
    1640             : /*                             FlushCache()                             */
    1641             : /************************************************************************/
    1642             : 
    1643             : /**
    1644             :  * \brief Flush raster data cache.
    1645             :  *
    1646             :  * This call will recover memory used to cache data blocks for this raster
    1647             :  * band, and ensure that new requests are referred to the underlying driver.
    1648             :  *
    1649             :  * This method is the same as the C function GDALFlushRasterCache().
    1650             :  *
    1651             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1652             :  * @return CE_None on success.
    1653             :  */
    1654             : 
    1655     5673890 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1656             : 
    1657             : {
    1658     5793550 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1659      119661 :         poBandBlockCache)
    1660        4256 :         poBandBlockCache->DisableDirtyBlockWriting();
    1661             : 
    1662     5673890 :     CPLErr eGlobalErr = eFlushBlockErr;
    1663             : 
    1664     5673890 :     if (eFlushBlockErr != CE_None)
    1665             :     {
    1666           0 :         ReportError(
    1667             :             eFlushBlockErr, CPLE_AppDefined,
    1668             :             "An error occurred while writing a dirty block from FlushCache");
    1669           0 :         eFlushBlockErr = CE_None;
    1670             :     }
    1671             : 
    1672     5673890 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1673     4904220 :         return eGlobalErr;
    1674             : 
    1675      769667 :     return poBandBlockCache->FlushCache();
    1676             : }
    1677             : 
    1678             : /************************************************************************/
    1679             : /*                        GDALFlushRasterCache()                        */
    1680             : /************************************************************************/
    1681             : 
    1682             : /**
    1683             :  * \brief Flush raster data cache.
    1684             :  *
    1685             :  * @see GDALRasterBand::FlushCache()
    1686             :  */
    1687             : 
    1688         487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1689             : 
    1690             : {
    1691         487 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1692             : 
    1693         487 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1694             : }
    1695             : 
    1696             : /************************************************************************/
    1697             : /*                             DropCache()                              */
    1698             : /************************************************************************/
    1699             : 
    1700             : /**
    1701             : * \brief Drop raster data cache : data in cache will be lost.
    1702             : *
    1703             : * This call will recover memory used to cache data blocks for this raster
    1704             : * band, and ensure that new requests are referred to the underlying driver.
    1705             : *
    1706             : * This method is the same as the C function GDALDropRasterCache().
    1707             : *
    1708             : * @return CE_None on success.
    1709             : * @since 3.9
    1710             : */
    1711             : 
    1712           1 : CPLErr GDALRasterBand::DropCache()
    1713             : 
    1714             : {
    1715           1 :     CPLErr result = CE_None;
    1716             : 
    1717           1 :     if (poBandBlockCache)
    1718           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1719             : 
    1720           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1721             : 
    1722           1 :     if (eFlushBlockErr != CE_None)
    1723             :     {
    1724           0 :         ReportError(
    1725             :             eFlushBlockErr, CPLE_AppDefined,
    1726             :             "An error occurred while writing a dirty block from DropCache");
    1727           0 :         eFlushBlockErr = CE_None;
    1728             :     }
    1729             : 
    1730           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1731           0 :         result = eGlobalErr;
    1732             :     else
    1733           1 :         result = poBandBlockCache->FlushCache();
    1734             : 
    1735           1 :     if (poBandBlockCache)
    1736           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1737             : 
    1738           1 :     return result;
    1739             : }
    1740             : 
    1741             : /************************************************************************/
    1742             : /*                        GDALDropRasterCache()                         */
    1743             : /************************************************************************/
    1744             : 
    1745             : /**
    1746             : * \brief Drop raster data cache.
    1747             : *
    1748             : * @see GDALRasterBand::DropCache()
    1749             : * @since 3.9
    1750             : */
    1751             : 
    1752           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1753             : 
    1754             : {
    1755           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1756             : 
    1757           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1758             : }
    1759             : 
    1760             : /************************************************************************/
    1761             : /*                        UnreferenceBlock()                            */
    1762             : /*                                                                      */
    1763             : /*      Unreference the block from our array of blocks                  */
    1764             : /*      This method should only be called by                            */
    1765             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1766             : /*      the block cache mutex)                                          */
    1767             : /************************************************************************/
    1768             : 
    1769       29366 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1770             : {
    1771             : #ifdef notdef
    1772             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1773             :     {
    1774             :         if (poBandBlockCache == nullptr)
    1775             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1776             :         else
    1777             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1778             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1779             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1780             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1781             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1782             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1783             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1784             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1785             :         poBlock->DumpBlock();
    1786             :         if (GetDataset() != nullptr)
    1787             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1788             :         GDALRasterBlock::Verify();
    1789             :         abort();
    1790             :     }
    1791             : #endif
    1792       29366 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1793       29366 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1794             : }
    1795             : 
    1796             : /************************************************************************/
    1797             : /*                        AddBlockToFreeList()                          */
    1798             : /*                                                                      */
    1799             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1800             : /*      finished with a block about to be free'd, they pass it to that  */
    1801             : /*      method.                                                         */
    1802             : /************************************************************************/
    1803             : 
    1804             : //! @cond Doxygen_Suppress
    1805       29366 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1806             : {
    1807       29366 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1808       29366 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1809             : }
    1810             : 
    1811             : //! @endcond
    1812             : 
    1813             : /************************************************************************/
    1814             : /*                           HasDirtyBlocks()                           */
    1815             : /************************************************************************/
    1816             : 
    1817             : //! @cond Doxygen_Suppress
    1818          17 : bool GDALRasterBand::HasDirtyBlocks() const
    1819             : {
    1820          17 :     return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
    1821             : }
    1822             : 
    1823             : //! @endcond
    1824             : 
    1825             : /************************************************************************/
    1826             : /*                             FlushBlock()                             */
    1827             : /************************************************************************/
    1828             : 
    1829             : /** Flush a block out of the block cache.
    1830             :  * @param nXBlockOff block x offset
    1831             :  * @param nYBlockOff blocky offset
    1832             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1833             :  * @return CE_None in case of success, an error code otherwise.
    1834             :  */
    1835        2313 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1836             :                                   int bWriteDirtyBlock)
    1837             : 
    1838             : {
    1839        2313 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1840           0 :         return (CE_Failure);
    1841             : 
    1842             :     /* -------------------------------------------------------------------- */
    1843             :     /*      Validate the request                                            */
    1844             :     /* -------------------------------------------------------------------- */
    1845        2313 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1846             :     {
    1847           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1848             :                     "Illegal nBlockXOff value (%d) in "
    1849             :                     "GDALRasterBand::FlushBlock()\n",
    1850             :                     nXBlockOff);
    1851             : 
    1852           0 :         return (CE_Failure);
    1853             :     }
    1854             : 
    1855        2313 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1856             :     {
    1857           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1858             :                     "Illegal nBlockYOff value (%d) in "
    1859             :                     "GDALRasterBand::FlushBlock()\n",
    1860             :                     nYBlockOff);
    1861             : 
    1862           0 :         return (CE_Failure);
    1863             :     }
    1864             : 
    1865        2313 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1866        2313 :                                         bWriteDirtyBlock);
    1867             : }
    1868             : 
    1869             : /************************************************************************/
    1870             : /*                        TryGetLockedBlockRef()                        */
    1871             : /************************************************************************/
    1872             : 
    1873             : /**
    1874             :  * \brief Try fetching block ref.
    1875             :  *
    1876             :  * This method will returned the requested block (locked) if it is already
    1877             :  * in the block cache for the layer.  If not, nullptr is returned.
    1878             :  *
    1879             :  * If a non-NULL value is returned, then a lock for the block will have been
    1880             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1881             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1882             :  * severe problems may result.
    1883             :  *
    1884             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1885             :  * the left most block, 1 the next block and so forth.
    1886             :  *
    1887             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1888             :  * the top most block, 1 the next block and so forth.
    1889             :  *
    1890             :  * @return NULL if block not available, or locked block pointer.
    1891             :  */
    1892             : 
    1893    10655000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1894             :                                                       int nYBlockOff)
    1895             : 
    1896             : {
    1897    10655000 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1898      173225 :         return nullptr;
    1899             : 
    1900             :     /* -------------------------------------------------------------------- */
    1901             :     /*      Validate the request                                            */
    1902             :     /* -------------------------------------------------------------------- */
    1903    10481800 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1904             :     {
    1905           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1906             :                     "Illegal nBlockXOff value (%d) in "
    1907             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1908             :                     nXBlockOff);
    1909             : 
    1910           0 :         return (nullptr);
    1911             :     }
    1912             : 
    1913    10481800 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1914             :     {
    1915           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1916             :                     "Illegal nBlockYOff value (%d) in "
    1917             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1918             :                     nYBlockOff);
    1919             : 
    1920           0 :         return (nullptr);
    1921             :     }
    1922             : 
    1923    10481800 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1924             : }
    1925             : 
    1926             : /************************************************************************/
    1927             : /*                         GetLockedBlockRef()                          */
    1928             : /************************************************************************/
    1929             : 
    1930             : /**
    1931             :  * \brief Fetch a pointer to an internally cached raster block.
    1932             :  *
    1933             :  * This method will returned the requested block (locked) if it is already
    1934             :  * in the block cache for the layer.  If not, the block will be read from
    1935             :  * the driver, and placed in the layer block cached, then returned.  If an
    1936             :  * error occurs reading the block from the driver, a NULL value will be
    1937             :  * returned.
    1938             :  *
    1939             :  * If a non-NULL value is returned, then a lock for the block will have been
    1940             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1941             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1942             :  * severe problems may result.
    1943             :  *
    1944             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1945             :  * enable caching.
    1946             :  *
    1947             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1948             :  * the left most block, 1 the next block and so forth.
    1949             :  *
    1950             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1951             :  * the top most block, 1 the next block and so forth.
    1952             :  *
    1953             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1954             :  * but not actually read from the source.  This is useful when it will just
    1955             :  * be completely set and written back.
    1956             :  *
    1957             :  * @return pointer to the block object, or NULL on failure.
    1958             :  */
    1959             : 
    1960    10344800 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1961             :                                                    int nYBlockOff,
    1962             :                                                    int bJustInitialize)
    1963             : 
    1964             : {
    1965             :     /* -------------------------------------------------------------------- */
    1966             :     /*      Try and fetch from cache.                                       */
    1967             :     /* -------------------------------------------------------------------- */
    1968    10344800 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1969             : 
    1970             :     /* -------------------------------------------------------------------- */
    1971             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1972             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1973             :     /*      cache.                                                          */
    1974             :     /* -------------------------------------------------------------------- */
    1975    10344800 :     if (poBlock == nullptr)
    1976             :     {
    1977     3378080 :         if (!InitBlockInfo())
    1978           0 :             return (nullptr);
    1979             : 
    1980             :         /* --------------------------------------------------------------------
    1981             :          */
    1982             :         /*      Validate the request */
    1983             :         /* --------------------------------------------------------------------
    1984             :          */
    1985     3378080 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1986             :         {
    1987           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1988             :                         "Illegal nBlockXOff value (%d) in "
    1989             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1990             :                         nXBlockOff);
    1991             : 
    1992           0 :             return (nullptr);
    1993             :         }
    1994             : 
    1995     3378080 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1996             :         {
    1997           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1998             :                         "Illegal nBlockYOff value (%d) in "
    1999             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    2000             :                         nYBlockOff);
    2001             : 
    2002           0 :             return (nullptr);
    2003             :         }
    2004             : 
    2005     3378080 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    2006     3378080 :         if (poBlock == nullptr)
    2007           0 :             return nullptr;
    2008             : 
    2009     3378080 :         poBlock->AddLock();
    2010             : 
    2011             :         /* We need to temporarily drop the read-write lock in the following */
    2012             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    2013             :          */
    2014             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    2015             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    2016             :          */
    2017             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    2018             :          */
    2019             :         /* called and attempt at taking the lock on T2 (already taken).
    2020             :          * Similarly */
    2021             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    2022             :         /* But this may open the door to other problems... */
    2023     3378080 :         if (poDS)
    2024     3377340 :             poDS->TemporarilyDropReadWriteLock();
    2025             :         /* allocate data space */
    2026     3378080 :         CPLErr eErr = poBlock->Internalize();
    2027     3378080 :         if (poDS)
    2028     3377340 :             poDS->ReacquireReadWriteLock();
    2029     3378080 :         if (eErr != CE_None)
    2030             :         {
    2031           0 :             poBlock->DropLock();
    2032           0 :             delete poBlock;
    2033           0 :             return nullptr;
    2034             :         }
    2035             : 
    2036     3378080 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2037             :         {
    2038           0 :             poBlock->DropLock();
    2039           0 :             delete poBlock;
    2040           0 :             return nullptr;
    2041             :         }
    2042             : 
    2043     3378080 :         if (!bJustInitialize)
    2044             :         {
    2045     2889760 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2046     2889760 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2047     2889760 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2048     2889760 :             if (bCallLeaveReadWrite)
    2049      133342 :                 LeaveReadWrite();
    2050     2889760 :             if (eErr != CE_None)
    2051             :             {
    2052        1163 :                 poBlock->DropLock();
    2053        1163 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2054        1163 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2055             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2056             :                             nXBlockOff, nYBlockOff,
    2057        1163 :                             (nErrorCounter != CPLGetErrorCounter())
    2058        1161 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2059             :                                 : "");
    2060        1163 :                 return nullptr;
    2061             :             }
    2062             : 
    2063     2888590 :             nBlockReads++;
    2064     2888590 :             if (static_cast<GIntBig>(nBlockReads) ==
    2065     2888590 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2066         228 :                         1 &&
    2067         228 :                 nBand == 1 && poDS != nullptr)
    2068             :             {
    2069         168 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2070         168 :                          poDS->GetDescription());
    2071             :             }
    2072             :         }
    2073             :     }
    2074             : 
    2075    10343600 :     return poBlock;
    2076             : }
    2077             : 
    2078             : /************************************************************************/
    2079             : /*                                Fill()                                */
    2080             : /************************************************************************/
    2081             : 
    2082             : /**
    2083             :  * \brief Fill this band with a constant value.
    2084             :  *
    2085             :  * GDAL makes no guarantees
    2086             :  * about what values pixels in newly created files are set to, so this
    2087             :  * method can be used to clear a band to a specified "default" value.
    2088             :  * The fill value is passed in as a double but this will be converted
    2089             :  * to the underlying type before writing to the file. An optional
    2090             :  * second argument allows the imaginary component of a complex
    2091             :  * constant value to be specified.
    2092             :  *
    2093             :  * This method is the same as the C function GDALFillRaster().
    2094             :  *
    2095             :  * @param dfRealValue Real component of fill value
    2096             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2097             :  *
    2098             :  * @return CE_Failure if the write fails, otherwise CE_None
    2099             :  */
    2100      269807 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2101             : {
    2102             : 
    2103             :     // General approach is to construct a source block of the file's
    2104             :     // native type containing the appropriate value and then copy this
    2105             :     // to each block in the image via the RasterBlock cache. Using
    2106             :     // the cache means we avoid file I/O if it is not necessary, at the
    2107             :     // expense of some extra memcpy's (since we write to the
    2108             :     // RasterBlock cache, which is then at some point written to the
    2109             :     // underlying file, rather than simply directly to the underlying
    2110             :     // file.)
    2111             : 
    2112             :     // Check we can write to the file.
    2113      269807 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
    2114             :     {
    2115           6 :         return CE_Failure;
    2116             :     }
    2117             : 
    2118             :     // Make sure block parameters are set.
    2119      269801 :     if (!InitBlockInfo())
    2120           0 :         return CE_Failure;
    2121             : 
    2122             :     // Allocate the source block.
    2123      269801 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2124      269801 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2125      269801 :     auto blockByteSize = blockSize * elementSize;
    2126             :     unsigned char *srcBlock =
    2127      269801 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2128      269801 :     if (srcBlock == nullptr)
    2129             :     {
    2130           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2131             :                     "GDALRasterBand::Fill(): Out of memory "
    2132             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2133             :                     static_cast<GUIntBig>(blockByteSize));
    2134           0 :         return CE_Failure;
    2135             :     }
    2136             : 
    2137             :     // Initialize the source block.
    2138      269801 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2139      269801 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2140             :                     elementSize, blockSize);
    2141             : 
    2142      269801 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2143             : 
    2144             :     // Write block to block cache
    2145      875197 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2146             :     {
    2147     1505170 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2148             :         {
    2149      899770 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2150      899770 :             if (destBlock == nullptr)
    2151             :             {
    2152           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2153             :                             "GDALRasterBand::Fill(): Error "
    2154             :                             "while retrieving cache block.");
    2155           0 :                 VSIFree(srcBlock);
    2156           0 :                 return CE_Failure;
    2157             :             }
    2158      899770 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2159      899770 :             destBlock->MarkDirty();
    2160      899770 :             destBlock->DropLock();
    2161             :         }
    2162             :     }
    2163             : 
    2164      269801 :     if (bCallLeaveReadWrite)
    2165      267753 :         LeaveReadWrite();
    2166             : 
    2167             :     // Free up the source block
    2168      269801 :     VSIFree(srcBlock);
    2169             : 
    2170      269801 :     return CE_None;
    2171             : }
    2172             : 
    2173             : /************************************************************************/
    2174             : /*                           GDALFillRaster()                           */
    2175             : /************************************************************************/
    2176             : 
    2177             : /**
    2178             :  * \brief Fill this band with a constant value.
    2179             :  *
    2180             :  * @see GDALRasterBand::Fill()
    2181             :  */
    2182      269587 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2183             :                                   double dfImaginaryValue)
    2184             : {
    2185      269587 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2186             : 
    2187      269587 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2188      269587 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2189             : }
    2190             : 
    2191             : /************************************************************************/
    2192             : /*                             GetAccess()                              */
    2193             : /************************************************************************/
    2194             : 
    2195             : /**
    2196             :  * \brief Find out if we have update permission for this band.
    2197             :  *
    2198             :  * This method is the same as the C function GDALGetRasterAccess().
    2199             :  *
    2200             :  * @return Either GA_Update or GA_ReadOnly.
    2201             :  */
    2202             : 
    2203        3211 : GDALAccess GDALRasterBand::GetAccess()
    2204             : 
    2205             : {
    2206        3211 :     return eAccess;
    2207             : }
    2208             : 
    2209             : /************************************************************************/
    2210             : /*                        GDALGetRasterAccess()                         */
    2211             : /************************************************************************/
    2212             : 
    2213             : /**
    2214             :  * \brief Find out if we have update permission for this band.
    2215             :  *
    2216             :  * @see GDALRasterBand::GetAccess()
    2217             :  */
    2218             : 
    2219        2553 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2220             : 
    2221             : {
    2222        2553 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2223             : 
    2224        2553 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2225        2553 :     return poBand->GetAccess();
    2226             : }
    2227             : 
    2228             : /************************************************************************/
    2229             : /*                          GetCategoryNames()                          */
    2230             : /************************************************************************/
    2231             : 
    2232             : /**
    2233             :  * \brief Fetch the list of category names for this raster.
    2234             :  *
    2235             :  * The return list is a "StringList" in the sense of the CPL functions.
    2236             :  * That is a NULL terminated array of strings.  Raster values without
    2237             :  * associated names will have an empty string in the returned list.  The
    2238             :  * first entry in the list is for raster values of zero, and so on.
    2239             :  *
    2240             :  * The returned stringlist should not be altered or freed by the application.
    2241             :  * It may change on the next GDAL call, so please copy it if it is needed
    2242             :  * for any period of time.
    2243             :  *
    2244             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2245             :  *
    2246             :  * @return list of names, or NULL if none.
    2247             :  */
    2248             : 
    2249         262 : char **GDALRasterBand::GetCategoryNames()
    2250             : 
    2251             : {
    2252         262 :     return nullptr;
    2253             : }
    2254             : 
    2255             : /************************************************************************/
    2256             : /*                     GDALGetRasterCategoryNames()                     */
    2257             : /************************************************************************/
    2258             : 
    2259             : /**
    2260             :  * \brief Fetch the list of category names for this raster.
    2261             :  *
    2262             :  * @see GDALRasterBand::GetCategoryNames()
    2263             :  */
    2264             : 
    2265         207 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2266             : 
    2267             : {
    2268         207 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2269             : 
    2270         207 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2271         207 :     return poBand->GetCategoryNames();
    2272             : }
    2273             : 
    2274             : /************************************************************************/
    2275             : /*                          SetCategoryNames()                          */
    2276             : /************************************************************************/
    2277             : 
    2278             : /**
    2279             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2280             :  * \brief Set the category names for this band.
    2281             :  *
    2282             :  * See the GetCategoryNames() method for more on the interpretation of
    2283             :  * category names.
    2284             :  *
    2285             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2286             :  *
    2287             :  * @param papszNames the NULL terminated StringList of category names.  May
    2288             :  * be NULL to just clear the existing list.
    2289             :  *
    2290             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2291             :  * by the driver CE_Failure is returned, but no error message is reported.
    2292             :  */
    2293             : 
    2294             : /**/
    2295             : /**/
    2296             : 
    2297           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2298             : {
    2299           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2300           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2301             :                     "SetCategoryNames() not supported for this dataset.");
    2302             : 
    2303           0 :     return CE_Failure;
    2304             : }
    2305             : 
    2306             : /************************************************************************/
    2307             : /*                        GDALSetCategoryNames()                        */
    2308             : /************************************************************************/
    2309             : 
    2310             : /**
    2311             :  * \brief Set the category names for this band.
    2312             :  *
    2313             :  * @see GDALRasterBand::SetCategoryNames()
    2314             :  */
    2315             : 
    2316           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2317             :                                               CSLConstList papszNames)
    2318             : 
    2319             : {
    2320           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2321             : 
    2322           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2323           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2324             : }
    2325             : 
    2326             : /************************************************************************/
    2327             : /*                           GetNoDataValue()                           */
    2328             : /************************************************************************/
    2329             : 
    2330             : /**
    2331             :  * \brief Fetch the no data value for this band.
    2332             :  *
    2333             :  * If there is no out of data value, an out of range value will generally
    2334             :  * be returned.  The no data value for a band is generally a special marker
    2335             :  * value used to mark pixels that are not valid data.  Such pixels should
    2336             :  * generally not be displayed, nor contribute to analysis operations.
    2337             :  *
    2338             :  * The no data value returned is 'raw', meaning that it has no offset and
    2339             :  * scale applied.
    2340             :  *
    2341             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2342             :  * lossy if the nodata value cannot exactly been represented by a double.
    2343             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2344             :  *
    2345             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2346             :  *
    2347             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2348             :  * is actually associated with this layer.  May be NULL (default).
    2349             :  *
    2350             :  * @return the nodata value for this band.
    2351             :  */
    2352             : 
    2353       13170 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2354             : 
    2355             : {
    2356       13170 :     if (pbSuccess != nullptr)
    2357       13170 :         *pbSuccess = FALSE;
    2358             : 
    2359       13170 :     return -1e10;
    2360             : }
    2361             : 
    2362             : /************************************************************************/
    2363             : /*                      GDALGetRasterNoDataValue()                      */
    2364             : /************************************************************************/
    2365             : 
    2366             : /**
    2367             :  * \brief Fetch the no data value for this band.
    2368             :  *
    2369             :  * @see GDALRasterBand::GetNoDataValue()
    2370             :  */
    2371             : 
    2372      414938 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2373             :                                             int *pbSuccess)
    2374             : 
    2375             : {
    2376      414938 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2377             : 
    2378      414938 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2379      414938 :     return poBand->GetNoDataValue(pbSuccess);
    2380             : }
    2381             : 
    2382             : /************************************************************************/
    2383             : /*                       GetNoDataValueAsInt64()                        */
    2384             : /************************************************************************/
    2385             : 
    2386             : /**
    2387             :  * \brief Fetch the no data value for this band.
    2388             :  *
    2389             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2390             :  *
    2391             :  * If there is no out of data value, an out of range value will generally
    2392             :  * be returned.  The no data value for a band is generally a special marker
    2393             :  * value used to mark pixels that are not valid data.  Such pixels should
    2394             :  * generally not be displayed, nor contribute to analysis operations.
    2395             :  *
    2396             :  * The no data value returned is 'raw', meaning that it has no offset and
    2397             :  * scale applied.
    2398             :  *
    2399             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2400             :  *
    2401             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2402             :  * is actually associated with this layer.  May be NULL (default).
    2403             :  *
    2404             :  * @return the nodata value for this band.
    2405             :  *
    2406             :  * @since GDAL 3.5
    2407             :  */
    2408             : 
    2409           5 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2410             : 
    2411             : {
    2412           5 :     if (pbSuccess != nullptr)
    2413           5 :         *pbSuccess = FALSE;
    2414             : 
    2415           5 :     return std::numeric_limits<int64_t>::min();
    2416             : }
    2417             : 
    2418             : /************************************************************************/
    2419             : /*                  GDALGetRasterNoDataValueAsInt64()                   */
    2420             : /************************************************************************/
    2421             : 
    2422             : /**
    2423             :  * \brief Fetch the no data value for this band.
    2424             :  *
    2425             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2426             :  *
    2427             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2428             :  *
    2429             :  * @since GDAL 3.5
    2430             :  */
    2431             : 
    2432          31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2433             :                                                     int *pbSuccess)
    2434             : 
    2435             : {
    2436          31 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2437             :                       std::numeric_limits<int64_t>::min());
    2438             : 
    2439          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2440          31 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2441             : }
    2442             : 
    2443             : /************************************************************************/
    2444             : /*                       GetNoDataValueAsUInt64()                       */
    2445             : /************************************************************************/
    2446             : 
    2447             : /**
    2448             :  * \brief Fetch the no data value for this band.
    2449             :  *
    2450             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2451             :  *
    2452             :  * If there is no out of data value, an out of range value will generally
    2453             :  * be returned.  The no data value for a band is generally a special marker
    2454             :  * value used to mark pixels that are not valid data.  Such pixels should
    2455             :  * generally not be displayed, nor contribute to analysis operations.
    2456             :  *
    2457             :  * The no data value returned is 'raw', meaning that it has no offset and
    2458             :  * scale applied.
    2459             :  *
    2460             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2461             :  *
    2462             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2463             :  * is actually associated with this layer.  May be NULL (default).
    2464             :  *
    2465             :  * @return the nodata value for this band.
    2466             :  *
    2467             :  * @since GDAL 3.5
    2468             :  */
    2469             : 
    2470           4 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2471             : 
    2472             : {
    2473           4 :     if (pbSuccess != nullptr)
    2474           4 :         *pbSuccess = FALSE;
    2475             : 
    2476           4 :     return std::numeric_limits<uint64_t>::max();
    2477             : }
    2478             : 
    2479             : /************************************************************************/
    2480             : /*                  GDALGetRasterNoDataValueAsUInt64()                  */
    2481             : /************************************************************************/
    2482             : 
    2483             : /**
    2484             :  * \brief Fetch the no data value for this band.
    2485             :  *
    2486             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2487             :  *
    2488             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2489             :  *
    2490             :  * @since GDAL 3.5
    2491             :  */
    2492             : 
    2493          22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2494             :                                                       int *pbSuccess)
    2495             : 
    2496             : {
    2497          22 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2498             :                       std::numeric_limits<uint64_t>::max());
    2499             : 
    2500          22 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2501          22 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2502             : }
    2503             : 
    2504             : /************************************************************************/
    2505             : /*                       SetNoDataValueAsString()                       */
    2506             : /************************************************************************/
    2507             : 
    2508             : /**
    2509             :  * \brief Set the no data value for this band.
    2510             :  *
    2511             :  * Depending on drivers, changing the no data value may or may not have an
    2512             :  * effect on the pixel values of a raster that has just been created. It is
    2513             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2514             :  * the raster to the nodata value.
    2515             :  * In any case, changing an existing no data value, when one already exists and
    2516             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2517             :  * value matched the previous nodata value.
    2518             :  *
    2519             :  * To clear the nodata value, use DeleteNoDataValue().
    2520             :  *
    2521             :  * @param pszNoData the value to set.
    2522             :  * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
    2523             :  *             If the value cannot be exactly represented on the output data
    2524             :  *             type, *pbCannotBeExactlyRepresented will be set to true.
    2525             :  *
    2526             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2527             :  * by the driver, CE_Failure is returned but no error message will have
    2528             :  * been emitted.
    2529             :  *
    2530             :  * @since 3.11
    2531             :  */
    2532             : 
    2533             : CPLErr
    2534         126 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
    2535             :                                        bool *pbCannotBeExactlyRepresented)
    2536             : {
    2537         126 :     if (pbCannotBeExactlyRepresented)
    2538         126 :         *pbCannotBeExactlyRepresented = false;
    2539         126 :     if (eDataType == GDT_Int64)
    2540             :     {
    2541           8 :         if (strchr(pszNoData, '.') ||
    2542           3 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2543             :         {
    2544           2 :             char *endptr = nullptr;
    2545           2 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2546           4 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2547           2 :                 GDALIsValueExactAs<int64_t>(dfVal))
    2548             :             {
    2549           0 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
    2550             :             }
    2551             :         }
    2552             :         else
    2553             :         {
    2554             :             try
    2555             :             {
    2556           7 :                 const auto val = std::stoll(pszNoData);
    2557           1 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(val));
    2558             :             }
    2559           2 :             catch (const std::exception &)
    2560             :             {
    2561             :             }
    2562             :         }
    2563             :     }
    2564         121 :     else if (eDataType == GDT_UInt64)
    2565             :     {
    2566           2 :         if (strchr(pszNoData, '.') ||
    2567           1 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2568             :         {
    2569           0 :             char *endptr = nullptr;
    2570           0 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2571           0 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2572           0 :                 GDALIsValueExactAs<uint64_t>(dfVal))
    2573             :             {
    2574           0 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
    2575             :             }
    2576             :         }
    2577             :         else
    2578             :         {
    2579             :             try
    2580             :             {
    2581           1 :                 const auto val = std::stoull(pszNoData);
    2582           1 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
    2583             :             }
    2584           0 :             catch (const std::exception &)
    2585             :             {
    2586             :             }
    2587             :         }
    2588             :     }
    2589         120 :     else if (eDataType == GDT_Float32)
    2590             :     {
    2591          10 :         char *endptr = nullptr;
    2592          10 :         const float fVal = CPLStrtof(pszNoData, &endptr);
    2593          10 :         if (endptr == pszNoData + strlen(pszNoData))
    2594             :         {
    2595          10 :             return SetNoDataValue(double(fVal));
    2596             :         }
    2597             :     }
    2598             :     else
    2599             :     {
    2600         110 :         char *endptr = nullptr;
    2601         110 :         const double dfVal = CPLStrtod(pszNoData, &endptr);
    2602         220 :         if (endptr == pszNoData + strlen(pszNoData) &&
    2603         110 :             GDALIsValueExactAs(dfVal, eDataType))
    2604             :         {
    2605         109 :             return SetNoDataValue(dfVal);
    2606             :         }
    2607             :     }
    2608           5 :     if (pbCannotBeExactlyRepresented)
    2609           5 :         *pbCannotBeExactlyRepresented = true;
    2610           5 :     return CE_Failure;
    2611             : }
    2612             : 
    2613             : /************************************************************************/
    2614             : /*                           SetNoDataValue()                           */
    2615             : /************************************************************************/
    2616             : 
    2617             : /**
    2618             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2619             :  * \brief Set the no data value for this band.
    2620             :  *
    2621             :  * Depending on drivers, changing the no data value may or may not have an
    2622             :  * effect on the pixel values of a raster that has just been created. It is
    2623             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2624             :  * the raster to the nodata value.
    2625             :  * In any case, changing an existing no data value, when one already exists and
    2626             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2627             :  * value matched the previous nodata value.
    2628             :  *
    2629             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2630             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2631             :  * SetNoDataValueAsUInt64() instead.
    2632             :  *
    2633             :  * To clear the nodata value, use DeleteNoDataValue().
    2634             :  *
    2635             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2636             :  *
    2637             :  * @param dfNoData the value to set.
    2638             :  *
    2639             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2640             :  * by the driver, CE_Failure is returned but no error message will have
    2641             :  * been emitted.
    2642             :  */
    2643             : 
    2644             : /**/
    2645             : /**/
    2646             : 
    2647           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2648             : 
    2649             : {
    2650           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2651           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2652             :                     "SetNoDataValue() not supported for this dataset.");
    2653             : 
    2654           0 :     return CE_Failure;
    2655             : }
    2656             : 
    2657             : /************************************************************************/
    2658             : /*                      GDALSetRasterNoDataValue()                      */
    2659             : /************************************************************************/
    2660             : 
    2661             : /**
    2662             :  * \brief Set the no data value for this band.
    2663             :  *
    2664             :  * Depending on drivers, changing the no data value may or may not have an
    2665             :  * effect on the pixel values of a raster that has just been created. It is
    2666             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2667             :  * the raster to the nodata value.
    2668             :  * In any case, changing an existing no data value, when one already exists and
    2669             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2670             :  * value matched the previous nodata value.
    2671             :  *
    2672             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2673             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2674             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2675             :  *
    2676             :  * @see GDALRasterBand::SetNoDataValue()
    2677             :  */
    2678             : 
    2679        1146 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2680             :                                             double dfValue)
    2681             : 
    2682             : {
    2683        1146 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2684             : 
    2685        1146 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2686        1146 :     return poBand->SetNoDataValue(dfValue);
    2687             : }
    2688             : 
    2689             : /************************************************************************/
    2690             : /*                       SetNoDataValueAsInt64()                        */
    2691             : /************************************************************************/
    2692             : 
    2693             : /**
    2694             :  * \brief Set the no data value for this band.
    2695             :  *
    2696             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2697             :  *
    2698             :  * Depending on drivers, changing the no data value may or may not have an
    2699             :  * effect on the pixel values of a raster that has just been created. It is
    2700             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2701             :  * the raster to the nodata value.
    2702             :  * In ay case, changing an existing no data value, when one already exists and
    2703             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2704             :  * value matched the previous nodata value.
    2705             :  *
    2706             :  * To clear the nodata value, use DeleteNoDataValue().
    2707             :  *
    2708             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2709             :  *
    2710             :  * @param nNoDataValue the value to set.
    2711             :  *
    2712             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2713             :  * by the driver, CE_Failure is returned but no error message will have
    2714             :  * been emitted.
    2715             :  *
    2716             :  * @since GDAL 3.5
    2717             :  */
    2718             : 
    2719           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2720             : 
    2721             : {
    2722           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2723           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2724             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2725             : 
    2726           0 :     return CE_Failure;
    2727             : }
    2728             : 
    2729             : /************************************************************************/
    2730             : /*                  GDALSetRasterNoDataValueAsInt64()                   */
    2731             : /************************************************************************/
    2732             : 
    2733             : /**
    2734             :  * \brief Set the no data value for this band.
    2735             :  *
    2736             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2737             :  *
    2738             :  * Depending on drivers, changing the no data value may or may not have an
    2739             :  * effect on the pixel values of a raster that has just been created. It is
    2740             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2741             :  * the raster to the nodata value.
    2742             :  * In ay case, changing an existing no data value, when one already exists and
    2743             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2744             :  * value matched the previous nodata value.
    2745             :  *
    2746             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2747             :  *
    2748             :  * @since GDAL 3.5
    2749             :  */
    2750             : 
    2751          24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2752             :                                                    int64_t nValue)
    2753             : 
    2754             : {
    2755          24 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2756             : 
    2757          24 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2758          24 :     return poBand->SetNoDataValueAsInt64(nValue);
    2759             : }
    2760             : 
    2761             : /************************************************************************/
    2762             : /*                       SetNoDataValueAsUInt64()                       */
    2763             : /************************************************************************/
    2764             : 
    2765             : /**
    2766             :  * \brief Set the no data value for this band.
    2767             :  *
    2768             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2769             :  *
    2770             :  * Depending on drivers, changing the no data value may or may not have an
    2771             :  * effect on the pixel values of a raster that has just been created. It is
    2772             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2773             :  * the raster to the nodata value.
    2774             :  * In ay case, changing an existing no data value, when one already exists and
    2775             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2776             :  * value matched the previous nodata value.
    2777             :  *
    2778             :  * To clear the nodata value, use DeleteNoDataValue().
    2779             :  *
    2780             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2781             :  *
    2782             :  * @param nNoDataValue the value to set.
    2783             :  *
    2784             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2785             :  * by the driver, CE_Failure is returned but no error message will have
    2786             :  * been emitted.
    2787             :  *
    2788             :  * @since GDAL 3.5
    2789             :  */
    2790             : 
    2791           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2792             : 
    2793             : {
    2794           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2795           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2796             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2797             : 
    2798           0 :     return CE_Failure;
    2799             : }
    2800             : 
    2801             : /************************************************************************/
    2802             : /*                  GDALSetRasterNoDataValueAsUInt64()                  */
    2803             : /************************************************************************/
    2804             : 
    2805             : /**
    2806             :  * \brief Set the no data value for this band.
    2807             :  *
    2808             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2809             :  *
    2810             :  * Depending on drivers, changing the no data value may or may not have an
    2811             :  * effect on the pixel values of a raster that has just been created. It is
    2812             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2813             :  * the raster to the nodata value.
    2814             :  * In ay case, changing an existing no data value, when one already exists and
    2815             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2816             :  * value matched the previous nodata value.
    2817             :  *
    2818             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2819             :  *
    2820             :  * @since GDAL 3.5
    2821             :  */
    2822             : 
    2823          23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2824             :                                                     uint64_t nValue)
    2825             : 
    2826             : {
    2827          23 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2828             : 
    2829          23 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2830          23 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2831             : }
    2832             : 
    2833             : /************************************************************************/
    2834             : /*                         DeleteNoDataValue()                          */
    2835             : /************************************************************************/
    2836             : 
    2837             : /**
    2838             :  * \brief Remove the no data value for this band.
    2839             :  *
    2840             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2841             :  *
    2842             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2843             :  * by the driver, CE_Failure is returned but no error message will have
    2844             :  * been emitted.
    2845             :  *
    2846             :  */
    2847             : 
    2848           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2849             : 
    2850             : {
    2851           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2852           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2853             :                     "DeleteNoDataValue() not supported for this dataset.");
    2854             : 
    2855           0 :     return CE_Failure;
    2856             : }
    2857             : 
    2858             : /************************************************************************/
    2859             : /*                    GDALDeleteRasterNoDataValue()                     */
    2860             : /************************************************************************/
    2861             : 
    2862             : /**
    2863             :  * \brief Remove the no data value for this band.
    2864             :  *
    2865             :  * @see GDALRasterBand::DeleteNoDataValue()
    2866             :  *
    2867             :  */
    2868             : 
    2869          56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2870             : 
    2871             : {
    2872          56 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2873             : 
    2874          56 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2875          56 :     return poBand->DeleteNoDataValue();
    2876             : }
    2877             : 
    2878             : /************************************************************************/
    2879             : /*                             GetMaximum()                             */
    2880             : /************************************************************************/
    2881             : 
    2882             : /**
    2883             :  * \brief Fetch the maximum value for this band.
    2884             :  *
    2885             :  * For file formats that don't know this intrinsically, the maximum supported
    2886             :  * value for the data type will generally be returned.
    2887             :  *
    2888             :  * This method is the same as the C function GDALGetRasterMaximum().
    2889             :  *
    2890             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2891             :  * returned value is a tight maximum or not.  May be NULL (default).
    2892             :  *
    2893             :  * @return the maximum raster value (excluding no data pixels)
    2894             :  */
    2895             : 
    2896         544 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2897             : 
    2898             : {
    2899         544 :     const char *pszValue = nullptr;
    2900             : 
    2901         544 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2902             :     {
    2903          47 :         if (pbSuccess != nullptr)
    2904          42 :             *pbSuccess = TRUE;
    2905             : 
    2906          47 :         return CPLAtofM(pszValue);
    2907             :     }
    2908             : 
    2909         497 :     if (pbSuccess != nullptr)
    2910         493 :         *pbSuccess = FALSE;
    2911             : 
    2912         497 :     switch (eDataType)
    2913             :     {
    2914         341 :         case GDT_UInt8:
    2915             :         {
    2916         341 :             EnablePixelTypeSignedByteWarning(false);
    2917             :             const char *pszPixelType =
    2918         341 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2919         341 :             EnablePixelTypeSignedByteWarning(true);
    2920         341 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2921           0 :                 return 127;
    2922             : 
    2923         341 :             return 255;
    2924             :         }
    2925             : 
    2926           1 :         case GDT_Int8:
    2927           1 :             return 127;
    2928             : 
    2929          21 :         case GDT_UInt16:
    2930          21 :             return 65535;
    2931             : 
    2932          24 :         case GDT_Int16:
    2933             :         case GDT_CInt16:
    2934          24 :             return 32767;
    2935             : 
    2936          39 :         case GDT_Int32:
    2937             :         case GDT_CInt32:
    2938          39 :             return 2147483647.0;
    2939             : 
    2940          14 :         case GDT_UInt32:
    2941          14 :             return 4294967295.0;
    2942             : 
    2943           1 :         case GDT_Int64:
    2944           1 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2945             : 
    2946           1 :         case GDT_UInt64:
    2947           1 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2948             : 
    2949           0 :         case GDT_Float16:
    2950             :         case GDT_CFloat16:
    2951           0 :             return 65504.0;
    2952             : 
    2953          33 :         case GDT_Float32:
    2954             :         case GDT_CFloat32:
    2955          33 :             return 4294967295.0;  // Not actually accurate.
    2956             : 
    2957          22 :         case GDT_Float64:
    2958             :         case GDT_CFloat64:
    2959          22 :             return 4294967295.0;  // Not actually accurate.
    2960             : 
    2961           0 :         case GDT_Unknown:
    2962             :         case GDT_TypeCount:
    2963           0 :             break;
    2964             :     }
    2965           0 :     return 4294967295.0;  // Not actually accurate.
    2966             : }
    2967             : 
    2968             : /************************************************************************/
    2969             : /*                        GDALGetRasterMaximum()                        */
    2970             : /************************************************************************/
    2971             : 
    2972             : /**
    2973             :  * \brief Fetch the maximum value for this band.
    2974             :  *
    2975             :  * @see GDALRasterBand::GetMaximum()
    2976             :  */
    2977             : 
    2978         346 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2979             : 
    2980             : {
    2981         346 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2982             : 
    2983         346 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2984         346 :     return poBand->GetMaximum(pbSuccess);
    2985             : }
    2986             : 
    2987             : /************************************************************************/
    2988             : /*                             GetMinimum()                             */
    2989             : /************************************************************************/
    2990             : 
    2991             : /**
    2992             :  * \brief Fetch the minimum value for this band.
    2993             :  *
    2994             :  * For file formats that don't know this intrinsically, the minimum supported
    2995             :  * value for the data type will generally be returned.
    2996             :  *
    2997             :  * This method is the same as the C function GDALGetRasterMinimum().
    2998             :  *
    2999             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3000             :  * returned value is a tight minimum or not.  May be NULL (default).
    3001             :  *
    3002             :  * @return the minimum raster value (excluding no data pixels)
    3003             :  */
    3004             : 
    3005         552 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    3006             : 
    3007             : {
    3008         552 :     const char *pszValue = nullptr;
    3009             : 
    3010         552 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    3011             :     {
    3012          52 :         if (pbSuccess != nullptr)
    3013          47 :             *pbSuccess = TRUE;
    3014             : 
    3015          52 :         return CPLAtofM(pszValue);
    3016             :     }
    3017             : 
    3018         500 :     if (pbSuccess != nullptr)
    3019         496 :         *pbSuccess = FALSE;
    3020             : 
    3021         500 :     switch (eDataType)
    3022             :     {
    3023         344 :         case GDT_UInt8:
    3024             :         {
    3025         344 :             EnablePixelTypeSignedByteWarning(false);
    3026             :             const char *pszPixelType =
    3027         344 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    3028         344 :             EnablePixelTypeSignedByteWarning(true);
    3029         344 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    3030           0 :                 return -128;
    3031             : 
    3032         344 :             return 0;
    3033             :         }
    3034             : 
    3035           1 :         case GDT_Int8:
    3036           1 :             return -128;
    3037             : 
    3038          21 :         case GDT_UInt16:
    3039          21 :             return 0;
    3040             : 
    3041          24 :         case GDT_Int16:
    3042             :         case GDT_CInt16:
    3043          24 :             return -32768;
    3044             : 
    3045          39 :         case GDT_Int32:
    3046             :         case GDT_CInt32:
    3047          39 :             return -2147483648.0;
    3048             : 
    3049          14 :         case GDT_UInt32:
    3050          14 :             return 0;
    3051             : 
    3052           1 :         case GDT_Int64:
    3053           1 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    3054             : 
    3055           1 :         case GDT_UInt64:
    3056           1 :             return 0;
    3057             : 
    3058           0 :         case GDT_Float16:
    3059             :         case GDT_CFloat16:
    3060           0 :             return -65504.0;
    3061             : 
    3062          33 :         case GDT_Float32:
    3063             :         case GDT_CFloat32:
    3064          33 :             return -4294967295.0;  // Not actually accurate.
    3065             : 
    3066          22 :         case GDT_Float64:
    3067             :         case GDT_CFloat64:
    3068          22 :             return -4294967295.0;  // Not actually accurate.
    3069             : 
    3070           0 :         case GDT_Unknown:
    3071             :         case GDT_TypeCount:
    3072           0 :             break;
    3073             :     }
    3074           0 :     return -4294967295.0;  // Not actually accurate.
    3075             : }
    3076             : 
    3077             : /************************************************************************/
    3078             : /*                        GDALGetRasterMinimum()                        */
    3079             : /************************************************************************/
    3080             : 
    3081             : /**
    3082             :  * \brief Fetch the minimum value for this band.
    3083             :  *
    3084             :  * @see GDALRasterBand::GetMinimum()
    3085             :  */
    3086             : 
    3087         356 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    3088             : 
    3089             : {
    3090         356 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    3091             : 
    3092         356 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3093         356 :     return poBand->GetMinimum(pbSuccess);
    3094             : }
    3095             : 
    3096             : /************************************************************************/
    3097             : /*                       GetColorInterpretation()                       */
    3098             : /************************************************************************/
    3099             : 
    3100             : /**
    3101             :  * \brief How should this band be interpreted as color?
    3102             :  *
    3103             :  * GCI_Undefined is returned when the format doesn't know anything
    3104             :  * about the color interpretation.
    3105             :  *
    3106             :  * This method is the same as the C function
    3107             :  * GDALGetRasterColorInterpretation().
    3108             :  *
    3109             :  * @return color interpretation value for band.
    3110             :  */
    3111             : 
    3112         163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    3113             : 
    3114             : {
    3115         163 :     return GCI_Undefined;
    3116             : }
    3117             : 
    3118             : /************************************************************************/
    3119             : /*                  GDALGetRasterColorInterpretation()                  */
    3120             : /************************************************************************/
    3121             : 
    3122             : /**
    3123             :  * \brief How should this band be interpreted as color?
    3124             :  *
    3125             :  * @see GDALRasterBand::GetColorInterpretation()
    3126             :  */
    3127             : 
    3128             : GDALColorInterp CPL_STDCALL
    3129        6172 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    3130             : 
    3131             : {
    3132        6172 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    3133             : 
    3134        6172 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3135        6172 :     return poBand->GetColorInterpretation();
    3136             : }
    3137             : 
    3138             : /************************************************************************/
    3139             : /*                       SetColorInterpretation()                       */
    3140             : /************************************************************************/
    3141             : 
    3142             : /**
    3143             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3144             :  * \brief Set color interpretation of a band.
    3145             :  *
    3146             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3147             :  *
    3148             :  * @param eColorInterp the new color interpretation to apply to this band.
    3149             :  *
    3150             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3151             :  */
    3152             : 
    3153             : /**/
    3154             : /**/
    3155             : 
    3156           1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3157             : 
    3158             : {
    3159           1 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3160           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    3161             :                     "SetColorInterpretation() not supported for this dataset.");
    3162           1 :     return CE_Failure;
    3163             : }
    3164             : 
    3165             : /************************************************************************/
    3166             : /*                  GDALSetRasterColorInterpretation()                  */
    3167             : /************************************************************************/
    3168             : 
    3169             : /**
    3170             :  * \brief Set color interpretation of a band.
    3171             :  *
    3172             :  * @see GDALRasterBand::SetColorInterpretation()
    3173             :  */
    3174             : 
    3175        1864 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3176             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3177             : 
    3178             : {
    3179        1864 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3180             : 
    3181        1864 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3182        1864 :     return poBand->SetColorInterpretation(eColorInterp);
    3183             : }
    3184             : 
    3185             : /************************************************************************/
    3186             : /*                           GetColorTable()                            */
    3187             : /************************************************************************/
    3188             : 
    3189             : /**
    3190             :  * \brief Fetch the color table associated with band.
    3191             :  *
    3192             :  * If there is no associated color table, the return result is NULL.  The
    3193             :  * returned color table remains owned by the GDALRasterBand, and can't
    3194             :  * be depended on for long, nor should it ever be modified by the caller.
    3195             :  *
    3196             :  * This method is the same as the C function GDALGetRasterColorTable().
    3197             :  *
    3198             :  * @return internal color table, or NULL.
    3199             :  */
    3200             : 
    3201         215 : GDALColorTable *GDALRasterBand::GetColorTable()
    3202             : 
    3203             : {
    3204         215 :     return nullptr;
    3205             : }
    3206             : 
    3207             : /************************************************************************/
    3208             : /*                      GDALGetRasterColorTable()                       */
    3209             : /************************************************************************/
    3210             : 
    3211             : /**
    3212             :  * \brief Fetch the color table associated with band.
    3213             :  *
    3214             :  * @see GDALRasterBand::GetColorTable()
    3215             :  */
    3216             : 
    3217        2119 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3218             : 
    3219             : {
    3220        2119 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3221             : 
    3222        2119 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3223        2119 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3224             : }
    3225             : 
    3226             : /************************************************************************/
    3227             : /*                           SetColorTable()                            */
    3228             : /************************************************************************/
    3229             : 
    3230             : /**
    3231             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3232             :  * \brief Set the raster color table.
    3233             :  *
    3234             :  * The driver will make a copy of all desired data in the colortable.  It
    3235             :  * remains owned by the caller after the call.
    3236             :  *
    3237             :  * This method is the same as the C function GDALSetRasterColorTable().
    3238             :  *
    3239             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3240             :  * table (where supported).
    3241             :  *
    3242             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3243             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3244             :  * error is issued.
    3245             :  */
    3246             : 
    3247             : /**/
    3248             : /**/
    3249             : 
    3250           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3251             : 
    3252             : {
    3253           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3254           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3255             :                     "SetColorTable() not supported for this dataset.");
    3256           0 :     return CE_Failure;
    3257             : }
    3258             : 
    3259             : /************************************************************************/
    3260             : /*                      GDALSetRasterColorTable()                       */
    3261             : /************************************************************************/
    3262             : 
    3263             : /**
    3264             :  * \brief Set the raster color table.
    3265             :  *
    3266             :  * @see GDALRasterBand::SetColorTable()
    3267             :  */
    3268             : 
    3269          84 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3270             :                                            GDALColorTableH hCT)
    3271             : 
    3272             : {
    3273          84 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3274             : 
    3275          84 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3276          84 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3277             : }
    3278             : 
    3279             : /************************************************************************/
    3280             : /*                       HasArbitraryOverviews()                        */
    3281             : /************************************************************************/
    3282             : 
    3283             : /**
    3284             :  * \brief Check for arbitrary overviews.
    3285             :  *
    3286             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3287             :  * overviews efficiently, such as is the case with OGDI over a network.
    3288             :  * Datastores with arbitrary overviews don't generally have any fixed
    3289             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3290             :  * to get overview data efficiently.
    3291             :  *
    3292             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3293             :  *
    3294             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3295             :  * FALSE.
    3296             :  */
    3297             : 
    3298         276 : int GDALRasterBand::HasArbitraryOverviews()
    3299             : 
    3300             : {
    3301         276 :     return FALSE;
    3302             : }
    3303             : 
    3304             : /************************************************************************/
    3305             : /*                     GDALHasArbitraryOverviews()                      */
    3306             : /************************************************************************/
    3307             : 
    3308             : /**
    3309             :  * \brief Check for arbitrary overviews.
    3310             :  *
    3311             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3312             :  */
    3313             : 
    3314         197 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3315             : 
    3316             : {
    3317         197 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3318             : 
    3319         197 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3320         197 :     return poBand->HasArbitraryOverviews();
    3321             : }
    3322             : 
    3323             : /************************************************************************/
    3324             : /*                          GetOverviewCount()                          */
    3325             : /************************************************************************/
    3326             : 
    3327             : /**
    3328             :  * \brief Return the number of overview layers available.
    3329             :  *
    3330             :  * This method is the same as the C function GDALGetOverviewCount().
    3331             :  *
    3332             :  * @return overview count, zero if none.
    3333             :  */
    3334             : 
    3335     1066710 : int GDALRasterBand::GetOverviewCount()
    3336             : 
    3337             : {
    3338     1723640 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3339      656924 :         poDS->AreOverviewsEnabled())
    3340      656924 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3341             : 
    3342      409790 :     return 0;
    3343             : }
    3344             : 
    3345             : /************************************************************************/
    3346             : /*                        GDALGetOverviewCount()                        */
    3347             : /************************************************************************/
    3348             : 
    3349             : /**
    3350             :  * \brief Return the number of overview layers available.
    3351             :  *
    3352             :  * @see GDALRasterBand::GetOverviewCount()
    3353             :  */
    3354             : 
    3355        3316 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3356             : 
    3357             : {
    3358        3316 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3359             : 
    3360        3316 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3361        3316 :     return poBand->GetOverviewCount();
    3362             : }
    3363             : 
    3364             : /************************************************************************/
    3365             : /*                            GetOverview()                             */
    3366             : /************************************************************************/
    3367             : 
    3368             : /**
    3369             :  * \brief Fetch overview raster band object.
    3370             :  *
    3371             :  * This method is the same as the C function GDALGetOverview().
    3372             :  *
    3373             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3374             :  *
    3375             :  * @return overview GDALRasterBand.
    3376             :  */
    3377             : 
    3378         943 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3379             : 
    3380             : {
    3381        1734 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3382         791 :         poDS->AreOverviewsEnabled())
    3383         791 :         return poDS->oOvManager.GetOverview(nBand, i);
    3384             : 
    3385         152 :     return nullptr;
    3386             : }
    3387             : 
    3388             : /************************************************************************/
    3389             : /*                          GDALGetOverview()                           */
    3390             : /************************************************************************/
    3391             : 
    3392             : /**
    3393             :  * \brief Fetch overview raster band object.
    3394             :  *
    3395             :  * @see GDALRasterBand::GetOverview()
    3396             :  */
    3397             : 
    3398        5666 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3399             : 
    3400             : {
    3401        5666 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3402             : 
    3403        5666 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3404        5666 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3405             : }
    3406             : 
    3407             : /************************************************************************/
    3408             : /*                      GetRasterSampleOverview()                       */
    3409             : /************************************************************************/
    3410             : 
    3411             : /**
    3412             :  * \brief Fetch best sampling overview.
    3413             :  *
    3414             :  * Returns the most reduced overview of the given band that still satisfies
    3415             :  * the desired number of samples.  This function can be used with zero
    3416             :  * as the number of desired samples to fetch the most reduced overview.
    3417             :  * The same band as was passed in will be returned if it has not overviews,
    3418             :  * or if none of the overviews have enough samples.
    3419             :  *
    3420             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3421             :  * and GDALGetRasterSampleOverviewEx().
    3422             :  *
    3423             :  * @param nDesiredSamples the returned band will have at least this many
    3424             :  * pixels.
    3425             :  *
    3426             :  * @return optimal overview or the band itself.
    3427             :  */
    3428             : 
    3429             : GDALRasterBand *
    3430        2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3431             : 
    3432             : {
    3433        2009 :     GDALRasterBand *poBestBand = this;
    3434             : 
    3435        2009 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3436             : 
    3437        4029 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3438             :     {
    3439        2020 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3440             : 
    3441        2020 :         if (poOBand == nullptr)
    3442           0 :             continue;
    3443             : 
    3444             :         const double dfOSamples =
    3445        2020 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3446             : 
    3447        2020 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3448             :         {
    3449        2017 :             dfBestSamples = dfOSamples;
    3450        2017 :             poBestBand = poOBand;
    3451             :         }
    3452             :     }
    3453             : 
    3454        2009 :     return poBestBand;
    3455             : }
    3456             : 
    3457             : /************************************************************************/
    3458             : /*                    GDALGetRasterSampleOverview()                     */
    3459             : /************************************************************************/
    3460             : 
    3461             : /**
    3462             :  * \brief Fetch best sampling overview.
    3463             :  *
    3464             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3465             :  * billion samples.
    3466             :  *
    3467             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3468             :  * @see GDALGetRasterSampleOverviewEx()
    3469             :  */
    3470             : 
    3471           0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3472             :                                                         int nDesiredSamples)
    3473             : 
    3474             : {
    3475           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3476             : 
    3477           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3478           0 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3479           0 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3480             : }
    3481             : 
    3482             : /************************************************************************/
    3483             : /*                   GDALGetRasterSampleOverviewEx()                    */
    3484             : /************************************************************************/
    3485             : 
    3486             : /**
    3487             :  * \brief Fetch best sampling overview.
    3488             :  *
    3489             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3490             :  */
    3491             : 
    3492             : GDALRasterBandH CPL_STDCALL
    3493        2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3494             : 
    3495             : {
    3496        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3497             : 
    3498        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3499        2000 :     return GDALRasterBand::ToHandle(
    3500        4000 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3501             : }
    3502             : 
    3503             : /************************************************************************/
    3504             : /*                           BuildOverviews()                           */
    3505             : /************************************************************************/
    3506             : 
    3507             : /**
    3508             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3509             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3510             :  *
    3511             :  * If the operation is unsupported for the indicated dataset, then
    3512             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3513             :  * CPLE_NotSupported.
    3514             :  *
    3515             :  * WARNING: Most formats don't support per-band overview computation, but
    3516             :  * require that overviews are computed for all bands of a dataset, using
    3517             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3518             :  * is the HFA driver which supports this method.
    3519             :  *
    3520             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3521             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3522             :  * applied.
    3523             :  * @param nOverviews number of overviews to build.
    3524             :  * @param panOverviewList the list of overview decimation factors to build.
    3525             :  * @param pfnProgress a function to call to report progress, or NULL.
    3526             :  * @param pProgressData application data to pass to the progress function.
    3527             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3528             :  *                     key=value pairs, or NULL
    3529             :  *
    3530             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3531             :  */
    3532             : 
    3533             : /**/
    3534             : /**/
    3535             : 
    3536           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3537             :                                       int /*nOverviews*/,
    3538             :                                       const int * /*panOverviewList*/,
    3539             :                                       GDALProgressFunc /*pfnProgress*/,
    3540             :                                       void * /*pProgressData*/,
    3541             :                                       CSLConstList /* papszOptions */)
    3542             : 
    3543             : {
    3544           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3545             :                 "BuildOverviews() not supported for this dataset.");
    3546             : 
    3547           0 :     return (CE_Failure);
    3548             : }
    3549             : 
    3550             : /************************************************************************/
    3551             : /*                             GetOffset()                              */
    3552             : /************************************************************************/
    3553             : 
    3554             : /**
    3555             :  * \brief Fetch the raster value offset.
    3556             :  *
    3557             :  * This value (in combination with the GetScale() value) can be used to
    3558             :  * transform raw pixel values into the units returned by GetUnitType().
    3559             :  * For example this might be used to store elevations in GUInt16 bands
    3560             :  * with a precision of 0.1, and starting from -100.
    3561             :  *
    3562             :  * Units value = (raw value * scale) + offset
    3563             :  *
    3564             :  * Note that applying scale and offset is of the responsibility of the user,
    3565             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3566             :  *
    3567             :  * For file formats that don't know this intrinsically a value of zero
    3568             :  * is returned.
    3569             :  *
    3570             :  * This method is the same as the C function GDALGetRasterOffset().
    3571             :  *
    3572             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3573             :  * returned value is meaningful or not.  May be NULL (default).
    3574             :  *
    3575             :  * @return the raster offset.
    3576             :  */
    3577             : 
    3578         445 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3579             : 
    3580             : {
    3581         445 :     if (pbSuccess != nullptr)
    3582         336 :         *pbSuccess = FALSE;
    3583             : 
    3584         445 :     return 0.0;
    3585             : }
    3586             : 
    3587             : /************************************************************************/
    3588             : /*                        GDALGetRasterOffset()                         */
    3589             : /************************************************************************/
    3590             : 
    3591             : /**
    3592             :  * \brief Fetch the raster value offset.
    3593             :  *
    3594             :  * @see GDALRasterBand::GetOffset()
    3595             :  */
    3596             : 
    3597         402 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3598             : 
    3599             : {
    3600         402 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3601             : 
    3602         402 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3603         402 :     return poBand->GetOffset(pbSuccess);
    3604             : }
    3605             : 
    3606             : /************************************************************************/
    3607             : /*                             SetOffset()                              */
    3608             : /************************************************************************/
    3609             : 
    3610             : /**
    3611             :  * \fn GDALRasterBand::SetOffset(double)
    3612             :  * \brief Set scaling offset.
    3613             :  *
    3614             :  * Very few formats implement this method.   When not implemented it will
    3615             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3616             :  *
    3617             :  * This method is the same as the C function GDALSetRasterOffset().
    3618             :  *
    3619             :  * @param dfNewOffset the new offset.
    3620             :  *
    3621             :  * @return CE_None or success or CE_Failure on failure.
    3622             :  */
    3623             : 
    3624             : /**/
    3625             : /**/
    3626             : 
    3627           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3628             : {
    3629           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3630           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3631             :                     "SetOffset() not supported on this raster band.");
    3632             : 
    3633           0 :     return CE_Failure;
    3634             : }
    3635             : 
    3636             : /************************************************************************/
    3637             : /*                        GDALSetRasterOffset()                         */
    3638             : /************************************************************************/
    3639             : 
    3640             : /**
    3641             :  * \brief Set scaling offset.
    3642             :  *
    3643             :  * @see GDALRasterBand::SetOffset()
    3644             :  */
    3645             : 
    3646          86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3647             :                                        double dfNewOffset)
    3648             : 
    3649             : {
    3650          86 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3651             : 
    3652          86 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3653          86 :     return poBand->SetOffset(dfNewOffset);
    3654             : }
    3655             : 
    3656             : /************************************************************************/
    3657             : /*                              GetScale()                              */
    3658             : /************************************************************************/
    3659             : 
    3660             : /**
    3661             :  * \brief Fetch the raster value scale.
    3662             :  *
    3663             :  * This value (in combination with the GetOffset() value) can be used to
    3664             :  * transform raw pixel values into the units returned by GetUnitType().
    3665             :  * For example this might be used to store elevations in GUInt16 bands
    3666             :  * with a precision of 0.1, and starting from -100.
    3667             :  *
    3668             :  * Units value = (raw value * scale) + offset
    3669             :  *
    3670             :  * Note that applying scale and offset is of the responsibility of the user,
    3671             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3672             :  *
    3673             :  * For file formats that don't know this intrinsically a value of one
    3674             :  * is returned.
    3675             :  *
    3676             :  * This method is the same as the C function GDALGetRasterScale().
    3677             :  *
    3678             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3679             :  * returned value is meaningful or not.  May be NULL (default).
    3680             :  *
    3681             :  * @return the raster scale.
    3682             :  */
    3683             : 
    3684         445 : double GDALRasterBand::GetScale(int *pbSuccess)
    3685             : 
    3686             : {
    3687         445 :     if (pbSuccess != nullptr)
    3688         336 :         *pbSuccess = FALSE;
    3689             : 
    3690         445 :     return 1.0;
    3691             : }
    3692             : 
    3693             : /************************************************************************/
    3694             : /*                         GDALGetRasterScale()                         */
    3695             : /************************************************************************/
    3696             : 
    3697             : /**
    3698             :  * \brief Fetch the raster value scale.
    3699             :  *
    3700             :  * @see GDALRasterBand::GetScale()
    3701             :  */
    3702             : 
    3703         400 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3704             : 
    3705             : {
    3706         400 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3707             : 
    3708         400 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3709         400 :     return poBand->GetScale(pbSuccess);
    3710             : }
    3711             : 
    3712             : /************************************************************************/
    3713             : /*                              SetScale()                              */
    3714             : /************************************************************************/
    3715             : 
    3716             : /**
    3717             :  * \fn GDALRasterBand::SetScale(double)
    3718             :  * \brief Set scaling ratio.
    3719             :  *
    3720             :  * Very few formats implement this method.   When not implemented it will
    3721             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3722             :  *
    3723             :  * This method is the same as the C function GDALSetRasterScale().
    3724             :  *
    3725             :  * @param dfNewScale the new scale.
    3726             :  *
    3727             :  * @return CE_None or success or CE_Failure on failure.
    3728             :  */
    3729             : 
    3730             : /**/
    3731             : /**/
    3732             : 
    3733           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3734             : 
    3735             : {
    3736           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3737           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3738             :                     "SetScale() not supported on this raster band.");
    3739             : 
    3740           0 :     return CE_Failure;
    3741             : }
    3742             : 
    3743             : /************************************************************************/
    3744             : /*                         GDALSetRasterScale()                         */
    3745             : /************************************************************************/
    3746             : 
    3747             : /**
    3748             :  * \brief Set scaling ratio.
    3749             :  *
    3750             :  * @see GDALRasterBand::SetScale()
    3751             :  */
    3752             : 
    3753          87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3754             : 
    3755             : {
    3756          87 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3757             : 
    3758          87 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3759          87 :     return poBand->SetScale(dfNewOffset);
    3760             : }
    3761             : 
    3762             : /************************************************************************/
    3763             : /*                            GetUnitType()                             */
    3764             : /************************************************************************/
    3765             : 
    3766             : /**
    3767             :  * \brief Return raster unit type.
    3768             :  *
    3769             :  * Return a name for the units of this raster's values.  For instance, it
    3770             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3771             :  * units are available, a value of "" will be returned.  The returned string
    3772             :  * should not be modified, nor freed by the calling application.
    3773             :  *
    3774             :  * This method is the same as the C function GDALGetRasterUnitType().
    3775             :  *
    3776             :  * @return unit name string.
    3777             :  */
    3778             : 
    3779         165 : const char *GDALRasterBand::GetUnitType()
    3780             : 
    3781             : {
    3782         165 :     return "";
    3783             : }
    3784             : 
    3785             : /************************************************************************/
    3786             : /*                       GDALGetRasterUnitType()                        */
    3787             : /************************************************************************/
    3788             : 
    3789             : /**
    3790             :  * \brief Return raster unit type.
    3791             :  *
    3792             :  * @see GDALRasterBand::GetUnitType()
    3793             :  */
    3794             : 
    3795        1662 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3796             : 
    3797             : {
    3798        1662 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3799             : 
    3800        1662 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3801        1662 :     return poBand->GetUnitType();
    3802             : }
    3803             : 
    3804             : /************************************************************************/
    3805             : /*                            SetUnitType()                             */
    3806             : /************************************************************************/
    3807             : 
    3808             : /**
    3809             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3810             :  * \brief Set unit type.
    3811             :  *
    3812             :  * Set the unit type for a raster band.  Values should be one of
    3813             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3814             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3815             :  *
    3816             :  * This method is the same as the C function GDALSetRasterUnitType().
    3817             :  *
    3818             :  * @param pszNewValue the new unit type value.
    3819             :  *
    3820             :  * @return CE_None on success or CE_Failure if not successful, or
    3821             :  * unsupported.
    3822             :  */
    3823             : 
    3824             : /**/
    3825             : /**/
    3826             : 
    3827           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3828             : 
    3829             : {
    3830           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3831           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3832             :                     "SetUnitType() not supported on this raster band.");
    3833           0 :     return CE_Failure;
    3834             : }
    3835             : 
    3836             : /************************************************************************/
    3837             : /*                       GDALSetRasterUnitType()                        */
    3838             : /************************************************************************/
    3839             : 
    3840             : /**
    3841             :  * \brief Set unit type.
    3842             :  *
    3843             :  * @see GDALRasterBand::SetUnitType()
    3844             :  *
    3845             :  */
    3846             : 
    3847         100 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3848             :                                          const char *pszNewValue)
    3849             : 
    3850             : {
    3851         100 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3852             : 
    3853         100 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3854         100 :     return poBand->SetUnitType(pszNewValue);
    3855             : }
    3856             : 
    3857             : /************************************************************************/
    3858             : /*                              GetXSize()                              */
    3859             : /************************************************************************/
    3860             : 
    3861             : /**
    3862             :  * \brief Fetch XSize of raster.
    3863             :  *
    3864             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3865             :  *
    3866             :  * @return the width in pixels of this band.
    3867             :  */
    3868             : 
    3869     8475720 : int GDALRasterBand::GetXSize() const
    3870             : 
    3871             : {
    3872     8475720 :     return nRasterXSize;
    3873             : }
    3874             : 
    3875             : /************************************************************************/
    3876             : /*                       GDALGetRasterBandXSize()                       */
    3877             : /************************************************************************/
    3878             : 
    3879             : /**
    3880             :  * \brief Fetch XSize of raster.
    3881             :  *
    3882             :  * @see GDALRasterBand::GetXSize()
    3883             :  */
    3884             : 
    3885       58070 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3886             : 
    3887             : {
    3888       58070 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3889             : 
    3890       58070 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3891       58070 :     return poBand->GetXSize();
    3892             : }
    3893             : 
    3894             : /************************************************************************/
    3895             : /*                              GetYSize()                              */
    3896             : /************************************************************************/
    3897             : 
    3898             : /**
    3899             :  * \brief Fetch YSize of raster.
    3900             :  *
    3901             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3902             :  *
    3903             :  * @return the height in pixels of this band.
    3904             :  */
    3905             : 
    3906     4706730 : int GDALRasterBand::GetYSize() const
    3907             : 
    3908             : {
    3909     4706730 :     return nRasterYSize;
    3910             : }
    3911             : 
    3912             : /************************************************************************/
    3913             : /*                       GDALGetRasterBandYSize()                       */
    3914             : /************************************************************************/
    3915             : 
    3916             : /**
    3917             :  * \brief Fetch YSize of raster.
    3918             :  *
    3919             :  * @see GDALRasterBand::GetYSize()
    3920             :  */
    3921             : 
    3922       56933 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3923             : 
    3924             : {
    3925       56933 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3926             : 
    3927       56933 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3928       56933 :     return poBand->GetYSize();
    3929             : }
    3930             : 
    3931             : /************************************************************************/
    3932             : /*                              GetBand()                               */
    3933             : /************************************************************************/
    3934             : 
    3935             : /**
    3936             :  * \brief Fetch the band number.
    3937             :  *
    3938             :  * This method returns the band that this GDALRasterBand objects represents
    3939             :  * within its dataset.  This method may return a value of 0 to indicate
    3940             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3941             :  * such as GDALRasterBands serving as overviews.
    3942             :  *
    3943             :  * This method is the same as the C function GDALGetBandNumber().
    3944             :  *
    3945             :  * @return band number (1+) or 0 if the band number isn't known.
    3946             :  */
    3947             : 
    3948      151931 : int GDALRasterBand::GetBand() const
    3949             : 
    3950             : {
    3951      151931 :     return nBand;
    3952             : }
    3953             : 
    3954             : /************************************************************************/
    3955             : /*                         GDALGetBandNumber()                          */
    3956             : /************************************************************************/
    3957             : 
    3958             : /**
    3959             :  * \brief Fetch the band number.
    3960             :  *
    3961             :  * @see GDALRasterBand::GetBand()
    3962             :  */
    3963             : 
    3964         159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3965             : 
    3966             : {
    3967         159 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3968             : 
    3969         159 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3970         159 :     return poBand->GetBand();
    3971             : }
    3972             : 
    3973             : /************************************************************************/
    3974             : /*                             GetDataset()                             */
    3975             : /************************************************************************/
    3976             : 
    3977             : /**
    3978             :  * \brief Fetch the owning dataset handle.
    3979             :  *
    3980             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3981             :  * such as overviews or other "freestanding" bands.
    3982             :  *
    3983             :  * This method is the same as the C function GDALGetBandDataset().
    3984             :  *
    3985             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3986             :  * NULL if this cannot be determined.
    3987             :  */
    3988             : 
    3989     5290970 : GDALDataset *GDALRasterBand::GetDataset() const
    3990             : 
    3991             : {
    3992     5290970 :     return poDS;
    3993             : }
    3994             : 
    3995             : /************************************************************************/
    3996             : /*                         GDALGetBandDataset()                         */
    3997             : /************************************************************************/
    3998             : 
    3999             : /**
    4000             :  * \brief Fetch the owning dataset handle.
    4001             :  *
    4002             :  * @see GDALRasterBand::GetDataset()
    4003             :  */
    4004             : 
    4005         359 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    4006             : 
    4007             : {
    4008         359 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    4009             : 
    4010         359 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4011         359 :     return GDALDataset::ToHandle(poBand->GetDataset());
    4012             : }
    4013             : 
    4014             : /************************************************************************/
    4015             : /*                     ComputeFloat16NoDataValue()                      */
    4016             : /************************************************************************/
    4017             : 
    4018        3074 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    4019             :                                              double dfNoDataValue,
    4020             :                                              int &bGotNoDataValue,
    4021             :                                              GFloat16 &hfNoDataValue,
    4022             :                                              bool &bGotFloat16NoDataValue)
    4023             : {
    4024        3074 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    4025             :     {
    4026           7 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4027           7 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    4028             :         {
    4029           7 :             hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    4030           7 :             bGotFloat16NoDataValue = true;
    4031           7 :             bGotNoDataValue = false;
    4032             :         }
    4033             :     }
    4034        3074 : }
    4035             : 
    4036             : /************************************************************************/
    4037             : /*                      ComputeFloatNoDataValue()                       */
    4038             : /************************************************************************/
    4039             : 
    4040        3074 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    4041             :                                            double dfNoDataValue,
    4042             :                                            int &bGotNoDataValue,
    4043             :                                            float &fNoDataValue,
    4044             :                                            bool &bGotFloatNoDataValue)
    4045             : {
    4046        3074 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    4047             :     {
    4048          97 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4049          97 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    4050             :         {
    4051          97 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    4052          97 :             bGotFloatNoDataValue = true;
    4053          97 :             bGotNoDataValue = false;
    4054             :         }
    4055             :     }
    4056        3050 :     else if (eDataType == GDT_Int16 && bGotNoDataValue &&
    4057          73 :              GDALIsValueExactAs<int16_t>(dfNoDataValue))
    4058             :     {
    4059          73 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4060          73 :         bGotFloatNoDataValue = true;
    4061             :     }
    4062        2917 :     else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
    4063          13 :              GDALIsValueExactAs<uint16_t>(dfNoDataValue))
    4064             :     {
    4065          13 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4066          13 :         bGotFloatNoDataValue = true;
    4067             :     }
    4068        2898 :     else if (eDataType == GDT_Float16 && bGotNoDataValue &&
    4069           7 :              GDALIsValueExactAs<GFloat16>(dfNoDataValue))
    4070             :     {
    4071           7 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4072           7 :         bGotFloatNoDataValue = true;
    4073             :     }
    4074        3074 : }
    4075             : 
    4076             : /************************************************************************/
    4077             : /*                       struct GDALNoDataValues                        */
    4078             : /************************************************************************/
    4079             : 
    4080             : /**
    4081             :  * \brief No-data-values for all types
    4082             :  *
    4083             :  * The functions below pass various no-data-values around. To avoid
    4084             :  * long argument lists, this struct collects the no-data-values for
    4085             :  * all types into a single, convenient place.
    4086             :  **/
    4087             : 
    4088             : struct GDALNoDataValues
    4089             : {
    4090             :     int bGotNoDataValue;
    4091             :     double dfNoDataValue;
    4092             : 
    4093             :     bool bGotInt64NoDataValue;
    4094             :     int64_t nInt64NoDataValue;
    4095             : 
    4096             :     bool bGotUInt64NoDataValue;
    4097             :     uint64_t nUInt64NoDataValue;
    4098             : 
    4099             :     bool bGotFloatNoDataValue;
    4100             :     float fNoDataValue;
    4101             : 
    4102             :     bool bGotFloat16NoDataValue;
    4103             :     GFloat16 hfNoDataValue;
    4104             : 
    4105        3174 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    4106        3174 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    4107             :           bGotInt64NoDataValue(false), nInt64NoDataValue(0),
    4108             :           bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
    4109             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    4110        3174 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    4111             :     {
    4112        3174 :         if (eDataType == GDT_Int64)
    4113             :         {
    4114          62 :             int nGot = false;
    4115          62 :             nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
    4116          62 :             bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
    4117          62 :             if (bGotInt64NoDataValue)
    4118             :             {
    4119          10 :                 dfNoDataValue = static_cast<double>(nInt64NoDataValue);
    4120          10 :                 bGotNoDataValue =
    4121          10 :                     nInt64NoDataValue <=
    4122          20 :                         std::numeric_limits<int64_t>::max() - 1024 &&
    4123          10 :                     static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
    4124             :             }
    4125             :             else
    4126          52 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4127             :         }
    4128        3112 :         else if (eDataType == GDT_UInt64)
    4129             :         {
    4130          38 :             int nGot = false;
    4131          38 :             nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
    4132          38 :             bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
    4133          38 :             if (bGotUInt64NoDataValue)
    4134             :             {
    4135          10 :                 dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
    4136          10 :                 bGotNoDataValue =
    4137          10 :                     nUInt64NoDataValue <=
    4138          20 :                         std::numeric_limits<uint64_t>::max() - 2048 &&
    4139          10 :                     static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
    4140             :             }
    4141             :             else
    4142          28 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4143             :         }
    4144             :         else
    4145             :         {
    4146        3074 :             dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4147        3074 :             bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4148             : 
    4149        3074 :             ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4150        3074 :                                     fNoDataValue, bGotFloatNoDataValue);
    4151             : 
    4152        3074 :             ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4153        3074 :                                       hfNoDataValue, bGotFloat16NoDataValue);
    4154             :         }
    4155        3174 :     }
    4156             : };
    4157             : 
    4158             : /************************************************************************/
    4159             : /*                           ARE_REAL_EQUAL()                           */
    4160             : /************************************************************************/
    4161             : 
    4162          28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
    4163             : {
    4164             :     using std::abs;
    4165          56 :     return dfVal1 == dfVal2 || /* Should cover infinity */
    4166          28 :            abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
    4167          28 :                                       abs(dfVal1 + dfVal2) * ulp;
    4168             : }
    4169             : 
    4170             : /************************************************************************/
    4171             : /*                            GetHistogram()                            */
    4172             : /************************************************************************/
    4173             : 
    4174             : /**
    4175             :  * \brief Compute raster histogram.
    4176             :  *
    4177             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    4178             :  *
    4179             :  * For example to compute a simple 256 entry histogram of eight bit data,
    4180             :  * the following would be suitable.  The unusual bounds are to ensure that
    4181             :  * bucket boundaries don't fall right on integer values causing possible errors
    4182             :  * due to rounding after scaling.
    4183             : \code{.cpp}
    4184             :     GUIntBig anHistogram[256];
    4185             : 
    4186             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    4187             :                           GDALDummyProgress, nullptr );
    4188             : \endcode
    4189             :  *
    4190             :  * Note that setting bApproxOK will generally result in a subsampling of the
    4191             :  * file, and will utilize overviews if available.  It should generally
    4192             :  * produce a representative histogram for the data that is suitable for use
    4193             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    4194             :  * much faster than an exactly computed histogram.
    4195             :  *
    4196             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    4197             :  * GDALGetRasterHistogramEx().
    4198             :  *
    4199             :  * @param dfMin the lower bound of the histogram.
    4200             :  * @param dfMax the upper bound of the histogram.
    4201             :  * @param nBuckets the number of buckets in panHistogram.
    4202             :  * @param panHistogram array into which the histogram totals are placed.
    4203             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    4204             :  * mapped into panHistogram[0], and values above will be mapped into
    4205             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4206             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4207             :  * @param pfnProgress function to report progress to completion.
    4208             :  * @param pProgressData application data to pass to pfnProgress.
    4209             :  *
    4210             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4211             :  */
    4212             : 
    4213          45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4214             :                                     GUIntBig *panHistogram,
    4215             :                                     int bIncludeOutOfRange, int bApproxOK,
    4216             :                                     GDALProgressFunc pfnProgress,
    4217             :                                     void *pProgressData)
    4218             : 
    4219             : {
    4220          45 :     CPLAssert(nullptr != panHistogram);
    4221             : 
    4222          45 :     if (pfnProgress == nullptr)
    4223          29 :         pfnProgress = GDALDummyProgress;
    4224             : 
    4225             :     /* -------------------------------------------------------------------- */
    4226             :     /*      If we have overviews, use them for the histogram.               */
    4227             :     /* -------------------------------------------------------------------- */
    4228          45 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4229             :     {
    4230             :         // FIXME: should we use the most reduced overview here or use some
    4231             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4232             :         // does?
    4233           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4234             : 
    4235           0 :         if (poBestOverview != this)
    4236             :         {
    4237           0 :             return poBestOverview->GetHistogram(
    4238             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4239           0 :                 bApproxOK, pfnProgress, pProgressData);
    4240             :         }
    4241             :     }
    4242             : 
    4243             :     /* -------------------------------------------------------------------- */
    4244             :     /*      Read actual data and build histogram.                           */
    4245             :     /* -------------------------------------------------------------------- */
    4246          45 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4247             :     {
    4248           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4249           0 :         return CE_Failure;
    4250             :     }
    4251             : 
    4252             :     // Written this way to deal with NaN
    4253          45 :     if (!(dfMax > dfMin))
    4254             :     {
    4255           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4256             :                     "dfMax should be strictly greater than dfMin");
    4257           5 :         return CE_Failure;
    4258             :     }
    4259             : 
    4260             :     GDALRasterIOExtraArg sExtraArg;
    4261          40 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4262             : 
    4263          40 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4264          40 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4265             :     {
    4266           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4267             :                     "dfMin and dfMax should be finite values such that "
    4268             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4269           5 :         return CE_Failure;
    4270             :     }
    4271          35 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4272             : 
    4273          35 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4274          35 :     GDALRasterBand *poMaskBand = nullptr;
    4275          35 :     if (!sNoDataValues.bGotNoDataValue)
    4276             :     {
    4277          34 :         const int l_nMaskFlags = GetMaskFlags();
    4278          36 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    4279           2 :             GetColorInterpretation() != GCI_AlphaBand)
    4280             :         {
    4281           2 :             poMaskBand = GetMaskBand();
    4282             :         }
    4283             :     }
    4284             : 
    4285          35 :     bool bSignedByte = false;
    4286          35 :     if (eDataType == GDT_UInt8)
    4287             :     {
    4288          26 :         EnablePixelTypeSignedByteWarning(false);
    4289             :         const char *pszPixelType =
    4290          26 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4291          26 :         EnablePixelTypeSignedByteWarning(true);
    4292          26 :         bSignedByte =
    4293          26 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4294             :     }
    4295             : 
    4296          35 :     if (bApproxOK && HasArbitraryOverviews())
    4297             :     {
    4298             :         /* --------------------------------------------------------------------
    4299             :          */
    4300             :         /*      Figure out how much the image should be reduced to get an */
    4301             :         /*      approximate value. */
    4302             :         /* --------------------------------------------------------------------
    4303             :          */
    4304             :         const double dfReduction =
    4305           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4306             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4307             : 
    4308           0 :         int nXReduced = nRasterXSize;
    4309           0 :         int nYReduced = nRasterYSize;
    4310           0 :         if (dfReduction > 1.0)
    4311             :         {
    4312           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4313           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4314             : 
    4315             :             // Catch the case of huge resizing ratios here
    4316           0 :             if (nXReduced == 0)
    4317           0 :                 nXReduced = 1;
    4318           0 :             if (nYReduced == 0)
    4319           0 :                 nYReduced = 1;
    4320             :         }
    4321             : 
    4322           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4323             :                                           nXReduced, nYReduced);
    4324           0 :         if (!pData)
    4325           0 :             return CE_Failure;
    4326             : 
    4327             :         const CPLErr eErr =
    4328           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4329           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4330           0 :         if (eErr != CE_None)
    4331             :         {
    4332           0 :             CPLFree(pData);
    4333           0 :             return eErr;
    4334             :         }
    4335             : 
    4336           0 :         GByte *pabyMaskData = nullptr;
    4337           0 :         if (poMaskBand)
    4338             :         {
    4339             :             pabyMaskData =
    4340           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4341           0 :             if (!pabyMaskData)
    4342             :             {
    4343           0 :                 CPLFree(pData);
    4344           0 :                 return CE_Failure;
    4345             :             }
    4346             : 
    4347           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4348             :                                      pabyMaskData, nXReduced, nYReduced,
    4349           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    4350             :             {
    4351           0 :                 CPLFree(pData);
    4352           0 :                 CPLFree(pabyMaskData);
    4353           0 :                 return CE_Failure;
    4354             :             }
    4355             :         }
    4356             : 
    4357             :         // This isn't the fastest way to do this, but is easier for now.
    4358           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4359             :         {
    4360           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4361             :             {
    4362           0 :                 const int iOffset = iX + iY * nXReduced;
    4363           0 :                 double dfValue = 0.0;
    4364             : 
    4365           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4366           0 :                     continue;
    4367             : 
    4368           0 :                 switch (eDataType)
    4369             :                 {
    4370           0 :                     case GDT_UInt8:
    4371             :                     {
    4372           0 :                         if (bSignedByte)
    4373           0 :                             dfValue =
    4374           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4375             :                         else
    4376           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4377           0 :                         break;
    4378             :                     }
    4379           0 :                     case GDT_Int8:
    4380           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4381           0 :                         break;
    4382           0 :                     case GDT_UInt16:
    4383           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4384           0 :                         break;
    4385           0 :                     case GDT_Int16:
    4386           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4387           0 :                         break;
    4388           0 :                     case GDT_UInt32:
    4389           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4390           0 :                         break;
    4391           0 :                     case GDT_Int32:
    4392           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4393           0 :                         break;
    4394           0 :                     case GDT_UInt64:
    4395           0 :                         dfValue = static_cast<double>(
    4396           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4397           0 :                         break;
    4398           0 :                     case GDT_Int64:
    4399           0 :                         dfValue = static_cast<double>(
    4400           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4401           0 :                         break;
    4402           0 :                     case GDT_Float16:
    4403             :                     {
    4404             :                         using namespace std;
    4405           0 :                         const GFloat16 hfValue =
    4406           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4407           0 :                         if (isnan(hfValue) ||
    4408           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4409           0 :                              ARE_REAL_EQUAL(hfValue,
    4410             :                                             sNoDataValues.hfNoDataValue)))
    4411           0 :                             continue;
    4412           0 :                         dfValue = hfValue;
    4413           0 :                         break;
    4414             :                     }
    4415           0 :                     case GDT_Float32:
    4416             :                     {
    4417           0 :                         const float fValue =
    4418           0 :                             static_cast<float *>(pData)[iOffset];
    4419           0 :                         if (std::isnan(fValue) ||
    4420           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4421           0 :                              ARE_REAL_EQUAL(fValue,
    4422             :                                             sNoDataValues.fNoDataValue)))
    4423           0 :                             continue;
    4424           0 :                         dfValue = double(fValue);
    4425           0 :                         break;
    4426             :                     }
    4427           0 :                     case GDT_Float64:
    4428           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4429           0 :                         if (std::isnan(dfValue))
    4430           0 :                             continue;
    4431           0 :                         break;
    4432           0 :                     case GDT_CInt16:
    4433             :                     {
    4434           0 :                         const double dfReal =
    4435           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4436           0 :                         const double dfImag =
    4437           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4438           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4439           0 :                             continue;
    4440           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4441             :                     }
    4442           0 :                     break;
    4443           0 :                     case GDT_CInt32:
    4444             :                     {
    4445           0 :                         const double dfReal =
    4446           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4447           0 :                         const double dfImag =
    4448           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4449           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4450           0 :                             continue;
    4451           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4452             :                     }
    4453           0 :                     break;
    4454           0 :                     case GDT_CFloat16:
    4455             :                     {
    4456             :                         const double dfReal =
    4457           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4458             :                         const double dfImag =
    4459           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4460           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4461           0 :                             continue;
    4462           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4463           0 :                         break;
    4464             :                     }
    4465           0 :                     case GDT_CFloat32:
    4466             :                     {
    4467           0 :                         const double dfReal =
    4468           0 :                             double(static_cast<float *>(pData)[iOffset * 2]);
    4469           0 :                         const double dfImag = double(
    4470           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1]);
    4471           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4472           0 :                             continue;
    4473           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4474           0 :                         break;
    4475             :                     }
    4476           0 :                     case GDT_CFloat64:
    4477             :                     {
    4478           0 :                         const double dfReal =
    4479           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4480           0 :                         const double dfImag =
    4481           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4482           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4483           0 :                             continue;
    4484           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4485           0 :                         break;
    4486             :                     }
    4487           0 :                     case GDT_Unknown:
    4488             :                     case GDT_TypeCount:
    4489           0 :                         CPLAssert(false);
    4490             :                 }
    4491             : 
    4492           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4493           0 :                     sNoDataValues.bGotNoDataValue &&
    4494           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4495           0 :                     continue;
    4496             : 
    4497             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4498             :                 // finite, the result of the multiplication cannot be NaN
    4499           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4500             : 
    4501           0 :                 if (dfIndex < 0)
    4502             :                 {
    4503           0 :                     if (bIncludeOutOfRange)
    4504           0 :                         panHistogram[0]++;
    4505             :                 }
    4506           0 :                 else if (dfIndex >= nBuckets)
    4507             :                 {
    4508           0 :                     if (bIncludeOutOfRange)
    4509           0 :                         ++panHistogram[nBuckets - 1];
    4510             :                 }
    4511             :                 else
    4512             :                 {
    4513           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4514             :                 }
    4515             :             }
    4516             :         }
    4517             : 
    4518           0 :         CPLFree(pData);
    4519           0 :         CPLFree(pabyMaskData);
    4520             :     }
    4521             :     else  // No arbitrary overviews.
    4522             :     {
    4523          35 :         if (!InitBlockInfo())
    4524           0 :             return CE_Failure;
    4525             : 
    4526             :         /* --------------------------------------------------------------------
    4527             :          */
    4528             :         /*      Figure out the ratio of blocks we will read to get an */
    4529             :         /*      approximate value. */
    4530             :         /* --------------------------------------------------------------------
    4531             :          */
    4532             : 
    4533          35 :         int nSampleRate = 1;
    4534          35 :         if (bApproxOK)
    4535             :         {
    4536           8 :             nSampleRate = static_cast<int>(std::max(
    4537          16 :                 1.0,
    4538           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4539             :             // We want to avoid probing only the first column of blocks for
    4540             :             // a square shaped raster, because it is not unlikely that it may
    4541             :             // be padding only (#6378).
    4542           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4543           1 :                 nSampleRate += 1;
    4544             :         }
    4545             : 
    4546          35 :         GByte *pabyMaskData = nullptr;
    4547          35 :         if (poMaskBand)
    4548             :         {
    4549             :             pabyMaskData = static_cast<GByte *>(
    4550           2 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4551           2 :             if (!pabyMaskData)
    4552             :             {
    4553           0 :                 return CE_Failure;
    4554             :             }
    4555             :         }
    4556             : 
    4557             :         /* --------------------------------------------------------------------
    4558             :          */
    4559             :         /*      Read the blocks, and add to histogram. */
    4560             :         /* --------------------------------------------------------------------
    4561             :          */
    4562          35 :         for (GIntBig iSampleBlock = 0;
    4563         160 :              iSampleBlock <
    4564         160 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4565         125 :              iSampleBlock += nSampleRate)
    4566             :         {
    4567         125 :             if (!pfnProgress(
    4568         125 :                     static_cast<double>(iSampleBlock) /
    4569         125 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4570             :                     "Compute Histogram", pProgressData))
    4571             :             {
    4572           0 :                 CPLFree(pabyMaskData);
    4573           0 :                 return CE_Failure;
    4574             :             }
    4575             : 
    4576         125 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4577         125 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4578             : 
    4579         125 :             int nXCheck = 0, nYCheck = 0;
    4580         125 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4581             : 
    4582         127 :             if (poMaskBand &&
    4583           2 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4584           2 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4585             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    4586           2 :                                      0, nBlockXSize, nullptr) != CE_None)
    4587             :             {
    4588           0 :                 CPLFree(pabyMaskData);
    4589           0 :                 return CE_Failure;
    4590             :             }
    4591             : 
    4592         125 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4593         125 :             if (poBlock == nullptr)
    4594             :             {
    4595           0 :                 CPLFree(pabyMaskData);
    4596           0 :                 return CE_Failure;
    4597             :             }
    4598             : 
    4599         125 :             void *pData = poBlock->GetDataRef();
    4600             : 
    4601             :             // this is a special case for a common situation.
    4602         125 :             if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
    4603          89 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4604          86 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4605             :             {
    4606          86 :                 const GPtrDiff_t nPixels =
    4607          86 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4608          86 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4609             : 
    4610       79640 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4611             :                 {
    4612       79554 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4613           0 :                         continue;
    4614       79554 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4615         512 :                           (pabyData[i] ==
    4616         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4617             :                     {
    4618       79298 :                         panHistogram[pabyData[i]]++;
    4619             :                     }
    4620             :                 }
    4621             : 
    4622          86 :                 poBlock->DropLock();
    4623          86 :                 continue;  // To next sample block.
    4624             :             }
    4625             : 
    4626             :             // This isn't the fastest way to do this, but is easier for now.
    4627         257 :             for (int iY = 0; iY < nYCheck; iY++)
    4628             :             {
    4629       36389 :                 for (int iX = 0; iX < nXCheck; iX++)
    4630             :                 {
    4631       36171 :                     const GPtrDiff_t iOffset =
    4632       36171 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4633             : 
    4634       36171 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4635           2 :                         continue;
    4636             : 
    4637       36169 :                     double dfValue = 0.0;
    4638             : 
    4639       36169 :                     switch (eDataType)
    4640             :                     {
    4641       19716 :                         case GDT_UInt8:
    4642             :                         {
    4643       19716 :                             if (bSignedByte)
    4644           0 :                                 dfValue =
    4645           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4646             :                             else
    4647       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4648       19716 :                             break;
    4649             :                         }
    4650           1 :                         case GDT_Int8:
    4651           1 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4652           1 :                             break;
    4653       16384 :                         case GDT_UInt16:
    4654       16384 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4655       16384 :                             break;
    4656           3 :                         case GDT_Int16:
    4657           3 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4658           3 :                             break;
    4659           0 :                         case GDT_UInt32:
    4660           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4661           0 :                             break;
    4662          60 :                         case GDT_Int32:
    4663          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4664          60 :                             break;
    4665           0 :                         case GDT_UInt64:
    4666           0 :                             dfValue = static_cast<double>(
    4667           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4668           0 :                             break;
    4669           0 :                         case GDT_Int64:
    4670           0 :                             dfValue = static_cast<double>(
    4671           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4672           0 :                             break;
    4673           0 :                         case GDT_Float16:
    4674             :                         {
    4675             :                             using namespace std;
    4676           0 :                             const GFloat16 hfValue =
    4677           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4678           0 :                             if (isnan(hfValue) ||
    4679           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4680           0 :                                  ARE_REAL_EQUAL(hfValue,
    4681             :                                                 sNoDataValues.hfNoDataValue)))
    4682           0 :                                 continue;
    4683           0 :                             dfValue = hfValue;
    4684           0 :                             break;
    4685             :                         }
    4686           3 :                         case GDT_Float32:
    4687             :                         {
    4688           3 :                             const float fValue =
    4689           3 :                                 static_cast<float *>(pData)[iOffset];
    4690           6 :                             if (std::isnan(fValue) ||
    4691           6 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4692           3 :                                  ARE_REAL_EQUAL(fValue,
    4693             :                                                 sNoDataValues.fNoDataValue)))
    4694           0 :                                 continue;
    4695           3 :                             dfValue = double(fValue);
    4696           3 :                             break;
    4697             :                         }
    4698           2 :                         case GDT_Float64:
    4699           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4700           2 :                             if (std::isnan(dfValue))
    4701           0 :                                 continue;
    4702           2 :                             break;
    4703           0 :                         case GDT_CInt16:
    4704             :                         {
    4705           0 :                             double dfReal =
    4706           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4707           0 :                             double dfImag =
    4708           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4709           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4710           0 :                             break;
    4711             :                         }
    4712           0 :                         case GDT_CInt32:
    4713             :                         {
    4714           0 :                             double dfReal =
    4715           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4716           0 :                             double dfImag =
    4717           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4718           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4719           0 :                             break;
    4720             :                         }
    4721           0 :                         case GDT_CFloat16:
    4722             :                         {
    4723             :                             double dfReal =
    4724           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4725             :                             double dfImag =
    4726           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4727           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4728           0 :                                 continue;
    4729           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4730           0 :                             break;
    4731             :                         }
    4732           0 :                         case GDT_CFloat32:
    4733             :                         {
    4734           0 :                             double dfReal = double(
    4735           0 :                                 static_cast<float *>(pData)[iOffset * 2]);
    4736           0 :                             double dfImag = double(
    4737           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1]);
    4738           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4739           0 :                                 continue;
    4740           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4741           0 :                             break;
    4742             :                         }
    4743           0 :                         case GDT_CFloat64:
    4744             :                         {
    4745           0 :                             double dfReal =
    4746           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4747           0 :                             double dfImag =
    4748           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4749           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4750           0 :                                 continue;
    4751           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4752           0 :                             break;
    4753             :                         }
    4754           0 :                         case GDT_Unknown:
    4755             :                         case GDT_TypeCount:
    4756           0 :                             CPLAssert(false);
    4757             :                             CPLFree(pabyMaskData);
    4758             :                             return CE_Failure;
    4759             :                     }
    4760             : 
    4761       36169 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4762       72338 :                         sNoDataValues.bGotNoDataValue &&
    4763           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4764           0 :                         continue;
    4765             : 
    4766             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4767             :                     // and finite, the result of the multiplication cannot be
    4768             :                     // NaN
    4769       36169 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4770             : 
    4771       36169 :                     if (dfIndex < 0)
    4772             :                     {
    4773           1 :                         if (bIncludeOutOfRange)
    4774           1 :                             panHistogram[0]++;
    4775             :                     }
    4776       36168 :                     else if (dfIndex >= nBuckets)
    4777             :                     {
    4778           7 :                         if (bIncludeOutOfRange)
    4779           4 :                             ++panHistogram[nBuckets - 1];
    4780             :                     }
    4781             :                     else
    4782             :                     {
    4783       36161 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4784             :                     }
    4785             :                 }
    4786             :             }
    4787             : 
    4788          39 :             poBlock->DropLock();
    4789             :         }
    4790             : 
    4791          35 :         CPLFree(pabyMaskData);
    4792             :     }
    4793             : 
    4794          35 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4795             : 
    4796          35 :     return CE_None;
    4797             : }
    4798             : 
    4799             : /************************************************************************/
    4800             : /*                       GDALGetRasterHistogram()                       */
    4801             : /************************************************************************/
    4802             : 
    4803             : /**
    4804             :  * \brief Compute raster histogram.
    4805             :  *
    4806             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4807             :  * exceeding 2 billion.
    4808             :  *
    4809             :  * @see GDALRasterBand::GetHistogram()
    4810             :  * @see GDALGetRasterHistogramEx()
    4811             :  */
    4812             : 
    4813           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4814             :                                           double dfMax, int nBuckets,
    4815             :                                           int *panHistogram,
    4816             :                                           int bIncludeOutOfRange, int bApproxOK,
    4817             :                                           GDALProgressFunc pfnProgress,
    4818             :                                           void *pProgressData)
    4819             : 
    4820             : {
    4821           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4822           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4823             : 
    4824           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4825             : 
    4826             :     GUIntBig *panHistogramTemp =
    4827           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4828           0 :     if (panHistogramTemp == nullptr)
    4829             :     {
    4830           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4831             :                             "Out of memory in GDALGetRasterHistogram().");
    4832           0 :         return CE_Failure;
    4833             :     }
    4834             : 
    4835           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4836             :                                        bIncludeOutOfRange, bApproxOK,
    4837           0 :                                        pfnProgress, pProgressData);
    4838             : 
    4839           0 :     if (eErr == CE_None)
    4840             :     {
    4841           0 :         for (int i = 0; i < nBuckets; i++)
    4842             :         {
    4843           0 :             if (panHistogramTemp[i] > INT_MAX)
    4844             :             {
    4845           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4846             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4847             :                          " exceeds maximum 32 bit value",
    4848           0 :                          i, panHistogramTemp[i]);
    4849           0 :                 panHistogram[i] = INT_MAX;
    4850             :             }
    4851             :             else
    4852             :             {
    4853           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4854             :             }
    4855             :         }
    4856             :     }
    4857             : 
    4858           0 :     CPLFree(panHistogramTemp);
    4859             : 
    4860           0 :     return eErr;
    4861             : }
    4862             : 
    4863             : /************************************************************************/
    4864             : /*                      GDALGetRasterHistogramEx()                      */
    4865             : /************************************************************************/
    4866             : 
    4867             : /**
    4868             :  * \brief Compute raster histogram.
    4869             :  *
    4870             :  * @see GDALRasterBand::GetHistogram()
    4871             :  *
    4872             :  */
    4873             : 
    4874          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4875             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4876             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4877             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4878             : 
    4879             : {
    4880          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4881          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4882             : 
    4883          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4884             : 
    4885          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4886             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4887          26 :                                 pProgressData);
    4888             : }
    4889             : 
    4890             : /************************************************************************/
    4891             : /*                        GetDefaultHistogram()                         */
    4892             : /************************************************************************/
    4893             : 
    4894             : /**
    4895             :  * \brief Fetch default raster histogram.
    4896             :  *
    4897             :  * The default method in GDALRasterBand will compute a default histogram. This
    4898             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4899             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4900             :  * stored histogram.
    4901             :  *
    4902             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4903             :  * GDALGetDefaultHistogramEx().
    4904             :  *
    4905             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4906             :  * the histogram.
    4907             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4908             :  * the histogram.
    4909             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4910             :  * in *ppanHistogram.
    4911             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4912             :  * placed. To be freed with VSIFree
    4913             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4914             :  * histogram is available, the method will return CE_Warning
    4915             :  * @param pfnProgress function to report progress to completion.
    4916             :  * @param pProgressData application data to pass to pfnProgress.
    4917             :  *
    4918             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4919             :  * CE_Warning if no default histogram is available.
    4920             :  */
    4921             : 
    4922          27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4923             :                                            int *pnBuckets,
    4924             :                                            GUIntBig **ppanHistogram, int bForce,
    4925             :                                            GDALProgressFunc pfnProgress,
    4926             :                                            void *pProgressData)
    4927             : 
    4928             : {
    4929          27 :     CPLAssert(nullptr != pnBuckets);
    4930          27 :     CPLAssert(nullptr != ppanHistogram);
    4931          27 :     CPLAssert(nullptr != pdfMin);
    4932          27 :     CPLAssert(nullptr != pdfMax);
    4933             : 
    4934          27 :     *pnBuckets = 0;
    4935          27 :     *ppanHistogram = nullptr;
    4936             : 
    4937          27 :     if (!bForce)
    4938           5 :         return CE_Warning;
    4939             : 
    4940          22 :     int nBuckets = 256;
    4941             : 
    4942          22 :     bool bSignedByte = false;
    4943          22 :     if (eDataType == GDT_UInt8)
    4944             :     {
    4945          20 :         EnablePixelTypeSignedByteWarning(false);
    4946             :         const char *pszPixelType =
    4947          20 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4948          20 :         EnablePixelTypeSignedByteWarning(true);
    4949          20 :         bSignedByte =
    4950          20 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4951             :     }
    4952             : 
    4953          22 :     if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
    4954             :     {
    4955          20 :         *pdfMin = -0.5;
    4956          20 :         *pdfMax = 255.5;
    4957             :     }
    4958           2 :     else if (GetRasterDataType() == GDT_Int8)
    4959             :     {
    4960           1 :         *pdfMin = -128 - 0.5;
    4961           1 :         *pdfMax = 127 + 0.5;
    4962             :     }
    4963             :     else
    4964             :     {
    4965             : 
    4966             :         const CPLErr eErr =
    4967           1 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4968           1 :         if (eErr != CE_None)
    4969           0 :             return eErr;
    4970           1 :         if (*pdfMin == *pdfMax)
    4971             :         {
    4972           1 :             nBuckets = 1;
    4973           1 :             *pdfMin -= 0.5;
    4974           1 :             *pdfMax += 0.5;
    4975             :         }
    4976             :         else
    4977             :         {
    4978           0 :             const double dfHalfBucket =
    4979           0 :                 (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4980           0 :             *pdfMin -= dfHalfBucket;
    4981           0 :             *pdfMax += dfHalfBucket;
    4982             :         }
    4983             :     }
    4984             : 
    4985          22 :     *ppanHistogram =
    4986          22 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4987          22 :     if (*ppanHistogram == nullptr)
    4988             :     {
    4989           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4990             :                     "Out of memory in GetDefaultHistogram().");
    4991           0 :         return CE_Failure;
    4992             :     }
    4993             : 
    4994          22 :     *pnBuckets = nBuckets;
    4995          44 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4996          22 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4997          22 :     if (eErr != CE_None)
    4998             :     {
    4999           0 :         *pnBuckets = 0;
    5000             :     }
    5001          22 :     return eErr;
    5002             : }
    5003             : 
    5004             : /************************************************************************/
    5005             : /*                      GDALGetDefaultHistogram()                       */
    5006             : /************************************************************************/
    5007             : 
    5008             : /**
    5009             :  * \brief Fetch default raster histogram.
    5010             :  *
    5011             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    5012             :  * exceeding 2 billion.
    5013             :  *
    5014             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    5015             :  * @see GDALGetRasterHistogramEx()
    5016             :  */
    5017             : 
    5018           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    5019             :                                            double *pdfMin, double *pdfMax,
    5020             :                                            int *pnBuckets, int **ppanHistogram,
    5021             :                                            int bForce,
    5022             :                                            GDALProgressFunc pfnProgress,
    5023             :                                            void *pProgressData)
    5024             : 
    5025             : {
    5026           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5027           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5028           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5029           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5030           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5031             : 
    5032           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    5033           0 :     GUIntBig *panHistogramTemp = nullptr;
    5034           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    5035             :                                               &panHistogramTemp, bForce,
    5036           0 :                                               pfnProgress, pProgressData);
    5037           0 :     if (eErr == CE_None)
    5038             :     {
    5039           0 :         const int nBuckets = *pnBuckets;
    5040           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    5041           0 :         if (*ppanHistogram == nullptr)
    5042             :         {
    5043           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    5044             :                                 "Out of memory in GDALGetDefaultHistogram().");
    5045           0 :             VSIFree(panHistogramTemp);
    5046           0 :             return CE_Failure;
    5047             :         }
    5048             : 
    5049           0 :         for (int i = 0; i < nBuckets; ++i)
    5050             :         {
    5051           0 :             if (panHistogramTemp[i] > INT_MAX)
    5052             :             {
    5053           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    5054             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    5055             :                          " exceeds maximum 32 bit value",
    5056           0 :                          i, panHistogramTemp[i]);
    5057           0 :                 (*ppanHistogram)[i] = INT_MAX;
    5058             :             }
    5059             :             else
    5060             :             {
    5061           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    5062             :             }
    5063             :         }
    5064             : 
    5065           0 :         CPLFree(panHistogramTemp);
    5066             :     }
    5067             :     else
    5068             :     {
    5069           0 :         *ppanHistogram = nullptr;
    5070             :     }
    5071             : 
    5072           0 :     return eErr;
    5073             : }
    5074             : 
    5075             : /************************************************************************/
    5076             : /*                     GDALGetDefaultHistogramEx()                      */
    5077             : /************************************************************************/
    5078             : 
    5079             : /**
    5080             :  * \brief Fetch default raster histogram.
    5081             :  *
    5082             :  * @see GDALRasterBand::GetDefaultHistogram()
    5083             :  *
    5084             :  */
    5085             : 
    5086             : CPLErr CPL_STDCALL
    5087          30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    5088             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    5089             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    5090             : 
    5091             : {
    5092          30 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5093          30 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5094          30 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5095          30 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5096          30 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5097             : 
    5098          30 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5099          30 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    5100          30 :                                        bForce, pfnProgress, pProgressData);
    5101             : }
    5102             : 
    5103             : /************************************************************************/
    5104             : /*                             AdviseRead()                             */
    5105             : /************************************************************************/
    5106             : 
    5107             : /**
    5108             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    5109             :  * \brief Advise driver of upcoming read requests.
    5110             :  *
    5111             :  * Some GDAL drivers operate more efficiently if they know in advance what
    5112             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    5113             :  * an application to notify the driver of the region of interest,
    5114             :  * and at what resolution the region will be read.
    5115             :  *
    5116             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    5117             :  * accelerate access via some drivers.
    5118             :  *
    5119             :  * Depending on call paths, drivers might receive several calls to
    5120             :  * AdviseRead() with the same parameters.
    5121             :  *
    5122             :  * @param nXOff The pixel offset to the top left corner of the region
    5123             :  * of the band to be accessed.  This would be zero to start from the left side.
    5124             :  *
    5125             :  * @param nYOff The line offset to the top left corner of the region
    5126             :  * of the band to be accessed.  This would be zero to start from the top.
    5127             :  *
    5128             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    5129             :  *
    5130             :  * @param nYSize The height of the region of the band to be accessed in lines.
    5131             :  *
    5132             :  * @param nBufXSize the width of the buffer image into which the desired region
    5133             :  * is to be read, or from which it is to be written.
    5134             :  *
    5135             :  * @param nBufYSize the height of the buffer image into which the desired
    5136             :  * region is to be read, or from which it is to be written.
    5137             :  *
    5138             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    5139             :  * pixel values will automatically be translated to/from the GDALRasterBand
    5140             :  * data type as needed.
    5141             :  *
    5142             :  * @param papszOptions a list of name=value strings with special control
    5143             :  * options.  Normally this is NULL.
    5144             :  *
    5145             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    5146             :  * is ignored.
    5147             :  */
    5148             : 
    5149             : /**/
    5150             : /**/
    5151             : 
    5152      114460 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    5153             :                                   int /*nYSize*/, int /*nBufXSize*/,
    5154             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    5155             :                                   CSLConstList /*papszOptions*/)
    5156             : {
    5157      114460 :     return CE_None;
    5158             : }
    5159             : 
    5160             : /************************************************************************/
    5161             : /*                        GDALRasterAdviseRead()                        */
    5162             : /************************************************************************/
    5163             : 
    5164             : /**
    5165             :  * \brief Advise driver of upcoming read requests.
    5166             :  *
    5167             :  * @see GDALRasterBand::AdviseRead()
    5168             :  */
    5169             : 
    5170           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    5171             :                                         int nYOff, int nXSize, int nYSize,
    5172             :                                         int nBufXSize, int nBufYSize,
    5173             :                                         GDALDataType eDT,
    5174             :                                         CSLConstList papszOptions)
    5175             : 
    5176             : {
    5177           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    5178             : 
    5179           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5180           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    5181             :                               nBufYSize, eDT,
    5182           2 :                               const_cast<char **>(papszOptions));
    5183             : }
    5184             : 
    5185             : /************************************************************************/
    5186             : /*                           GetStatistics()                            */
    5187             : /************************************************************************/
    5188             : 
    5189             : /**
    5190             :  * \brief Fetch image statistics.
    5191             :  *
    5192             :  * Returns the minimum, maximum, mean and standard deviation of all
    5193             :  * pixel values in this band.  If approximate statistics are sufficient,
    5194             :  * the bApproxOK flag can be set to true in which case overviews, or a
    5195             :  * subset of image tiles may be used in computing the statistics.
    5196             :  *
    5197             :  * If bForce is FALSE results will only be returned if it can be done
    5198             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    5199             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    5200             :  * returned efficiently, the method will return CE_Warning but no warning will
    5201             :  * be issued. This is a non-standard use of the CE_Warning return value
    5202             :  * to indicate "nothing done".
    5203             :  *
    5204             :  * If bForce is TRUE, and results are quickly available without scanning the
    5205             :  * image, they will be used. If bForce is TRUE and results are not quickly
    5206             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    5207             :  * which will scan the image.
    5208             :  *
    5209             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    5210             :  * of this method.
    5211             :  *
    5212             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    5213             :  * will generally cache statistics in the .pam file allowing fast fetch
    5214             :  * after the first request.
    5215             :  *
    5216             :  * This method is the same as the C function GDALGetRasterStatistics().
    5217             :  *
    5218             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5219             :  * or a subset of all tiles.
    5220             :  *
    5221             :  * @param bForce If FALSE statistics will only be returned if it can
    5222             :  * be done without rescanning the image. If TRUE, statistics computation will
    5223             :  * be forced if pre-existing values are not quickly available.
    5224             :  *
    5225             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5226             :  *
    5227             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5228             :  *
    5229             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5230             :  *
    5231             :  * @param pdfStdDev Location into which to load image standard deviation
    5232             :  * (may be NULL).
    5233             :  *
    5234             :  * @return CE_None on success, CE_Warning if no values returned,
    5235             :  * CE_Failure if an error occurs.
    5236             :  */
    5237             : 
    5238         673 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5239             :                                      double *pdfMax, double *pdfMean,
    5240             :                                      double *pdfStdDev)
    5241             : 
    5242             : {
    5243             :     /* -------------------------------------------------------------------- */
    5244             :     /*      Do we already have metadata items for the requested values?     */
    5245             :     /* -------------------------------------------------------------------- */
    5246        1346 :     if ((pdfMin == nullptr ||
    5247         673 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5248         206 :         (pdfMax == nullptr ||
    5249         206 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5250        1552 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5251         206 :         (pdfStdDev == nullptr ||
    5252         206 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5253             :     {
    5254         206 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5255             :         {
    5256         199 :             if (pdfMin != nullptr)
    5257         199 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5258         199 :             if (pdfMax != nullptr)
    5259         199 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5260         199 :             if (pdfMean != nullptr)
    5261         199 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5262         199 :             if (pdfStdDev != nullptr)
    5263         199 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5264             : 
    5265         199 :             return CE_None;
    5266             :         }
    5267             :     }
    5268             : 
    5269             :     /* -------------------------------------------------------------------- */
    5270             :     /*      Does the driver already know the min/max?                       */
    5271             :     /* -------------------------------------------------------------------- */
    5272         474 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5273             :     {
    5274           1 :         int bSuccessMin = FALSE;
    5275           1 :         int bSuccessMax = FALSE;
    5276             : 
    5277           1 :         const double dfMin = GetMinimum(&bSuccessMin);
    5278           1 :         const double dfMax = GetMaximum(&bSuccessMax);
    5279             : 
    5280           1 :         if (bSuccessMin && bSuccessMax)
    5281             :         {
    5282           0 :             if (pdfMin != nullptr)
    5283           0 :                 *pdfMin = dfMin;
    5284           0 :             if (pdfMax != nullptr)
    5285           0 :                 *pdfMax = dfMax;
    5286           0 :             return CE_None;
    5287             :         }
    5288             :     }
    5289             : 
    5290             :     /* -------------------------------------------------------------------- */
    5291             :     /*      Either return without results, or force computation.            */
    5292             :     /* -------------------------------------------------------------------- */
    5293         474 :     if (!bForce)
    5294         191 :         return CE_Warning;
    5295             :     else
    5296         283 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5297         283 :                                  GDALDummyProgress, nullptr);
    5298             : }
    5299             : 
    5300             : /************************************************************************/
    5301             : /*                      GDALGetRasterStatistics()                       */
    5302             : /************************************************************************/
    5303             : 
    5304             : /**
    5305             :  * \brief Fetch image statistics.
    5306             :  *
    5307             :  * @see GDALRasterBand::GetStatistics()
    5308             :  */
    5309             : 
    5310         321 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5311             :                                            int bForce, double *pdfMin,
    5312             :                                            double *pdfMax, double *pdfMean,
    5313             :                                            double *pdfStdDev)
    5314             : 
    5315             : {
    5316         321 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5317             : 
    5318         321 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5319         321 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5320         321 :                                  pdfStdDev);
    5321             : }
    5322             : 
    5323             : /************************************************************************/
    5324             : /*                             GDALUInt128                              */
    5325             : /************************************************************************/
    5326             : 
    5327             : #ifdef HAVE_UINT128_T
    5328             : class GDALUInt128
    5329             : {
    5330             :     __uint128_t val;
    5331             : 
    5332        1188 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5333             :     {
    5334        1188 :     }
    5335             : 
    5336             :   public:
    5337         792 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5338             :     {
    5339             :         // Evaluates to just a single mul on x86_64
    5340         792 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5341             :     }
    5342             : 
    5343         396 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5344             :     {
    5345         396 :         return GDALUInt128(val - other.val);
    5346             :     }
    5347             : 
    5348         387 :     operator double() const
    5349             :     {
    5350         387 :         return static_cast<double>(val);
    5351             :     }
    5352             : };
    5353             : #else
    5354             : 
    5355             : #if defined(_MSC_VER) && defined(_M_X64)
    5356             : #include <intrin.h>
    5357             : #endif
    5358             : 
    5359             : class GDALUInt128
    5360             : {
    5361             :     GUIntBig low, high;
    5362             : 
    5363             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5364             :     {
    5365             :     }
    5366             : 
    5367             :   public:
    5368             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5369             :     {
    5370             : #if defined(_MSC_VER) && defined(_M_X64)
    5371             :         GUIntBig highRes;
    5372             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5373             :         return GDALUInt128(lowRes, highRes);
    5374             : #else
    5375             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5376             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5377             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5378             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5379             :         GUIntBig highRes = 0;
    5380             :         const GUIntBig firstLowSecondHigh =
    5381             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5382             :         const GUIntBig firstHighSecondLow =
    5383             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5384             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5385             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5386             :             highRes += static_cast<GUIntBig>(1) << 32;
    5387             :         const GUIntBig firstLowSecondLow =
    5388             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5389             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5390             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5391             :             highRes++;
    5392             :         highRes +=
    5393             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5394             :         return GDALUInt128(lowRes, highRes);
    5395             : #endif
    5396             :     }
    5397             : 
    5398             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5399             :     {
    5400             :         GUIntBig highRes = high - other.high;
    5401             :         GUIntBig lowRes = low - other.low;
    5402             :         if (lowRes > low)  // check for underflow
    5403             :             --highRes;
    5404             :         return GDALUInt128(lowRes, highRes);
    5405             :     }
    5406             : 
    5407             :     operator double() const
    5408             :     {
    5409             :         const double twoPow64 = 18446744073709551616.0;
    5410             :         return high * twoPow64 + low;
    5411             :     }
    5412             : };
    5413             : #endif
    5414             : 
    5415             : /************************************************************************/
    5416             : /*                     ComputeStatisticsInternal()                      */
    5417             : /************************************************************************/
    5418             : 
    5419             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5420             : // not needed.
    5421             : #define static_cast_for_coverity_scan static_cast
    5422             : 
    5423             : // The rationale for below optimizations is detailed in statistics.txt
    5424             : 
    5425             : // Use with T = GByte or GUInt16 only !
    5426             : template <class T, bool COMPUTE_OTHER_STATS>
    5427             : struct ComputeStatisticsInternalGeneric
    5428             : {
    5429         255 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5430             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5431             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5432             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5433             :     {
    5434             :         static_assert(std::is_same<T, GByte>::value ||
    5435             :                           std::is_same<T, GUInt16>::value,
    5436             :                       "bad type for T");
    5437         255 :         if (bHasNoData)
    5438             :         {
    5439             :             // General case
    5440         620 :             for (int iY = 0; iY < nYCheck; iY++)
    5441             :             {
    5442      161785 :                 for (int iX = 0; iX < nXCheck; iX++)
    5443             :                 {
    5444      161293 :                     const GPtrDiff_t iOffset =
    5445      161293 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5446      161293 :                     const GUInt32 nValue = pData[iOffset];
    5447      161293 :                     if (nValue == nNoDataValue)
    5448         323 :                         continue;
    5449      160970 :                     if (nValue < nMin)
    5450          44 :                         nMin = nValue;
    5451      160970 :                     if (nValue > nMax)
    5452          75 :                         nMax = nValue;
    5453             :                     if constexpr (COMPUTE_OTHER_STATS)
    5454             :                     {
    5455      159334 :                         nValidCount++;
    5456      159334 :                         nSum += nValue;
    5457      159334 :                         nSumSquare +=
    5458      159334 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5459      159334 :                             nValue;
    5460             :                     }
    5461             :                 }
    5462             :             }
    5463             :             if constexpr (COMPUTE_OTHER_STATS)
    5464             :             {
    5465          44 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5466             :             }
    5467             :         }
    5468         145 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5469          18 :                  nMax == std::numeric_limits<T>::max())
    5470             :         {
    5471             :             if constexpr (COMPUTE_OTHER_STATS)
    5472             :             {
    5473             :                 // Optimization when there is no nodata and we know we have already
    5474             :                 // reached the min and max
    5475         416 :                 for (int iY = 0; iY < nYCheck; iY++)
    5476             :                 {
    5477             :                     int iX;
    5478        2004 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5479             :                     {
    5480        1600 :                         const GPtrDiff_t iOffset =
    5481        1600 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5482        1600 :                         const GUIntBig nValue = pData[iOffset];
    5483        1600 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5484        1600 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5485        1600 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5486        1600 :                         nSum += nValue;
    5487        1600 :                         nSumSquare += nValue * nValue;
    5488        1600 :                         nSum += nValue2;
    5489        1600 :                         nSumSquare += nValue2 * nValue2;
    5490        1600 :                         nSum += nValue3;
    5491        1600 :                         nSumSquare += nValue3 * nValue3;
    5492        1600 :                         nSum += nValue4;
    5493        1600 :                         nSumSquare += nValue4 * nValue4;
    5494             :                     }
    5495         414 :                     for (; iX < nXCheck; ++iX)
    5496             :                     {
    5497          10 :                         const GPtrDiff_t iOffset =
    5498          10 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5499          10 :                         const GUIntBig nValue = pData[iOffset];
    5500          10 :                         nSum += nValue;
    5501          10 :                         nSumSquare += nValue * nValue;
    5502             :                     }
    5503             :                 }
    5504          12 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5505          12 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5506             :             }
    5507             :         }
    5508             :         else
    5509             :         {
    5510        6021 :             for (int iY = 0; iY < nYCheck; iY++)
    5511             :             {
    5512             :                 int iX;
    5513     1270512 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5514             :                 {
    5515     1264612 :                     const GPtrDiff_t iOffset =
    5516     1264612 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5517     1264612 :                     const GUInt32 nValue = pData[iOffset];
    5518     1264612 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5519     1264612 :                     if (nValue < nValue2)
    5520             :                     {
    5521        2325 :                         if (nValue < nMin)
    5522          51 :                             nMin = nValue;
    5523        2325 :                         if (nValue2 > nMax)
    5524         119 :                             nMax = nValue2;
    5525             :                     }
    5526             :                     else
    5527             :                     {
    5528     1262285 :                         if (nValue2 < nMin)
    5529          67 :                             nMin = nValue2;
    5530     1262285 :                         if (nValue > nMax)
    5531         216 :                             nMax = nValue;
    5532             :                     }
    5533             :                     if constexpr (COMPUTE_OTHER_STATS)
    5534             :                     {
    5535     1257560 :                         nSum += nValue;
    5536     1257560 :                         nSumSquare +=
    5537     1257560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5538     1257560 :                             nValue;
    5539     1257560 :                         nSum += nValue2;
    5540     1257560 :                         nSumSquare +=
    5541     1257560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5542     1257560 :                             nValue2;
    5543             :                     }
    5544             :                 }
    5545        5906 :                 if (iX < nXCheck)
    5546             :                 {
    5547          27 :                     const GPtrDiff_t iOffset =
    5548          27 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5549          27 :                     const GUInt32 nValue = pData[iOffset];
    5550          27 :                     if (nValue < nMin)
    5551          19 :                         nMin = nValue;
    5552          27 :                     if (nValue > nMax)
    5553          20 :                         nMax = nValue;
    5554             :                     if (COMPUTE_OTHER_STATS)
    5555             :                     {
    5556          19 :                         nSum += nValue;
    5557          19 :                         nSumSquare +=
    5558          19 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5559          19 :                             nValue;
    5560             :                     }
    5561             :                 }
    5562             :             }
    5563             :             if constexpr (COMPUTE_OTHER_STATS)
    5564             :             {
    5565          60 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5566          60 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5567             :             }
    5568             :         }
    5569         255 :     }
    5570             : };
    5571             : 
    5572             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5573             : // using 64bit accumulators in internal loops. This also slightly helps in
    5574             : // 64bit mode.
    5575             : template <bool COMPUTE_OTHER_STATS>
    5576             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5577             : {
    5578       13781 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5579             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5580             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5581             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5582             :     {
    5583       13781 :         int nOuterLoops = nXCheck / 65536;
    5584       13781 :         if (nXCheck % 65536)
    5585       13781 :             nOuterLoops++;
    5586             : 
    5587       13781 :         if (bHasNoData)
    5588             :         {
    5589             :             // General case
    5590       23801 :             for (int iY = 0; iY < nYCheck; iY++)
    5591             :             {
    5592       13205 :                 int iX = 0;
    5593       26410 :                 for (int k = 0; k < nOuterLoops; k++)
    5594             :                 {
    5595       13205 :                     int iMax = iX + 65536;
    5596       13205 :                     if (iMax > nXCheck)
    5597       13205 :                         iMax = nXCheck;
    5598       13205 :                     GUInt32 nSum32bit = 0;
    5599       13205 :                     GUInt32 nSumSquare32bit = 0;
    5600       13205 :                     GUInt32 nValidCount32bit = 0;
    5601       13205 :                     GUInt32 nSampleCount32bit = 0;
    5602    20722932 :                     for (; iX < iMax; iX++)
    5603             :                     {
    5604    20709787 :                         const GPtrDiff_t iOffset =
    5605    20709787 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5606    20709787 :                         const GUInt32 nValue = pData[iOffset];
    5607             : 
    5608    20709787 :                         nSampleCount32bit++;
    5609    20709787 :                         if (nValue == nNoDataValue)
    5610    20353620 :                             continue;
    5611      356112 :                         if (nValue < nMin)
    5612         381 :                             nMin = nValue;
    5613      356112 :                         if (nValue > nMax)
    5614         838 :                             nMax = nValue;
    5615             :                         if constexpr (COMPUTE_OTHER_STATS)
    5616             :                         {
    5617       32367 :                             nValidCount32bit++;
    5618       32367 :                             nSum32bit += nValue;
    5619       32367 :                             nSumSquare32bit += nValue * nValue;
    5620             :                         }
    5621             :                     }
    5622             :                     if constexpr (COMPUTE_OTHER_STATS)
    5623             :                     {
    5624         945 :                         nSampleCount += nSampleCount32bit;
    5625         945 :                         nValidCount += nValidCount32bit;
    5626         945 :                         nSum += nSum32bit;
    5627         945 :                         nSumSquare += nSumSquare32bit;
    5628             :                     }
    5629             :                 }
    5630             :             }
    5631             :         }
    5632        3185 :         else if (nMin == 0 && nMax == 255)
    5633             :         {
    5634             :             if constexpr (COMPUTE_OTHER_STATS)
    5635             :             {
    5636             :                 // Optimization when there is no nodata and we know we have already
    5637             :                 // reached the min and max
    5638        2850 :                 for (int iY = 0; iY < nYCheck; iY++)
    5639             :                 {
    5640        2818 :                     int iX = 0;
    5641        5636 :                     for (int k = 0; k < nOuterLoops; k++)
    5642             :                     {
    5643        2818 :                         int iMax = iX + 65536;
    5644        2818 :                         if (iMax > nXCheck)
    5645        2818 :                             iMax = nXCheck;
    5646        2818 :                         GUInt32 nSum32bit = 0;
    5647        2818 :                         GUInt32 nSumSquare32bit = 0;
    5648      177298 :                         for (; iX + 3 < iMax; iX += 4)
    5649             :                         {
    5650      174480 :                             const GPtrDiff_t iOffset =
    5651      174480 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5652      174480 :                             const GUInt32 nValue = pData[iOffset];
    5653      174480 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5654      174480 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5655      174480 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5656      174480 :                             nSum32bit += nValue;
    5657      174480 :                             nSumSquare32bit += nValue * nValue;
    5658      174480 :                             nSum32bit += nValue2;
    5659      174480 :                             nSumSquare32bit += nValue2 * nValue2;
    5660      174480 :                             nSum32bit += nValue3;
    5661      174480 :                             nSumSquare32bit += nValue3 * nValue3;
    5662      174480 :                             nSum32bit += nValue4;
    5663      174480 :                             nSumSquare32bit += nValue4 * nValue4;
    5664             :                         }
    5665        2818 :                         nSum += nSum32bit;
    5666        2818 :                         nSumSquare += nSumSquare32bit;
    5667             :                     }
    5668        2824 :                     for (; iX < nXCheck; ++iX)
    5669             :                     {
    5670           6 :                         const GPtrDiff_t iOffset =
    5671           6 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5672           6 :                         const GUIntBig nValue = pData[iOffset];
    5673           6 :                         nSum += nValue;
    5674           6 :                         nSumSquare += nValue * nValue;
    5675             :                     }
    5676             :                 }
    5677          32 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5678          32 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5679          32 :             }
    5680             :         }
    5681             :         else
    5682             :         {
    5683        8510 :             for (int iY = 0; iY < nYCheck; iY++)
    5684             :             {
    5685        5357 :                 int iX = 0;
    5686       10714 :                 for (int k = 0; k < nOuterLoops; k++)
    5687             :                 {
    5688        5357 :                     int iMax = iX + 65536;
    5689        5357 :                     if (iMax > nXCheck)
    5690        5357 :                         iMax = nXCheck;
    5691        5357 :                     GUInt32 nSum32bit = 0;
    5692        5357 :                     GUInt32 nSumSquare32bit = 0;
    5693      285321 :                     for (; iX + 1 < iMax; iX += 2)
    5694             :                     {
    5695      279964 :                         const GPtrDiff_t iOffset =
    5696      279964 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5697      279964 :                         const GUInt32 nValue = pData[iOffset];
    5698      279964 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5699      279964 :                         if (nValue < nValue2)
    5700             :                         {
    5701        8151 :                             if (nValue < nMin)
    5702         235 :                                 nMin = nValue;
    5703        8151 :                             if (nValue2 > nMax)
    5704         226 :                                 nMax = nValue2;
    5705             :                         }
    5706             :                         else
    5707             :                         {
    5708      271813 :                             if (nValue2 < nMin)
    5709         364 :                                 nMin = nValue2;
    5710      271813 :                             if (nValue > nMax)
    5711         837 :                                 nMax = nValue;
    5712             :                         }
    5713             :                         if constexpr (COMPUTE_OTHER_STATS)
    5714             :                         {
    5715      257626 :                             nSum32bit += nValue;
    5716      257626 :                             nSumSquare32bit += nValue * nValue;
    5717      257626 :                             nSum32bit += nValue2;
    5718      257626 :                             nSumSquare32bit += nValue2 * nValue2;
    5719             :                         }
    5720             :                     }
    5721             :                     if constexpr (COMPUTE_OTHER_STATS)
    5722             :                     {
    5723        2150 :                         nSum += nSum32bit;
    5724        2150 :                         nSumSquare += nSumSquare32bit;
    5725             :                     }
    5726             :                 }
    5727        5357 :                 if (iX < nXCheck)
    5728             :                 {
    5729        1532 :                     const GPtrDiff_t iOffset =
    5730        1532 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5731        1532 :                     const GUInt32 nValue = pData[iOffset];
    5732        1532 :                     if (nValue < nMin)
    5733         117 :                         nMin = nValue;
    5734        1532 :                     if (nValue > nMax)
    5735         101 :                         nMax = nValue;
    5736             :                     if constexpr (COMPUTE_OTHER_STATS)
    5737             :                     {
    5738         321 :                         nSum += nValue;
    5739         321 :                         nSumSquare +=
    5740         321 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5741         321 :                             nValue;
    5742             :                     }
    5743             :                 }
    5744             :             }
    5745             :             if constexpr (COMPUTE_OTHER_STATS)
    5746             :             {
    5747         936 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5748         936 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5749             :             }
    5750             :         }
    5751       13781 :     }
    5752             : };
    5753             : 
    5754             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5755             : {
    5756             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5757             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5758             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5759             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5760             :     {
    5761             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5762             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5763             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5764             :     }
    5765             : };
    5766             : 
    5767             : #if (defined(__x86_64__) || defined(_M_X64) ||                                 \
    5768             :      defined(USE_NEON_OPTIMIZATIONS)) &&                                       \
    5769             :     (defined(__GNUC__) || defined(_MSC_VER))
    5770             : 
    5771             : #include "gdal_avx2_emulation.hpp"
    5772             : 
    5773             : #define ZERO256 GDALmm256_setzero_si256()
    5774             : 
    5775             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5776             : static void
    5777       21346 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5778             :                               // assumed to be aligned on 256 bits
    5779             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5780             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5781             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5782             : {
    5783             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5784             :     GByte
    5785             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5786       21346 :     GByte *paby32ByteAligned =
    5787             :         aby32ByteUnaligned +
    5788       21346 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5789       21346 :     GByte *pabyMin = paby32ByteAligned;
    5790       21346 :     GByte *pabyMax = paby32ByteAligned + 32;
    5791       21346 :     GUInt32 *panSum =
    5792             :         COMPUTE_OTHER_STATS
    5793             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5794             :             : nullptr;
    5795       21346 :     GUInt32 *panSumSquare =
    5796             :         COMPUTE_OTHER_STATS
    5797             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5798             :             : nullptr;
    5799             : 
    5800       21346 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5801             : 
    5802       21346 :     GPtrDiff_t i = 0;
    5803             :     // Make sure that sumSquare can fit on uint32
    5804             :     // * 8 since we can hold 8 sums per vector register
    5805       21346 :     const int nMaxIterationsPerInnerLoop =
    5806             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5807       21346 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5808       21346 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5809       21346 :         nOuterLoops++;
    5810             : 
    5811             :     GDALm256i ymm_min =
    5812       21346 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5813       21346 :     GDALm256i ymm_max = ymm_min;
    5814       21346 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5815             : 
    5816       42692 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5817             :     {
    5818       21346 :         const auto iMax =
    5819       21346 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5820             : 
    5821             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5822       21346 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5823             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5824       21346 :             ZERO256;  // holds 8 uint32 sums
    5825      724785 :         for (; i + 31 < iMax; i += 32)
    5826             :         {
    5827      703439 :             const GDALm256i ymm = GDALmm256_load_si256(
    5828      703439 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5829             :             if (COMPUTE_MIN)
    5830             :             {
    5831      243330 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5832             :             }
    5833             :             if (COMPUTE_MAX)
    5834             :             {
    5835      612140 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5836             :             }
    5837             : 
    5838             :             if constexpr (COMPUTE_OTHER_STATS)
    5839             :             {
    5840             :                 // Extract even-8bit values
    5841             :                 const GDALm256i ymm_even =
    5842      504167 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5843             :                 // Compute square of those 16 values as 32 bit result
    5844             :                 // and add adjacent pairs
    5845             :                 const GDALm256i ymm_even_square =
    5846      504167 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5847             :                 // Add to the sumsquare accumulator
    5848             :                 ymm_sumsquare =
    5849      504167 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5850             : 
    5851             :                 // Extract odd-8bit values
    5852      504167 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5853             :                 const GDALm256i ymm_odd_square =
    5854      504167 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5855             :                 ymm_sumsquare =
    5856      504167 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5857             : 
    5858             :                 // Now compute the sums
    5859      504167 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5860             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5861             :             }
    5862             :         }
    5863             : 
    5864             :         if constexpr (COMPUTE_OTHER_STATS)
    5865             :         {
    5866       10677 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5867             :                                   ymm_sum);
    5868       10677 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5869             :                                   ymm_sumsquare);
    5870             : 
    5871       10677 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5872       10677 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5873       10677 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5874       10677 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5875             :                           panSumSquare[7];
    5876             :         }
    5877             :     }
    5878             : 
    5879             :     if constexpr (COMPUTE_MIN)
    5880             :     {
    5881        8449 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5882             :     }
    5883             :     if constexpr (COMPUTE_MAX)
    5884             :     {
    5885       17334 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5886             :     }
    5887             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5888             :     {
    5889      589281 :         for (int j = 0; j < 32; j++)
    5890             :         {
    5891             :             if constexpr (COMPUTE_MIN)
    5892             :             {
    5893      270368 :                 if (pabyMin[j] < nMin)
    5894        1236 :                     nMin = pabyMin[j];
    5895             :             }
    5896             :             if constexpr (COMPUTE_MAX)
    5897             :             {
    5898      554688 :                 if (pabyMax[j] > nMax)
    5899        1799 :                     nMax = pabyMax[j];
    5900             :             }
    5901             :         }
    5902             :     }
    5903             : 
    5904      234348 :     for (; i < nBlockPixels; i++)
    5905             :     {
    5906      213002 :         const GUInt32 nValue = pData[i];
    5907             :         if constexpr (COMPUTE_MIN)
    5908             :         {
    5909       88326 :             if (nValue < nMin)
    5910           2 :                 nMin = nValue;
    5911             :         }
    5912             :         if constexpr (COMPUTE_MAX)
    5913             :         {
    5914      210227 :             if (nValue > nMax)
    5915        1150 :                 nMax = nValue;
    5916             :         }
    5917             :         if constexpr (COMPUTE_OTHER_STATS)
    5918             :         {
    5919       77203 :             nSum += nValue;
    5920       77203 :             nSumSquare +=
    5921       77203 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5922             :         }
    5923             :     }
    5924             : 
    5925             :     if constexpr (COMPUTE_OTHER_STATS)
    5926             :     {
    5927       10677 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5928       10677 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5929             :     }
    5930       21346 : }
    5931             : 
    5932             : // SSE2/AVX2 optimization for GByte case
    5933             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5934             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5935             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5936             : template <bool COMPUTE_OTHER_STATS>
    5937             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5938             : {
    5939       30296 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5940             :                   // assumed to be aligned on 256 bits
    5941             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5942             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5943             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5944             :                   GUIntBig &nValidCount)
    5945             :     {
    5946       30296 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5947       30296 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5948       11610 :             nMin <= nMax)
    5949             :         {
    5950             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5951             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5952        1492 :             GByte *paby32ByteAligned =
    5953             :                 aby32ByteUnaligned +
    5954        1492 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5955        1492 :             GByte *pabyMin = paby32ByteAligned;
    5956        1492 :             GByte *pabyMax = paby32ByteAligned + 32;
    5957        1492 :             GUInt32 *panSum =
    5958             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5959        1492 :             GUInt32 *panSumSquare =
    5960             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5961             : 
    5962        1492 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5963             : 
    5964        1492 :             GPtrDiff_t i = 0;
    5965             :             // Make sure that sumSquare can fit on uint32
    5966             :             // * 8 since we can hold 8 sums per vector register
    5967        1492 :             const int nMaxIterationsPerInnerLoop =
    5968             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5969        1492 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5970        1492 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5971        1492 :                 nOuterLoops++;
    5972             : 
    5973             :             const GDALm256i ymm_nodata =
    5974        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5975             :             // any non noData value in [min,max] would do.
    5976             :             const GDALm256i ymm_neutral =
    5977        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5978        1492 :             GDALm256i ymm_min = ymm_neutral;
    5979        1492 :             GDALm256i ymm_max = ymm_neutral;
    5980             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5981        1492 :                 GDALmm256_set1_epi16(0xFF);
    5982             : 
    5983        1492 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5984        1492 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5985        1492 :             const bool bComputeMinMax =
    5986        1492 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5987             : 
    5988        2984 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5989             :             {
    5990        1492 :                 const auto iMax =
    5991        1492 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5992             : 
    5993             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5994        1492 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5995             :                 // holds 8 uint32 sums
    5996        1492 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5997             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5998        1492 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5999        1492 :                 const auto iInit = i;
    6000       18982 :                 for (; i + 31 < iMax; i += 32)
    6001             :                 {
    6002       17490 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6003       17490 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6004             : 
    6005             :                     // Check which values are nodata
    6006             :                     const GDALm256i ymm_eq_nodata =
    6007       17490 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    6008             :                     if constexpr (COMPUTE_OTHER_STATS)
    6009             :                     {
    6010             :                         // Count how many values are nodata (due to cmpeq
    6011             :                         // putting 255 when condition is met, this will actually
    6012             :                         // be 255 times the number of nodata value, spread in 4
    6013             :                         // 64 bits words). We can use add_epi32 as the counter
    6014             :                         // will not overflow uint32
    6015        9148 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    6016             :                             ymm_count_nodata_mul_255,
    6017             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    6018             :                     }
    6019             :                     // Replace all nodata values by zero for the purpose of sum
    6020             :                     // and sumquare.
    6021             :                     const GDALm256i ymm_nodata_by_zero =
    6022       17490 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    6023       17490 :                     if (bComputeMinMax)
    6024             :                     {
    6025             :                         // Replace all nodata values by a neutral value for the
    6026             :                         // purpose of min and max.
    6027             :                         const GDALm256i ymm_nodata_by_neutral =
    6028        8720 :                             GDALmm256_or_si256(
    6029             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    6030             :                                 ymm_nodata_by_zero);
    6031             : 
    6032             :                         ymm_min =
    6033        8720 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    6034             :                         ymm_max =
    6035        8720 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    6036             :                     }
    6037             : 
    6038             :                     if constexpr (COMPUTE_OTHER_STATS)
    6039             :                     {
    6040             :                         // Extract even-8bit values
    6041        9148 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    6042             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    6043             :                         // Compute square of those 16 values as 32 bit result
    6044             :                         // and add adjacent pairs
    6045             :                         const GDALm256i ymm_even_square =
    6046        9148 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    6047             :                         // Add to the sumsquare accumulator
    6048             :                         ymm_sumsquare =
    6049        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    6050             : 
    6051             :                         // Extract odd-8bit values
    6052             :                         const GDALm256i ymm_odd =
    6053        9148 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    6054             :                         const GDALm256i ymm_odd_square =
    6055        9148 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    6056             :                         ymm_sumsquare =
    6057        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    6058             : 
    6059             :                         // Now compute the sums
    6060        9148 :                         ymm_sum = GDALmm256_add_epi32(
    6061             :                             ymm_sum,
    6062             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    6063             :                     }
    6064             :                 }
    6065             : 
    6066             :                 if constexpr (COMPUTE_OTHER_STATS)
    6067             :                 {
    6068         186 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    6069         186 :                     GDALmm256_store_si256(
    6070             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    6071             :                         ymm_count_nodata_mul_255);
    6072             : 
    6073         186 :                     nSampleCount += (i - iInit);
    6074             : 
    6075         186 :                     nValidCount +=
    6076         186 :                         (i - iInit) -
    6077         186 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    6078         186 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    6079             :                             255;
    6080             : 
    6081         186 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    6082             :                                           ymm_sum);
    6083         186 :                     GDALmm256_store_si256(
    6084             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    6085             :                         ymm_sumsquare);
    6086         186 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    6087         186 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    6088         186 :                                   panSumSquare[1] + panSumSquare[2] +
    6089         186 :                                   panSumSquare[3] + panSumSquare[4] +
    6090         186 :                                   panSumSquare[5] + panSumSquare[6] +
    6091             :                                   panSumSquare[7];
    6092             :                 }
    6093             :             }
    6094             : 
    6095        1492 :             if (bComputeMinMax)
    6096             :             {
    6097        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    6098             :                                       ymm_min);
    6099        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    6100             :                                       ymm_max);
    6101       47190 :                 for (int j = 0; j < 32; j++)
    6102             :                 {
    6103       45760 :                     if (pabyMin[j] < nMin)
    6104          40 :                         nMin = pabyMin[j];
    6105       45760 :                     if (pabyMax[j] > nMax)
    6106         161 :                         nMax = pabyMax[j];
    6107             :                 }
    6108             :             }
    6109             : 
    6110             :             if constexpr (COMPUTE_OTHER_STATS)
    6111             :             {
    6112         186 :                 nSampleCount += nBlockPixels - i;
    6113             :             }
    6114       34048 :             for (; i < nBlockPixels; i++)
    6115             :             {
    6116       32556 :                 const GUInt32 nValue = pData[i];
    6117       32556 :                 if (nValue == nNoDataValue)
    6118       24923 :                     continue;
    6119        7633 :                 if (nValue < nMin)
    6120           2 :                     nMin = nValue;
    6121        7633 :                 if (nValue > nMax)
    6122          14 :                     nMax = nValue;
    6123             :                 if constexpr (COMPUTE_OTHER_STATS)
    6124             :                 {
    6125        3700 :                     nValidCount++;
    6126        3700 :                     nSum += nValue;
    6127        3700 :                     nSumSquare +=
    6128        3700 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6129        3700 :                         nValue;
    6130             :                 }
    6131        1492 :             }
    6132             :         }
    6133       28804 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    6134             :         {
    6135       14990 :             if (nMin > 0)
    6136             :             {
    6137        2093 :                 if (nMax < 255)
    6138             :                 {
    6139             :                     ComputeStatisticsByteNoNodata<true, true,
    6140        1570 :                                                   COMPUTE_OTHER_STATS>(
    6141             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6142             :                         nSampleCount, nValidCount);
    6143             :                 }
    6144             :                 else
    6145             :                 {
    6146             :                     ComputeStatisticsByteNoNodata<true, false,
    6147         523 :                                                   COMPUTE_OTHER_STATS>(
    6148             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6149             :                         nSampleCount, nValidCount);
    6150             :                 }
    6151             :             }
    6152             :             else
    6153             :             {
    6154       12897 :                 if (nMax < 255)
    6155             :                 {
    6156             :                     ComputeStatisticsByteNoNodata<false, true,
    6157        9408 :                                                   COMPUTE_OTHER_STATS>(
    6158             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6159             :                         nSampleCount, nValidCount);
    6160             :                 }
    6161             :                 else
    6162             :                 {
    6163             :                     ComputeStatisticsByteNoNodata<false, false,
    6164        3489 :                                                   COMPUTE_OTHER_STATS>(
    6165             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6166             :                         nSampleCount, nValidCount);
    6167             :                 }
    6168             :             }
    6169             :         }
    6170       12516 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    6171          33 :                  (nBlockXSize % 32) == 0)
    6172             :         {
    6173        6389 :             for (int iY = 0; iY < nYCheck; iY++)
    6174             :             {
    6175        6356 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    6176        6356 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    6177             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6178          33 :             }
    6179             :         }
    6180             :         else
    6181             :         {
    6182       13781 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    6183             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6184             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6185             :         }
    6186       30296 :     }
    6187             : };
    6188             : 
    6189             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    6190         570 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    6191             :                              GUIntBig i)
    6192             : {
    6193         570 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    6194         570 : }
    6195             : 
    6196             : // AVX2/SSE2 optimization for GUInt16 case
    6197             : template <bool COMPUTE_OTHER_STATS>
    6198             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    6199             : {
    6200        2099 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    6201             :                   // assumed to be aligned on 128 bits
    6202             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    6203             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    6204             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    6205             :                   GUIntBig &nValidCount)
    6206             :     {
    6207        2099 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    6208        2099 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    6209             :         {
    6210        1844 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    6211             : 
    6212        1844 :             GPtrDiff_t i = 0;
    6213             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    6214             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    6215             :             // Furthermore the shift is also needed to use madd_epi16
    6216        1844 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    6217        1844 :             GDALm256i ymm_min = GDALmm256_load_si256(
    6218        1844 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6219        1844 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6220        1844 :             GDALm256i ymm_max = ymm_min;
    6221             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6222        1844 :                 ZERO256;  // holds 4 uint64 sums
    6223             : 
    6224             :             // Make sure that sum can fit on uint32
    6225             :             // * 8 since we can hold 8 sums per vector register
    6226        1844 :             const int nMaxIterationsPerInnerLoop =
    6227             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6228        1844 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6229        1844 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6230        1844 :                 nOuterLoops++;
    6231             : 
    6232        1844 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6233             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6234        1844 :                 GDALmm256_set1_epi32(0xFFFF);
    6235             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6236        1844 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6237             : 
    6238        1844 :             GUIntBig nSumThis = 0;
    6239        3712 :             for (int k = 0; k < nOuterLoops; k++)
    6240             :             {
    6241        1868 :                 const auto iMax =
    6242        1868 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6243             : 
    6244             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6245        1868 :                     ZERO256;  // holds 8 uint32 sums
    6246     1057198 :                 for (; i + 15 < iMax; i += 16)
    6247             :                 {
    6248     1055330 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6249     1055330 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6250             :                     const GDALm256i ymm_shifted =
    6251     1055330 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6252     1055330 :                     if (bComputeMinMax)
    6253             :                     {
    6254     1037292 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6255     1037292 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6256             :                     }
    6257             : 
    6258             :                     if constexpr (COMPUTE_OTHER_STATS)
    6259             :                     {
    6260             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6261             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6262             :                         // is positive, this is OK as we interpret is a uint32.
    6263             :                         const GDALm256i ymm_square =
    6264      188312 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6265      188312 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6266             :                             ymm_sumsquare,
    6267             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6268      188312 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6269             :                             ymm_sumsquare,
    6270             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6271             : 
    6272             :                         // Now compute the sums
    6273      188312 :                         ymm_sum = GDALmm256_add_epi32(
    6274             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6275      188312 :                         ymm_sum = GDALmm256_add_epi32(
    6276             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6277             :                     }
    6278             :                 }
    6279             : 
    6280             :                 if constexpr (COMPUTE_OTHER_STATS)
    6281             :                 {
    6282             :                     GUInt32 anSum[8];
    6283         570 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6284             :                                            ymm_sum);
    6285         570 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6286         570 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6287         570 :                                 anSum[6] + anSum[7];
    6288             :                 }
    6289             :             }
    6290             : 
    6291        1844 :             if (bComputeMinMax)
    6292             :             {
    6293             :                 GUInt16 anMin[16];
    6294             :                 GUInt16 anMax[16];
    6295             : 
    6296             :                 // Unshift the result
    6297        1762 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6298        1762 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6299        1762 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6300             :                                        ymm_min);
    6301        1762 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6302             :                                        ymm_max);
    6303       29954 :                 for (int j = 0; j < 16; j++)
    6304             :                 {
    6305       28192 :                     if (anMin[j] < nMin)
    6306         389 :                         nMin = anMin[j];
    6307       28192 :                     if (anMax[j] > nMax)
    6308         567 :                         nMax = anMax[j];
    6309             :                 }
    6310             :             }
    6311             : 
    6312             :             if constexpr (COMPUTE_OTHER_STATS)
    6313             :             {
    6314             :                 GUIntBig anSumSquare[4];
    6315         570 :                 GDALmm256_storeu_si256(
    6316             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6317         570 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6318             :                               anSumSquare[3];
    6319             : 
    6320             :                 // Unshift the sum of squares
    6321         570 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6322             :                                  static_cast<GUIntBig>(i));
    6323             : 
    6324         570 :                 nSum += nSumThis;
    6325             : 
    6326        1014 :                 for (; i < nBlockPixels; i++)
    6327             :                 {
    6328         444 :                     const GUInt32 nValue = pData[i];
    6329         444 :                     if (nValue < nMin)
    6330           2 :                         nMin = nValue;
    6331         444 :                     if (nValue > nMax)
    6332           2 :                         nMax = nValue;
    6333         444 :                     nSum += nValue;
    6334         444 :                     nSumSquare +=
    6335         444 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6336         444 :                         nValue;
    6337             :                 }
    6338             : 
    6339         570 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6340         570 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6341        1844 :             }
    6342             :         }
    6343             :         else
    6344             :         {
    6345         255 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6346             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6347             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6348             :         }
    6349        2099 :     }
    6350             : };
    6351             : 
    6352             : #endif
    6353             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6354             : // defined(_MSC_VER))
    6355             : 
    6356             : /************************************************************************/
    6357             : /*                           GetPixelValue()                            */
    6358             : /************************************************************************/
    6359             : 
    6360    15872100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6361             :                                    const void *pData, GPtrDiff_t iOffset,
    6362             :                                    const GDALNoDataValues &sNoDataValues,
    6363             :                                    bool &bValid)
    6364             : {
    6365    15872100 :     bValid = true;
    6366    15872100 :     double dfValue = 0;
    6367    15872100 :     switch (eDataType)
    6368             :     {
    6369     1400770 :         case GDT_UInt8:
    6370             :         {
    6371     1400770 :             if (bSignedByte)
    6372         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6373             :             else
    6374     1400580 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6375     1400770 :             break;
    6376             :         }
    6377         641 :         case GDT_Int8:
    6378         641 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6379         641 :             break;
    6380      200608 :         case GDT_UInt16:
    6381      200608 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6382      200608 :             break;
    6383       54248 :         case GDT_Int16:
    6384       54248 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6385       54248 :             break;
    6386       10478 :         case GDT_UInt32:
    6387       10478 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6388       10478 :             break;
    6389      140132 :         case GDT_Int32:
    6390      140132 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6391      140132 :             break;
    6392          60 :         case GDT_UInt64:
    6393          60 :             dfValue = static_cast<double>(
    6394          60 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6395          60 :             break;
    6396        3268 :         case GDT_Int64:
    6397        3268 :             dfValue = static_cast<double>(
    6398        3268 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6399        3268 :             break;
    6400          40 :         case GDT_Float16:
    6401             :         {
    6402             :             using namespace std;
    6403          40 :             const GFloat16 hfValue =
    6404          40 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6405          74 :             if (isnan(hfValue) ||
    6406          34 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6407          28 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6408             :             {
    6409           6 :                 bValid = false;
    6410           6 :                 return 0.0;
    6411             :             }
    6412          34 :             dfValue = hfValue;
    6413          34 :             return dfValue;
    6414             :         }
    6415    13643900 :         case GDT_Float32:
    6416             :         {
    6417    13643900 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6418    27260900 :             if (std::isnan(fValue) ||
    6419    26885800 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6420    13268800 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6421             :             {
    6422       26883 :                 bValid = false;
    6423       26883 :                 return 0.0;
    6424             :             }
    6425    13617000 :             dfValue = double(fValue);
    6426    13617000 :             return dfValue;
    6427             :         }
    6428      400868 :         case GDT_Float64:
    6429      400868 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6430      400868 :             if (std::isnan(dfValue))
    6431             :             {
    6432           6 :                 bValid = false;
    6433           6 :                 return 0.0;
    6434             :             }
    6435      400862 :             break;
    6436        2692 :         case GDT_CInt16:
    6437        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6438        2692 :             break;
    6439        2692 :         case GDT_CInt32:
    6440        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6441        2692 :             break;
    6442           0 :         case GDT_CFloat16:
    6443           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6444           0 :             if (std::isnan(dfValue))
    6445             :             {
    6446           0 :                 bValid = false;
    6447           0 :                 return 0.0;
    6448             :             }
    6449           0 :             break;
    6450        5812 :         case GDT_CFloat32:
    6451        5812 :             dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
    6452        5812 :             if (std::isnan(dfValue))
    6453             :             {
    6454           0 :                 bValid = false;
    6455           0 :                 return 0.0;
    6456             :             }
    6457        5812 :             break;
    6458        5892 :         case GDT_CFloat64:
    6459        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6460        5892 :             if (std::isnan(dfValue))
    6461             :             {
    6462           0 :                 bValid = false;
    6463           0 :                 return 0.0;
    6464             :             }
    6465        5892 :             break;
    6466           0 :         case GDT_Unknown:
    6467             :         case GDT_TypeCount:
    6468           0 :             CPLAssert(false);
    6469             :             break;
    6470             :     }
    6471             : 
    6472     2483320 :     if (sNoDataValues.bGotNoDataValue &&
    6473      255165 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6474             :     {
    6475        4222 :         bValid = false;
    6476        4222 :         return 0.0;
    6477             :     }
    6478     2223930 :     return dfValue;
    6479             : }
    6480             : 
    6481             : /************************************************************************/
    6482             : /*                          SetValidPercent()                           */
    6483             : /************************************************************************/
    6484             : 
    6485             : //! @cond Doxygen_Suppress
    6486             : /**
    6487             :  * \brief Set percentage of valid (not nodata) pixels.
    6488             :  *
    6489             :  * Stores the percentage of valid pixels in the metadata item
    6490             :  * STATISTICS_VALID_PERCENT
    6491             :  *
    6492             :  * @param nSampleCount Number of sampled pixels.
    6493             :  *
    6494             :  * @param nValidCount Number of valid pixels.
    6495             :  */
    6496             : 
    6497         595 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6498             :                                      GUIntBig nValidCount)
    6499             : {
    6500         595 :     if (nValidCount == 0)
    6501             :     {
    6502          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6503             :     }
    6504         583 :     else if (nValidCount == nSampleCount)
    6505             :     {
    6506         491 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6507             :     }
    6508             :     else /* nValidCount < nSampleCount */
    6509             :     {
    6510          92 :         char szValue[128] = {0};
    6511             : 
    6512             :         /* percentage is only an indicator: limit precision */
    6513          92 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6514          92 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6515             : 
    6516          92 :         if (EQUAL(szValue, "100"))
    6517             :         {
    6518             :             /* don't set 100 percent valid
    6519             :              * because some of the sampled pixels were nodata */
    6520           4 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6521             :         }
    6522             :         else
    6523             :         {
    6524          88 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6525             :         }
    6526             :     }
    6527         595 : }
    6528             : 
    6529             : //! @endcond
    6530             : 
    6531             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6532             : 
    6533             : #ifdef __AVX2__
    6534             : 
    6535             : #define set1_ps _mm256_set1_ps
    6536             : #define loadu_ps _mm256_loadu_ps
    6537             : #define or_ps _mm256_or_ps
    6538             : #define min_ps _mm256_min_ps
    6539             : #define max_ps _mm256_max_ps
    6540             : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
    6541             : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
    6542             : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
    6543             : #define movemask_ps _mm256_movemask_ps
    6544             : #define storeu_ps _mm256_storeu_ps
    6545             : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
    6546             : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
    6547             : 
    6548             : #define unpacklo_ps _mm256_unpacklo_ps
    6549             : #define castps_pd _mm256_castps_pd
    6550             : 
    6551             : inline __m256 dup_hi_ps(__m256 x)
    6552             : {
    6553             :     const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
    6554             :     return _mm256_permutevar8x32_ps(x, idx);
    6555             : }
    6556             : 
    6557             : #define setzero_pd _mm256_setzero_pd
    6558             : #define set1_pd _mm256_set1_pd
    6559             : #define loadu_pd _mm256_loadu_pd
    6560             : #define or_pd _mm256_or_pd
    6561             : #define min_pd _mm256_min_pd
    6562             : #define max_pd _mm256_max_pd
    6563             : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
    6564             : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
    6565             : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
    6566             : #define movemask_pd _mm256_movemask_pd
    6567             : #define add_pd _mm256_add_pd
    6568             : #define sub_pd _mm256_sub_pd
    6569             : #define mul_pd _mm256_mul_pd
    6570             : #define div_pd _mm256_div_pd
    6571             : #define storeu_pd _mm256_storeu_pd
    6572             : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
    6573             : #define blendv_pd _mm256_blendv_pd
    6574             : #ifdef __FMA__
    6575             : #define fmadd_pd _mm256_fmadd_pd
    6576             : #else
    6577             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6578             : #endif
    6579             : 
    6580             : #else
    6581             : 
    6582             : #define set1_ps _mm_set1_ps
    6583             : #define loadu_ps _mm_loadu_ps
    6584             : #define or_ps _mm_or_ps
    6585             : #define min_ps _mm_min_ps
    6586             : #define max_ps _mm_max_ps
    6587             : #define cmpeq_ps _mm_cmpeq_ps
    6588             : #define cmpneq_ps _mm_cmpneq_ps
    6589             : #define cmpunord_ps _mm_cmpunord_ps
    6590             : #define movemask_ps _mm_movemask_ps
    6591             : #define storeu_ps _mm_storeu_ps
    6592             : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
    6593             : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
    6594             : #define unpacklo_ps _mm_unpacklo_ps
    6595             : #define castps_pd _mm_castps_pd
    6596             : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
    6597             : 
    6598             : #define setzero_pd _mm_setzero_pd
    6599             : #define set1_pd _mm_set1_pd
    6600             : #define loadu_pd _mm_loadu_pd
    6601             : #define or_pd _mm_or_pd
    6602             : #define min_pd _mm_min_pd
    6603             : #define max_pd _mm_max_pd
    6604             : #define cmpeq_pd _mm_cmpeq_pd
    6605             : #define cmpneq_pd _mm_cmpneq_pd
    6606             : #define cmpunord_pd _mm_cmpunord_pd
    6607             : #define movemask_pd _mm_movemask_pd
    6608             : #define add_pd _mm_add_pd
    6609             : #define sub_pd _mm_sub_pd
    6610             : #define mul_pd _mm_mul_pd
    6611             : #define div_pd _mm_div_pd
    6612             : #define storeu_pd _mm_storeu_pd
    6613             : #define cvtsd_f64 _mm_cvtsd_f64
    6614             : #ifdef __FMA__
    6615             : #define fmadd_pd _mm_fmadd_pd
    6616             : #else
    6617             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6618             : #endif
    6619             : 
    6620     4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
    6621             : {
    6622             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
    6623             :     return _mm_blendv_pd(a, b, mask);
    6624             : #else
    6625    12898000 :     return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
    6626             : #endif
    6627             : }
    6628             : #endif
    6629             : 
    6630             : #define dup_lo_ps(x) unpacklo_ps((x), (x))
    6631             : 
    6632             : /************************************************************************/
    6633             : /*                   ComputeStatisticsFloat32_SSE2()                    */
    6634             : /************************************************************************/
    6635             : 
    6636             : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6637             : #if defined(__GNUC__)
    6638             : __attribute__((noinline))
    6639             : #endif
    6640             : static int
    6641        8330 : ComputeStatisticsFloat32_SSE2(const float *const pafData,
    6642             :                               [[maybe_unused]] float fNoDataValue, int iX,
    6643             :                               int nCount, float &fMin, float &fMax,
    6644             :                               double &dfBlockMean, double &dfBlockM2,
    6645             :                               double &dfBlockValidCount)
    6646             : {
    6647        8330 :     auto vValidCount = setzero_pd();
    6648        8330 :     const auto vOne = set1_pd(1);
    6649        8330 :     [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
    6650             : 
    6651        8330 :     auto vMin = set1_ps(fMin);
    6652       16660 :     auto vMax = set1_ps(fMax);
    6653             : 
    6654        8330 :     auto vMean_lo = setzero_pd();
    6655        8330 :     auto vM2_lo = setzero_pd();
    6656             : 
    6657        8330 :     auto vMean_hi = setzero_pd();
    6658        8330 :     auto vM2_hi = setzero_pd();
    6659             : 
    6660        8330 :     constexpr int VALS_PER_LOOP =
    6661             :         static_cast<int>(sizeof(vOne) / sizeof(float));
    6662     1258087 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6663             :     {
    6664     2499510 :         const auto vValues = loadu_ps(pafData + iX);
    6665             : 
    6666             :         if constexpr (HAS_NAN)
    6667             :         {
    6668     1236117 :             auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
    6669             :             if constexpr (HAS_NODATA)
    6670             :             {
    6671             :                 isNaNOrNoData =
    6672           0 :                     or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
    6673             :             }
    6674     1236117 :             if (movemask_ps(isNaNOrNoData))
    6675             :             {
    6676           1 :                 break;
    6677             :             }
    6678             :         }
    6679             :         else if constexpr (HAS_NODATA)
    6680             :         {
    6681           0 :             if (movemask_ps(cmpeq_ps(vValues, vNoData)))
    6682             :             {
    6683           0 :                 break;
    6684             :             }
    6685             :         }
    6686             : 
    6687     1249754 :         vMin = min_ps(vMin, vValues);
    6688     1249754 :         vMax = max_ps(vMax, vValues);
    6689             : 
    6690     1249754 :         const auto vValues_lo = cvtps_lo_pd(vValues);
    6691     2499508 :         const auto vValues_hi = cvtps_hi_pd(vValues);
    6692     1249754 :         [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
    6693             : 
    6694     1249754 :         vValidCount = add_pd(vValidCount, vOne);
    6695     1249754 :         const auto vInvValidCount = div_pd(vOne, vValidCount);
    6696             : 
    6697     1249754 :         const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
    6698     2298362 :         const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
    6699             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6700             :         {
    6701             :             const auto vMinNotSameAsMax_lo =
    6702     1048608 :                 castps_pd(dup_lo_ps(vMinNotSameAsMax));
    6703     1048608 :             vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6704             :             const auto vNewM2_lo =
    6705     2097216 :                 fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6706     1048608 :             vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6707             :         }
    6708             :         else
    6709             :         {
    6710      201146 :             vMean_lo = vNewMean_lo;
    6711      603438 :             vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6712             :         }
    6713             : 
    6714     1249754 :         const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
    6715     2298362 :         const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
    6716             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6717             :         {
    6718             :             const auto vMinNotSameAsMax_hi =
    6719     1048608 :                 castps_pd(dup_hi_ps(vMinNotSameAsMax));
    6720     1048608 :             vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6721             :             const auto vNewM2_hi =
    6722     2097216 :                 fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6723     1048608 :             vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6724             :         }
    6725             :         else
    6726             :         {
    6727      201146 :             vMean_hi = vNewMean_hi;
    6728      603438 :             vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6729             :         }
    6730             :     }
    6731        8330 :     const double dfValidVectorCount = cvtsd_f64(vValidCount);
    6732        8330 :     if (dfValidVectorCount > 0)
    6733             :     {
    6734             :         float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
    6735             :         storeu_ps(afMin, vMin);
    6736             :         storeu_ps(afMax, vMax);
    6737       39955 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6738             :         {
    6739       31964 :             fMin = std::min(fMin, afMin[i]);
    6740       31964 :             fMax = std::max(fMax, afMax[i]);
    6741             :         }
    6742             : 
    6743             :         double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
    6744             :         storeu_pd(adfMean, vMean_lo);
    6745             :         storeu_pd(adfM2, vM2_lo);
    6746        7991 :         storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
    6747        7991 :         storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
    6748       39955 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6749             :         {
    6750       31964 :             const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
    6751       31964 :             dfBlockM2 += adfM2[i];
    6752       31964 :             if (adfMean[i] != dfBlockMean)
    6753             :             {
    6754       13172 :                 const double dfDelta = adfMean[i] - dfBlockMean;
    6755       13172 :                 dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
    6756       13172 :                 dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
    6757       13172 :                              dfValidVectorCount / dfNewValidCount;
    6758             :             }
    6759       31964 :             dfBlockValidCount = dfNewValidCount;
    6760             :         }
    6761             :     }
    6762             : 
    6763        8330 :     return iX;
    6764             : }
    6765             : 
    6766             : /************************************************************************/
    6767             : /*                   ComputeStatisticsFloat64_SSE2()                    */
    6768             : /************************************************************************/
    6769             : 
    6770             : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6771             : #if defined(__GNUC__)
    6772             : __attribute__((noinline))
    6773             : #endif
    6774             : static int
    6775        2367 : ComputeStatisticsFloat64_SSE2(const double *padfData,
    6776             :                               [[maybe_unused]] double dfNoDataValue, int iX,
    6777             :                               int nCount, double &dfMin, double &dfMax,
    6778             :                               double &dfBlockMean, double &dfBlockM2,
    6779             :                               double &dfBlockValidCount)
    6780             : {
    6781        2367 :     auto vValidCount = setzero_pd();
    6782        2367 :     const auto vOne = set1_pd(1);
    6783        2367 :     [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
    6784             : 
    6785        2367 :     auto vMin_lo = set1_pd(dfMin);
    6786        4734 :     auto vMax_lo = set1_pd(dfMax);
    6787        2367 :     auto vMean_lo = setzero_pd();
    6788        2367 :     auto vM2_lo = setzero_pd();
    6789             : 
    6790        2367 :     auto vMin_hi = vMin_lo;
    6791        2367 :     auto vMax_hi = vMax_lo;
    6792        2367 :     auto vMean_hi = setzero_pd();
    6793        2367 :     auto vM2_hi = setzero_pd();
    6794             : 
    6795        2367 :     constexpr int VALS_PER_LOOP =
    6796             :         2 * static_cast<int>(sizeof(vOne) / sizeof(double));
    6797      107199 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6798             :     {
    6799      104875 :         const auto vValues_lo = loadu_pd(padfData + iX);
    6800      209750 :         const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
    6801             :         // Check if there's at least one NaN in both vectors
    6802      104875 :         auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
    6803             :         if constexpr (HAS_NODATA)
    6804             :         {
    6805             :             isNaNOrNoData =
    6806      103248 :                 or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
    6807             :                                            cmpeq_pd(vValues_hi, vNoData)));
    6808             :         }
    6809      104875 :         if (movemask_pd(isNaNOrNoData))
    6810             :         {
    6811          43 :             break;
    6812             :         }
    6813             : 
    6814      104832 :         vValidCount = add_pd(vValidCount, vOne);
    6815      104832 :         const auto vInvValidCount = div_pd(vOne, vValidCount);
    6816             : 
    6817      104832 :         vMin_lo = min_pd(vMin_lo, vValues_lo);
    6818      104832 :         vMax_lo = max_pd(vMax_lo, vValues_lo);
    6819      104832 :         const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
    6820      131060 :         const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
    6821             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6822             :         {
    6823       26228 :             const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
    6824       26228 :             vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6825             :             const auto vNewM2_lo =
    6826       52456 :                 fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6827       26228 :             vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6828             :         }
    6829             :         else
    6830             :         {
    6831       78604 :             vMean_lo = vNewMean_lo;
    6832      235812 :             vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6833             :         }
    6834             : 
    6835      104832 :         vMin_hi = min_pd(vMin_hi, vValues_hi);
    6836      104832 :         vMax_hi = max_pd(vMax_hi, vValues_hi);
    6837      104832 :         const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
    6838      131060 :         const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
    6839             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6840             :         {
    6841       26228 :             const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
    6842       26228 :             vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6843             :             const auto vNewM2_hi =
    6844       52456 :                 fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6845       26228 :             vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6846             :         }
    6847             :         else
    6848             :         {
    6849       78604 :             vMean_hi = vNewMean_hi;
    6850      235812 :             vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6851             :         }
    6852             :     }
    6853        2367 :     const double dfValidVectorCount = cvtsd_f64(vValidCount);
    6854        2367 :     if (dfValidVectorCount > 0)
    6855             :     {
    6856             :         double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
    6857             :             adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
    6858             :         storeu_pd(adfMin, vMin_lo);
    6859             :         storeu_pd(adfMax, vMax_lo);
    6860             :         storeu_pd(adfMean, vMean_lo);
    6861             :         storeu_pd(adfM2, vM2_lo);
    6862        1801 :         storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
    6863        1801 :         storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
    6864        1801 :         storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
    6865        1801 :         storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
    6866             : 
    6867        9005 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6868             :         {
    6869        7204 :             dfMin = std::min(dfMin, adfMin[i]);
    6870        7204 :             dfMax = std::max(dfMax, adfMax[i]);
    6871        7204 :             const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
    6872        7204 :             dfBlockM2 += adfM2[i];
    6873        7204 :             if (adfMean[i] != dfBlockMean)
    6874             :             {
    6875        5871 :                 const double dfDelta = adfMean[i] - dfBlockMean;
    6876        5871 :                 dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
    6877        5871 :                 dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
    6878        5871 :                              dfValidVectorCount / dfNewValidCount;
    6879             :             }
    6880        7204 :             dfBlockValidCount = dfNewValidCount;
    6881             :         }
    6882             :     }
    6883             : 
    6884        2367 :     return iX;
    6885             : }
    6886             : 
    6887             : #endif
    6888             : 
    6889             : /************************************************************************/
    6890             : /*                   ComputeBlockStatisticsFloat32()                    */
    6891             : /************************************************************************/
    6892             : 
    6893             : template <bool HAS_NAN, bool HAS_NODATA>
    6894        4733 : static void ComputeBlockStatisticsFloat32(
    6895             :     const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
    6896             :     const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
    6897             :     float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
    6898             :     double &dfBlockValidCountInOut)
    6899             : {
    6900        4733 :     float fMin = fMinInOut;
    6901        4733 :     float fMax = fMaxInOut;
    6902        4733 :     double dfBlockMean = dfBlockMeanInOut;
    6903        4733 :     double dfBlockM2 = dfBlockM2InOut;
    6904        4733 :     double dfBlockValidCount = dfBlockValidCountInOut;
    6905             : 
    6906       13063 :     for (int iY = 0; iY < nYCheck; iY++)
    6907             :     {
    6908        8330 :         const int iOffset = iY * nBlockXSize;
    6909        8330 :         if (dfBlockValidCount > 0 && fMin != fMax)
    6910             :         {
    6911        3470 :             int iX = 0;
    6912             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6913             :             iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
    6914             :                                                /* bCheckMinEqMax = */ false,
    6915        3470 :                                                HAS_NODATA>(
    6916        3470 :                 pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
    6917             :                 fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    6918             : #endif
    6919        4011 :             for (; iX < nXCheck; iX++)
    6920             :             {
    6921         541 :                 const float fValue = pafSrcData[iOffset + iX];
    6922             :                 if constexpr (HAS_NAN)
    6923             :                 {
    6924         535 :                     if (std::isnan(fValue))
    6925          13 :                         continue;
    6926             :                 }
    6927             :                 if constexpr (HAS_NODATA)
    6928             :                 {
    6929           6 :                     if (fValue == sNoDataValues.fNoDataValue)
    6930           1 :                         continue;
    6931             :                 }
    6932         527 :                 fMin = std::min(fMin, fValue);
    6933         527 :                 fMax = std::max(fMax, fValue);
    6934         527 :                 dfBlockValidCount += 1.0;
    6935         527 :                 const double dfValue = static_cast<double>(fValue);
    6936         527 :                 const double dfDelta = dfValue - dfBlockMean;
    6937         527 :                 dfBlockMean += dfDelta / dfBlockValidCount;
    6938         527 :                 dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    6939        3470 :             }
    6940             :         }
    6941             :         else
    6942             :         {
    6943        4860 :             int iX = 0;
    6944        4860 :             if (dfBlockValidCount == 0)
    6945             :             {
    6946        4734 :                 while (iX < nXCheck)
    6947             :                 {
    6948        4734 :                     const float fValue = pafSrcData[iOffset + iX];
    6949        4734 :                     ++iX;
    6950             :                     if constexpr (HAS_NAN)
    6951             :                     {
    6952        2340 :                         if (std::isnan(fValue))
    6953           0 :                             continue;
    6954             :                     }
    6955             :                     if constexpr (HAS_NODATA)
    6956             :                     {
    6957           9 :                         if (fValue == sNoDataValues.fNoDataValue)
    6958           1 :                             continue;
    6959             :                     }
    6960        4733 :                     fMin = std::min(fMin, fValue);
    6961        4733 :                     fMax = std::max(fMax, fValue);
    6962        4733 :                     dfBlockValidCount = 1;
    6963        4733 :                     dfBlockMean = static_cast<double>(fValue);
    6964        4733 :                     break;
    6965             :                 }
    6966             :             }
    6967             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6968             :             iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
    6969             :                                                /* bCheckMinEqMax = */ true,
    6970        4860 :                                                HAS_NODATA>(
    6971        4860 :                 pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
    6972             :                 fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    6973             : #endif
    6974       14998 :             for (; iX < nXCheck; iX++)
    6975             :             {
    6976       10138 :                 const float fValue = pafSrcData[iOffset + iX];
    6977             :                 if constexpr (HAS_NAN)
    6978             :                 {
    6979        6877 :                     if (std::isnan(fValue))
    6980           7 :                         continue;
    6981             :                 }
    6982             :                 if constexpr (HAS_NODATA)
    6983             :                 {
    6984          13 :                     if (fValue == sNoDataValues.fNoDataValue)
    6985           3 :                         continue;
    6986             :                 }
    6987       10128 :                 fMin = std::min(fMin, fValue);
    6988       10128 :                 fMax = std::max(fMax, fValue);
    6989       10128 :                 dfBlockValidCount += 1.0;
    6990       10128 :                 if (fMin != fMax)
    6991             :                 {
    6992        3263 :                     const double dfValue = static_cast<double>(fValue);
    6993        3263 :                     const double dfDelta = dfValue - dfBlockMean;
    6994        3263 :                     dfBlockMean += dfDelta / dfBlockValidCount;
    6995        3263 :                     dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    6996             :                 }
    6997             :             }
    6998             :         }
    6999             :     }
    7000             : 
    7001        4733 :     fMinInOut = fMin;
    7002        4733 :     fMaxInOut = fMax;
    7003        4733 :     dfBlockMeanInOut = dfBlockMean;
    7004        4733 :     dfBlockM2InOut = dfBlockM2;
    7005        4733 :     dfBlockValidCountInOut = dfBlockValidCount;
    7006        4733 : }
    7007             : 
    7008             : /************************************************************************/
    7009             : /*                        StatisticsTaskFloat32                         */
    7010             : /************************************************************************/
    7011             : 
    7012             : namespace
    7013             : {
    7014             : struct StatisticsTaskFloat32
    7015             : {
    7016             :     double dfBlockMean = 0;
    7017             :     double dfBlockM2 = 0;
    7018             :     double dfBlockValidCount = 0;
    7019             :     GDALDataType eDataType = GDT_Unknown;
    7020             :     bool bHasNoData = false;
    7021             :     GDALNoDataValues *psNoDataValues = nullptr;
    7022             :     const float *pafSrcData = nullptr;
    7023             :     float fMin = std::numeric_limits<float>::infinity();
    7024             :     float fMax = -std::numeric_limits<float>::infinity();
    7025             :     int nChunkXSize = 0;
    7026             :     int nXCheck = 0;
    7027             :     int nYCheck = 0;
    7028             : 
    7029        4733 :     void Perform()
    7030             :     {
    7031        4733 :         if (GDALDataTypeIsInteger(eDataType))
    7032             :         {
    7033        2393 :             if (bHasNoData)
    7034             :             {
    7035             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
    7036           8 :                                               /* HAS_NODATA = */ true>(
    7037           8 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7038           8 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7039             :             }
    7040             :             else
    7041             :             {
    7042             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
    7043        2385 :                                               /* HAS_NODATA = */ false>(
    7044        2385 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7045        2385 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7046             :             }
    7047             :         }
    7048             :         else
    7049             :         {
    7050        2340 :             if (bHasNoData)
    7051             :             {
    7052             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
    7053           0 :                                               /* HAS_NODATA = */ true>(
    7054           0 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7055           0 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7056             :             }
    7057             :             else
    7058             :             {
    7059             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
    7060        2340 :                                               /* HAS_NODATA = */ false>(
    7061        2340 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7062        2340 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7063             :             }
    7064             :         }
    7065        4733 :     }
    7066             : };
    7067             : }  // namespace
    7068             : 
    7069             : /************************************************************************/
    7070             : /*                         ComputeStatistics()                          */
    7071             : /************************************************************************/
    7072             : 
    7073             : /**
    7074             :  * \brief Compute image statistics.
    7075             :  *
    7076             :  * Returns the minimum, maximum, mean and standard deviation of all
    7077             :  * pixel values in this band.  If approximate statistics are sufficient,
    7078             :  * the bApproxOK flag can be set to true in which case overviews, or a
    7079             :  * subset of image tiles may be used in computing the statistics.
    7080             :  *
    7081             :  * Once computed, the statistics will generally be "set" back on the
    7082             :  * raster band using SetStatistics().
    7083             :  *
    7084             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    7085             :  *
    7086             :  * This method is the same as the C function GDALComputeRasterStatistics().
    7087             :  *
    7088             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    7089             :  * or a subset of all tiles.
    7090             :  *
    7091             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    7092             :  *
    7093             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    7094             :  *
    7095             :  * @param pdfMean Location into which to load image mean (may be NULL).
    7096             :  *
    7097             :  * @param pdfStdDev Location into which to load image standard deviation
    7098             :  * (may be NULL).
    7099             :  *
    7100             :  * @param pfnProgress a function to call to report progress, or NULL.
    7101             :  *
    7102             :  * @param pProgressData application data to pass to the progress function.
    7103             :  *
    7104             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    7105             :  * is terminated by the user.
    7106             :  */
    7107             : 
    7108         573 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    7109             :                                          double *pdfMax, double *pdfMean,
    7110             :                                          double *pdfStdDev,
    7111             :                                          GDALProgressFunc pfnProgress,
    7112             :                                          void *pProgressData)
    7113             : 
    7114             : {
    7115         573 :     if (pfnProgress == nullptr)
    7116         244 :         pfnProgress = GDALDummyProgress;
    7117             : 
    7118             :     /* -------------------------------------------------------------------- */
    7119             :     /*      If we have overview bands, use them for statistics.             */
    7120             :     /* -------------------------------------------------------------------- */
    7121         573 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7122             :     {
    7123             :         GDALRasterBand *poBand =
    7124           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7125             : 
    7126           3 :         if (poBand != this)
    7127             :         {
    7128           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    7129             :                                                     pdfMean, pdfStdDev,
    7130           3 :                                                     pfnProgress, pProgressData);
    7131           3 :             if (eErr == CE_None)
    7132             :             {
    7133           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    7134             :                 {
    7135           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7136           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    7137             :                 }
    7138             : 
    7139             :                 /* transfer metadata from overview band to this */
    7140             :                 const char *pszPercentValid =
    7141           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    7142             : 
    7143           3 :                 if (pszPercentValid != nullptr)
    7144             :                 {
    7145           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    7146           3 :                                     pszPercentValid);
    7147             :                 }
    7148             :             }
    7149           3 :             return eErr;
    7150             :         }
    7151             :     }
    7152             : 
    7153         570 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    7154             :     {
    7155           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7156           0 :         return CE_Failure;
    7157             :     }
    7158             : 
    7159             :     /* -------------------------------------------------------------------- */
    7160             :     /*      Read actual data and compute statistics.                        */
    7161             :     /* -------------------------------------------------------------------- */
    7162             :     // Using Welford algorithm:
    7163             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    7164             :     // to compute standard deviation in a more numerically robust way than
    7165             :     // the difference of the sum of square values with the square of the sum.
    7166             :     // dfMean and dfM2 are updated at each sample.
    7167             :     // dfM2 is the sum of square of differences to the current mean.
    7168         570 :     double dfMin = std::numeric_limits<double>::infinity();
    7169         570 :     double dfMax = -std::numeric_limits<double>::infinity();
    7170         570 :     double dfMean = 0.0;
    7171         570 :     double dfM2 = 0.0;
    7172             : 
    7173             :     GDALRasterIOExtraArg sExtraArg;
    7174         570 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7175             : 
    7176         570 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7177         570 :     GDALRasterBand *poMaskBand = nullptr;
    7178         570 :     if (!sNoDataValues.bGotNoDataValue)
    7179             :     {
    7180         499 :         const int l_nMaskFlags = GetMaskFlags();
    7181         557 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    7182          58 :             GetColorInterpretation() != GCI_AlphaBand)
    7183             :         {
    7184          58 :             poMaskBand = GetMaskBand();
    7185             :         }
    7186             :     }
    7187             : 
    7188         570 :     bool bSignedByte = false;
    7189         570 :     if (eDataType == GDT_UInt8)
    7190             :     {
    7191         217 :         EnablePixelTypeSignedByteWarning(false);
    7192             :         const char *pszPixelType =
    7193         217 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7194         217 :         EnablePixelTypeSignedByteWarning(true);
    7195         217 :         bSignedByte =
    7196         217 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7197             :     }
    7198             : 
    7199         570 :     GUIntBig nSampleCount = 0;
    7200         570 :     GUIntBig nValidCount = 0;
    7201             : 
    7202         570 :     if (bApproxOK && HasArbitraryOverviews())
    7203             :     {
    7204             :         /* --------------------------------------------------------------------
    7205             :          */
    7206             :         /*      Figure out how much the image should be reduced to get an */
    7207             :         /*      approximate value. */
    7208             :         /* --------------------------------------------------------------------
    7209             :          */
    7210           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7211           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7212             : 
    7213           0 :         int nXReduced = nRasterXSize;
    7214           0 :         int nYReduced = nRasterYSize;
    7215           0 :         if (dfReduction > 1.0)
    7216             :         {
    7217           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7218           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7219             : 
    7220             :             // Catch the case of huge resizing ratios here
    7221           0 :             if (nXReduced == 0)
    7222           0 :                 nXReduced = 1;
    7223           0 :             if (nYReduced == 0)
    7224           0 :                 nYReduced = 1;
    7225             :         }
    7226             : 
    7227           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    7228           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7229             : 
    7230             :         const CPLErr eErr =
    7231           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7232           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7233           0 :         if (eErr != CE_None)
    7234             :         {
    7235           0 :             CPLFree(pData);
    7236           0 :             return eErr;
    7237             :         }
    7238             : 
    7239           0 :         GByte *pabyMaskData = nullptr;
    7240           0 :         if (poMaskBand)
    7241             :         {
    7242             :             pabyMaskData =
    7243           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7244           0 :             if (!pabyMaskData)
    7245             :             {
    7246           0 :                 CPLFree(pData);
    7247           0 :                 return CE_Failure;
    7248             :             }
    7249             : 
    7250           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7251             :                                      pabyMaskData, nXReduced, nYReduced,
    7252           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    7253             :             {
    7254           0 :                 CPLFree(pData);
    7255           0 :                 CPLFree(pabyMaskData);
    7256           0 :                 return CE_Failure;
    7257             :             }
    7258             :         }
    7259             : 
    7260             :         /* this isn't the fastest way to do this, but is easier for now */
    7261           0 :         for (int iY = 0; iY < nYReduced; iY++)
    7262             :         {
    7263           0 :             for (int iX = 0; iX < nXReduced; iX++)
    7264             :             {
    7265           0 :                 const int iOffset = iX + iY * nXReduced;
    7266           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7267           0 :                     continue;
    7268             : 
    7269           0 :                 bool bValid = true;
    7270           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7271           0 :                                                iOffset, sNoDataValues, bValid);
    7272           0 :                 if (!bValid)
    7273           0 :                     continue;
    7274             : 
    7275           0 :                 dfMin = std::min(dfMin, dfValue);
    7276           0 :                 dfMax = std::max(dfMax, dfValue);
    7277             : 
    7278           0 :                 nValidCount++;
    7279           0 :                 if (dfMin == dfMax)
    7280             :                 {
    7281           0 :                     if (nValidCount == 1)
    7282           0 :                         dfMean = dfMin;
    7283             :                 }
    7284             :                 else
    7285             :                 {
    7286           0 :                     const double dfDelta = dfValue - dfMean;
    7287           0 :                     dfMean += dfDelta / nValidCount;
    7288           0 :                     dfM2 += dfDelta * (dfValue - dfMean);
    7289             :                 }
    7290             :             }
    7291             :         }
    7292             : 
    7293           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    7294             : 
    7295           0 :         CPLFree(pData);
    7296           0 :         CPLFree(pabyMaskData);
    7297             :     }
    7298             : 
    7299             :     else  // No arbitrary overviews.
    7300             :     {
    7301         570 :         if (!InitBlockInfo())
    7302         251 :             return CE_Failure;
    7303             : 
    7304             :         /* --------------------------------------------------------------------
    7305             :          */
    7306             :         /*      Figure out the ratio of blocks we will read to get an */
    7307             :         /*      approximate value. */
    7308             :         /* --------------------------------------------------------------------
    7309             :          */
    7310         570 :         int nSampleRate = 1;
    7311         570 :         if (bApproxOK)
    7312             :         {
    7313          43 :             nSampleRate = static_cast<int>(std::max(
    7314          86 :                 1.0,
    7315          43 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7316             :             // We want to avoid probing only the first column of blocks for
    7317             :             // a square shaped raster, because it is not unlikely that it may
    7318             :             // be padding only (#6378)
    7319          43 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7320           1 :                 nSampleRate += 1;
    7321             :         }
    7322         570 :         if (nSampleRate == 1)
    7323         536 :             bApproxOK = false;
    7324             : 
    7325             :         // Particular case for GDT_UInt8 and GUInt16 that only use integral types
    7326             :         // for each block, and possibly for the whole raster.
    7327         570 :         if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    7328         312 :                             eDataType == GDT_UInt16))
    7329             :         {
    7330             :             // We can do integer computation on the whole raster in the Byte case
    7331             :             // only if the number of pixels explored is lower than
    7332             :             // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
    7333             :             // Should be 99.99999% of cases.
    7334             :             // For GUInt16, this limits to raster of 4 giga pixels
    7335             : 
    7336             :             const bool bIntegerStats =
    7337         451 :                 ((eDataType == GDT_UInt8 &&
    7338         200 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7339         200 :                           nSampleRate <
    7340         200 :                       GUINTBIG_MAX / (255U * 255U) /
    7341         200 :                           (static_cast<GUInt64>(nBlockXSize) *
    7342         200 :                            static_cast<GUInt64>(nBlockYSize))) ||
    7343          51 :                  (eDataType == GDT_UInt16 &&
    7344          51 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7345          51 :                           nSampleRate <
    7346          51 :                       GUINTBIG_MAX / (65535U * 65535U) /
    7347          51 :                           (static_cast<GUInt64>(nBlockXSize) *
    7348         553 :                            static_cast<GUInt64>(nBlockYSize)))) &&
    7349             :                 // Can be set to NO for easier debugging of the !bIntegerStats
    7350             :                 // case which requires huge rasters to trigger
    7351         251 :                 CPLTestBool(
    7352         251 :                     CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
    7353             : 
    7354         251 :             const GUInt32 nMaxValueType =
    7355         251 :                 (eDataType == GDT_UInt8) ? 255 : 65535;
    7356         251 :             GUInt32 nMin = nMaxValueType;
    7357         251 :             GUInt32 nMax = 0;
    7358         251 :             GUIntBig nSum = 0;
    7359         251 :             GUIntBig nSumSquare = 0;
    7360             :             // If no valid nodata, map to invalid value (256 for Byte)
    7361         251 :             const GUInt32 nNoDataValue =
    7362         286 :                 (sNoDataValues.bGotNoDataValue &&
    7363          35 :                  sNoDataValues.dfNoDataValue >= 0 &&
    7364          35 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    7365          35 :                  fabs(sNoDataValues.dfNoDataValue -
    7366          35 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    7367             :                                            1e-10)) < 1e-10)
    7368         286 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    7369             :                     : nMaxValueType + 1;
    7370             : 
    7371         251 :             for (GIntBig iSampleBlock = 0;
    7372       13098 :                  iSampleBlock <
    7373       13098 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7374       12847 :                  iSampleBlock += nSampleRate)
    7375             :             {
    7376       12847 :                 const int iYBlock =
    7377       12847 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7378       12847 :                 const int iXBlock =
    7379       12847 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7380             : 
    7381             :                 GDALRasterBlock *const poBlock =
    7382       12847 :                     GetLockedBlockRef(iXBlock, iYBlock);
    7383       12847 :                 if (poBlock == nullptr)
    7384           0 :                     return CE_Failure;
    7385             : 
    7386       12847 :                 void *const pData = poBlock->GetDataRef();
    7387             : 
    7388       12847 :                 int nXCheck = 0, nYCheck = 0;
    7389       12847 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7390             : 
    7391       12847 :                 GUIntBig nBlockSum = 0;
    7392       12847 :                 GUIntBig nBlockSumSquare = 0;
    7393       12847 :                 GUIntBig nBlockSampleCount = 0;
    7394       12847 :                 GUIntBig nBlockValidCount = 0;
    7395       12847 :                 GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
    7396       12847 :                 GUIntBig &nBlockSumSquareRef =
    7397             :                     bIntegerStats ? nSumSquare : nBlockSumSquare;
    7398       12847 :                 GUIntBig &nBlockSampleCountRef =
    7399             :                     bIntegerStats ? nSampleCount : nBlockSampleCount;
    7400       12847 :                 GUIntBig &nBlockValidCountRef =
    7401             :                     bIntegerStats ? nValidCount : nBlockValidCount;
    7402             : 
    7403       12847 :                 if (eDataType == GDT_UInt8)
    7404             :                 {
    7405             :                     ComputeStatisticsInternal<
    7406             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    7407       12161 :                         f(nXCheck, nBlockXSize, nYCheck,
    7408             :                           static_cast<const GByte *>(pData),
    7409             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7410             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7411             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7412             :                 }
    7413             :                 else
    7414             :                 {
    7415             :                     ComputeStatisticsInternal<
    7416             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    7417         686 :                         f(nXCheck, nBlockXSize, nYCheck,
    7418             :                           static_cast<const GUInt16 *>(pData),
    7419             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7420             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7421             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7422             :                 }
    7423             : 
    7424       12847 :                 poBlock->DropLock();
    7425             : 
    7426       12847 :                 if (!bIntegerStats)
    7427             :                 {
    7428         169 :                     nSampleCount += nBlockSampleCount;
    7429         169 :                     if (nBlockValidCount)
    7430             :                     {
    7431             :                         // Update the global mean and M2 (the difference of the
    7432             :                         // square to the mean) from the values of the block
    7433             :                         // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7434         169 :                         const double dfBlockValidCount =
    7435         169 :                             static_cast<double>(nBlockValidCount);
    7436         169 :                         const double dfBlockMean =
    7437         169 :                             static_cast<double>(nBlockSum) / dfBlockValidCount;
    7438             :                         const double dfBlockM2 =
    7439         169 :                             static_cast<double>(
    7440         169 :                                 GDALUInt128::Mul(nBlockSumSquare,
    7441         169 :                                                  nBlockValidCount) -
    7442         338 :                                 GDALUInt128::Mul(nBlockSum, nBlockSum)) /
    7443         169 :                             dfBlockValidCount;
    7444         169 :                         const double dfDelta = dfBlockMean - dfMean;
    7445         169 :                         const auto nNewValidCount =
    7446         169 :                             nValidCount + nBlockValidCount;
    7447         169 :                         const double dfNewValidCount =
    7448             :                             static_cast<double>(nNewValidCount);
    7449         169 :                         dfMean +=
    7450         169 :                             dfDelta * (dfBlockValidCount / dfNewValidCount);
    7451         169 :                         dfM2 +=
    7452         169 :                             dfBlockM2 + dfDelta * dfDelta *
    7453         169 :                                             static_cast<double>(nValidCount) *
    7454         169 :                                             dfBlockValidCount / dfNewValidCount;
    7455         169 :                         nValidCount = nNewValidCount;
    7456             :                     }
    7457             :                 }
    7458             : 
    7459       12847 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    7460       12847 :                                      (static_cast<double>(nBlocksPerRow) *
    7461       12847 :                                       nBlocksPerColumn),
    7462             :                                  "Compute Statistics", pProgressData))
    7463             :                 {
    7464           0 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    7465             :                                 "User terminated");
    7466           0 :                     return CE_Failure;
    7467             :                 }
    7468             :             }
    7469             : 
    7470         251 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    7471             :             {
    7472           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7473           0 :                 return CE_Failure;
    7474             :             }
    7475             : 
    7476         251 :             double dfStdDev = 0;
    7477         251 :             if (bIntegerStats)
    7478             :             {
    7479         227 :                 if (nValidCount)
    7480         218 :                     dfMean = static_cast<double>(nSum) / nValidCount;
    7481             : 
    7482             :                 // To avoid potential precision issues when doing the difference,
    7483             :                 // we need to do that computation on 128 bit rather than casting
    7484             :                 // to double
    7485             :                 const GDALUInt128 nTmpForStdDev(
    7486         227 :                     GDALUInt128::Mul(nSumSquare, nValidCount) -
    7487         454 :                     GDALUInt128::Mul(nSum, nSum));
    7488         227 :                 dfStdDev =
    7489         227 :                     nValidCount > 0
    7490         227 :                         ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    7491             :                         : 0.0;
    7492             :             }
    7493          24 :             else if (nValidCount > 0)
    7494             :             {
    7495          24 :                 dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
    7496             :             }
    7497             : 
    7498             :             /// Save computed information
    7499         251 :             if (nValidCount > 0)
    7500             :             {
    7501         242 :                 if (bApproxOK)
    7502             :                 {
    7503          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7504             :                 }
    7505         218 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    7506             :                 {
    7507           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    7508             :                 }
    7509         242 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    7510             :             }
    7511             : 
    7512         251 :             SetValidPercent(nSampleCount, nValidCount);
    7513             : 
    7514             :             /* --------------------------------------------------------------------
    7515             :              */
    7516             :             /*      Record results. */
    7517             :             /* --------------------------------------------------------------------
    7518             :              */
    7519         251 :             if (pdfMin != nullptr)
    7520         248 :                 *pdfMin = nValidCount ? nMin : 0;
    7521         251 :             if (pdfMax != nullptr)
    7522         248 :                 *pdfMax = nValidCount ? nMax : 0;
    7523             : 
    7524         251 :             if (pdfMean != nullptr)
    7525         244 :                 *pdfMean = dfMean;
    7526             : 
    7527         251 :             if (pdfStdDev != nullptr)
    7528         244 :                 *pdfStdDev = dfStdDev;
    7529             : 
    7530         251 :             if (nValidCount > 0)
    7531         242 :                 return CE_None;
    7532             : 
    7533           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    7534             :                         "Failed to compute statistics, no valid pixels found "
    7535             :                         "in sampling.");
    7536           9 :             return CE_Failure;
    7537             :         }
    7538             : 
    7539         319 :         GByte *pabyMaskData = nullptr;
    7540         319 :         if (poMaskBand)
    7541             :         {
    7542             :             pabyMaskData = static_cast<GByte *>(
    7543          58 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7544          58 :             if (!pabyMaskData)
    7545             :             {
    7546           0 :                 return CE_Failure;
    7547             :             }
    7548             :         }
    7549             : 
    7550         319 :         float fMin = std::numeric_limits<float>::infinity();
    7551         319 :         float fMax = -std::numeric_limits<float>::infinity();
    7552             :         bool bFloat32Optim =
    7553         133 :             (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
    7554         319 :              eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
    7555         209 :             !pabyMaskData &&
    7556         847 :             nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
    7557         209 :             CPLTestBool(
    7558         319 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
    7559           0 :         std::unique_ptr<float, VSIFreeReleaser> pafTemp;
    7560             : 
    7561         319 :         int nChunkXSize = nBlockXSize;
    7562         319 :         int nChunkYSize = nBlockYSize;
    7563         319 :         int nChunksPerRow = nBlocksPerRow;
    7564         319 :         int nChunksPerCol = nBlocksPerColumn;
    7565             : 
    7566             : #define nBlockXSize use_nChunkXSize_instead
    7567             : #define nBlockYSize use_nChunkYSize_instead
    7568             : #define nBlocksPerRow use_nChunksPerRow_instead
    7569             : #define nBlocksPerColumn use_nChunksPerCol_instead
    7570             : 
    7571         319 :         int nThreads = 1;
    7572         319 :         CPLWorkerThreadPool *psThreadPool = nullptr;
    7573         319 :         if (bFloat32Optim)
    7574             :         {
    7575         207 :             if (nChunkYSize > 1)
    7576             :             {
    7577             :                 const char *pszNumThreads =
    7578          15 :                     CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
    7579          15 :                 if (pszNumThreads)
    7580             :                 {
    7581           4 :                     if (EQUAL(pszNumThreads, "ALL_CPUS"))
    7582           4 :                         nThreads = CPLGetNumCPUs();
    7583             :                     else
    7584           0 :                         nThreads =
    7585           0 :                             std::clamp(atoi(pszNumThreads), 1, CPLGetNumCPUs());
    7586           4 :                     if (nThreads > 1)
    7587           4 :                         psThreadPool = GDALGetGlobalThreadPool(nThreads);
    7588             :                 }
    7589             :             }
    7590             : 
    7591         207 :             int nNewChunkXSize = nChunkXSize;
    7592         211 :             if (!bApproxOK && nThreads > 1 &&
    7593           4 :                 MayMultiBlockReadingBeMultiThreaded())
    7594             :             {
    7595           0 :                 const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
    7596           0 :                 const size_t nChunkPixels =
    7597           0 :                     static_cast<size_t>(nChunkXSize) * nChunkYSize;
    7598           0 :                 if (nRAMAmount > 0 &&
    7599             :                     nChunkPixels <=
    7600           0 :                         std::numeric_limits<size_t>::max() / sizeof(float))
    7601             :                 {
    7602           0 :                     const size_t nBlockSizeAsFloat32 =
    7603             :                         sizeof(float) * nChunkPixels;
    7604           0 :                     const int64_t nBlockCount =
    7605           0 :                         nRAMAmount / nBlockSizeAsFloat32;
    7606           0 :                     if (nBlockCount >= 2)
    7607             :                     {
    7608           0 :                         nNewChunkXSize = static_cast<int>(std::min<int64_t>(
    7609           0 :                             nChunkXSize * std::min<int64_t>(
    7610             :                                               nBlockCount,
    7611           0 :                                               std::numeric_limits<int>::max() /
    7612           0 :                                                   nChunkPixels),
    7613           0 :                             nRasterXSize));
    7614             : 
    7615           0 :                         CPLAssert(nChunkXSize <
    7616             :                                   std::numeric_limits<int>::max() /
    7617             :                                       nChunkYSize);
    7618             :                     }
    7619             :                 }
    7620             :             }
    7621         207 :             if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
    7622             :             {
    7623         187 :                 pafTemp.reset(static_cast<float *>(
    7624         187 :                     VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
    7625         187 :                 bFloat32Optim = pafTemp != nullptr;
    7626         187 :                 if (bFloat32Optim)
    7627             :                 {
    7628         187 :                     nChunkXSize = nNewChunkXSize;
    7629             :                     nChunksPerRow =
    7630         187 :                         cpl::div_round_up(nRasterXSize, nChunkXSize);
    7631             :                 }
    7632             :             }
    7633         207 :             CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
    7634             :                      nChunkXSize, nChunkYSize);
    7635             :         }
    7636             : 
    7637             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    7638             :         const bool bFloat64Optim =
    7639          23 :             eDataType == GDT_Float64 && !pabyMaskData &&
    7640         365 :             nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
    7641          23 :             CPLTestBool(
    7642         319 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
    7643             : #endif
    7644             : 
    7645         319 :         std::vector<StatisticsTaskFloat32> tasksFloat32;
    7646             : 
    7647         319 :         for (GIntBig iSampleBlock = 0;
    7648        6034 :              iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
    7649        5715 :              iSampleBlock += nSampleRate)
    7650             :         {
    7651        5715 :             const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
    7652        5715 :             const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
    7653             : 
    7654             :             const int nXCheck =
    7655        5715 :                 std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
    7656             :             const int nYCheck =
    7657        5715 :                 std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
    7658             : 
    7659        6300 :             if (poMaskBand &&
    7660         585 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
    7661             :                                      iYBlock * nChunkYSize, nXCheck, nYCheck,
    7662             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    7663             :                                      0, nChunkXSize, nullptr) != CE_None)
    7664             :             {
    7665           0 :                 CPLFree(pabyMaskData);
    7666           0 :                 return CE_Failure;
    7667             :             }
    7668             : 
    7669        5715 :             GDALRasterBlock *poBlock = nullptr;
    7670        5715 :             if (pafTemp)
    7671             :             {
    7672        2393 :                 if (RasterIO(GF_Read, iXBlock * nChunkXSize,
    7673             :                              iYBlock * nChunkYSize, nXCheck, nYCheck,
    7674        2393 :                              pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
    7675        2393 :                              static_cast<GSpacing>(nChunkXSize * sizeof(float)),
    7676        2393 :                              nullptr) != CE_None)
    7677             :                 {
    7678           0 :                     CPLFree(pabyMaskData);
    7679           0 :                     return CE_Failure;
    7680             :                 }
    7681             :             }
    7682             :             else
    7683             :             {
    7684        3322 :                 poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7685        3322 :                 if (poBlock == nullptr)
    7686             :                 {
    7687           0 :                     CPLFree(pabyMaskData);
    7688           0 :                     return CE_Failure;
    7689             :                 }
    7690             :             }
    7691             : 
    7692             :             const void *const pData =
    7693        5715 :                 poBlock ? poBlock->GetDataRef() : pafTemp.get();
    7694             : 
    7695        5715 :             if (bFloat32Optim)
    7696             :             {
    7697        4729 :                 const float *const pafSrcData =
    7698             :                     static_cast<const float *>(pData);
    7699             : 
    7700        4735 :                 const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
    7701           6 :                                         !std::isnan(sNoDataValues.fNoDataValue);
    7702        4729 :                 const int nTasks = std::min(nYCheck, nThreads);
    7703        4729 :                 const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
    7704        4729 :                 tasksFloat32.clear();
    7705        9462 :                 for (int i = 0; i < nTasks; ++i)
    7706             :                 {
    7707        4733 :                     StatisticsTaskFloat32 task;
    7708        4733 :                     task.eDataType = eDataType;
    7709        4733 :                     task.bHasNoData = bHasNoData;
    7710        4733 :                     task.psNoDataValues = &sNoDataValues;
    7711        4733 :                     task.nChunkXSize = nChunkXSize;
    7712        4733 :                     task.fMin = fMin;
    7713        4733 :                     task.fMax = fMax;
    7714        4733 :                     task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
    7715        4733 :                                                        nRowsPerTask *
    7716        4733 :                                                        nChunkXSize;
    7717        4733 :                     task.nXCheck = nXCheck;
    7718        4733 :                     task.nYCheck =
    7719        4733 :                         std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
    7720        4733 :                     tasksFloat32.emplace_back(std::move(task));
    7721             :                 }
    7722        4729 :                 if (psThreadPool)
    7723             :                 {
    7724           8 :                     auto poJobQueue = psThreadPool->CreateJobQueue();
    7725          12 :                     for (auto &task : tasksFloat32)
    7726             :                     {
    7727          16 :                         poJobQueue->SubmitJob([&task]() { task.Perform(); });
    7728             :                     }
    7729           4 :                     poJobQueue->WaitCompletion();
    7730             :                 }
    7731             :                 else
    7732             :                 {
    7733        4725 :                     tasksFloat32[0].Perform();
    7734             :                 }
    7735             : 
    7736        9462 :                 for (const auto &task : tasksFloat32)
    7737             :                 {
    7738        4733 :                     if (task.dfBlockValidCount > 0)
    7739             :                     {
    7740        4733 :                         fMin = std::min(fMin, task.fMin);
    7741        4733 :                         fMax = std::max(fMax, task.fMax);
    7742             : 
    7743             :                         // Update the global mean and M2 (the difference of the
    7744             :                         // square to the mean) from the values of the block
    7745             :                         // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7746        4733 :                         const auto nNewValidCount =
    7747        4733 :                             nValidCount +
    7748        4733 :                             static_cast<int>(task.dfBlockValidCount);
    7749        4733 :                         dfM2 += task.dfBlockM2;
    7750        4733 :                         if (task.dfBlockMean != dfMean)
    7751             :                         {
    7752        1167 :                             if (nValidCount == 0)
    7753             :                             {
    7754          50 :                                 dfMean = task.dfBlockMean;
    7755             :                             }
    7756             :                             else
    7757             :                             {
    7758        1117 :                                 const double dfDelta =
    7759        1117 :                                     task.dfBlockMean - dfMean;
    7760        1117 :                                 const double dfNewValidCount =
    7761             :                                     static_cast<double>(nNewValidCount);
    7762        1117 :                                 dfMean += dfDelta * (task.dfBlockValidCount /
    7763             :                                                      dfNewValidCount);
    7764        1117 :                                 dfM2 += dfDelta * dfDelta *
    7765        1117 :                                         static_cast<double>(nValidCount) *
    7766        1117 :                                         task.dfBlockValidCount /
    7767             :                                         dfNewValidCount;
    7768             :                             }
    7769             :                         }
    7770        4733 :                         nValidCount = nNewValidCount;
    7771             :                     }
    7772             :                 }
    7773             :             }
    7774             : 
    7775             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    7776         986 :             else if (bFloat64Optim)
    7777             :             {
    7778             :                 const bool bHasNoData =
    7779         563 :                     sNoDataValues.bGotNoDataValue &&
    7780         269 :                     !std::isnan(sNoDataValues.dfNoDataValue);
    7781         294 :                 double dfBlockMean = 0;
    7782         294 :                 double dfBlockM2 = 0;
    7783         294 :                 double dfBlockValidCount = 0;
    7784        2661 :                 for (int iY = 0; iY < nYCheck; iY++)
    7785             :                 {
    7786        2367 :                     const int iOffset = iY * nChunkXSize;
    7787        2367 :                     if (dfBlockValidCount != 0 && dfMin != dfMax)
    7788             :                     {
    7789        1817 :                         int iX = 0;
    7790        1817 :                         if (bHasNoData)
    7791             :                         {
    7792             :                             iX = ComputeStatisticsFloat64_SSE2<
    7793             :                                 /* bCheckMinEqMax = */ false,
    7794         387 :                                 /* bHasNoData = */ true>(
    7795         387 :                                 static_cast<const double *>(pData) + iOffset,
    7796             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7797             :                                 dfMax, dfBlockMean, dfBlockM2,
    7798             :                                 dfBlockValidCount);
    7799             :                         }
    7800             :                         else
    7801             :                         {
    7802             :                             iX = ComputeStatisticsFloat64_SSE2<
    7803             :                                 /* bCheckMinEqMax = */ false,
    7804        1430 :                                 /* bHasNoData = */ false>(
    7805        1430 :                                 static_cast<const double *>(pData) + iOffset,
    7806             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7807             :                                 dfMax, dfBlockMean, dfBlockM2,
    7808             :                                 dfBlockValidCount);
    7809             :                         }
    7810        2959 :                         for (; iX < nXCheck; iX++)
    7811             :                         {
    7812        1142 :                             const double dfValue = static_cast<const double *>(
    7813        1142 :                                 pData)[iOffset + iX];
    7814        1665 :                             if (std::isnan(dfValue) ||
    7815         523 :                                 (bHasNoData &&
    7816         523 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7817          59 :                                 continue;
    7818        1083 :                             dfMin = std::min(dfMin, dfValue);
    7819        1083 :                             dfMax = std::max(dfMax, dfValue);
    7820        1083 :                             dfBlockValidCount += 1.0;
    7821        1083 :                             const double dfDelta = dfValue - dfBlockMean;
    7822        1083 :                             dfBlockMean += dfDelta / dfBlockValidCount;
    7823        1083 :                             dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7824        1817 :                         }
    7825             :                     }
    7826             :                     else
    7827             :                     {
    7828         550 :                         int iX = 0;
    7829         550 :                         if (dfBlockValidCount == 0)
    7830             :                         {
    7831        7673 :                             for (; iX < nXCheck; iX++)
    7832             :                             {
    7833        7639 :                                 const double dfValue =
    7834             :                                     static_cast<const double *>(
    7835        7639 :                                         pData)[iOffset + iX];
    7836       15253 :                                 if (std::isnan(dfValue) ||
    7837        7614 :                                     (bHasNoData &&
    7838        7614 :                                      dfValue == sNoDataValues.dfNoDataValue))
    7839        7377 :                                     continue;
    7840         262 :                                 dfMin = std::min(dfMin, dfValue);
    7841         262 :                                 dfMax = std::max(dfMax, dfValue);
    7842         262 :                                 dfBlockValidCount = 1;
    7843         262 :                                 dfBlockMean = dfValue;
    7844         262 :                                 iX++;
    7845         262 :                                 break;
    7846             :                             }
    7847             :                         }
    7848         550 :                         if (bHasNoData)
    7849             :                         {
    7850             :                             iX = ComputeStatisticsFloat64_SSE2<
    7851             :                                 /* bCheckMinEqMax = */ true,
    7852         398 :                                 /* bHasNoData = */ true>(
    7853         398 :                                 static_cast<const double *>(pData) + iOffset,
    7854             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7855             :                                 dfMax, dfBlockMean, dfBlockM2,
    7856             :                                 dfBlockValidCount);
    7857             :                         }
    7858             :                         else
    7859             :                         {
    7860             :                             iX = ComputeStatisticsFloat64_SSE2<
    7861             :                                 /* bCheckMinEqMax = */ true,
    7862         152 :                                 /* bHasNoData = */ false>(
    7863         152 :                                 static_cast<const double *>(pData) + iOffset,
    7864             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7865             :                                 dfMax, dfBlockMean, dfBlockM2,
    7866             :                                 dfBlockValidCount);
    7867             :                         }
    7868        1121 :                         for (; iX < nXCheck; iX++)
    7869             :                         {
    7870         571 :                             const double dfValue = static_cast<const double *>(
    7871         571 :                                 pData)[iOffset + iX];
    7872        1103 :                             if (std::isnan(dfValue) ||
    7873         532 :                                 (bHasNoData &&
    7874         532 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7875         146 :                                 continue;
    7876         425 :                             dfMin = std::min(dfMin, dfValue);
    7877         425 :                             dfMax = std::max(dfMax, dfValue);
    7878         425 :                             dfBlockValidCount += 1.0;
    7879         425 :                             if (dfMin != dfMax)
    7880             :                             {
    7881         150 :                                 const double dfDelta = dfValue - dfBlockMean;
    7882         150 :                                 dfBlockMean += dfDelta / dfBlockValidCount;
    7883         150 :                                 dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7884             :                             }
    7885             :                         }
    7886             :                     }
    7887             :                 }
    7888             : 
    7889         294 :                 if (dfBlockValidCount > 0)
    7890             :                 {
    7891             :                     // Update the global mean and M2 (the difference of the
    7892             :                     // square to the mean) from the values of the block
    7893             :                     // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7894         262 :                     const auto nNewValidCount =
    7895         262 :                         nValidCount + static_cast<int>(dfBlockValidCount);
    7896         262 :                     dfM2 += dfBlockM2;
    7897         262 :                     if (dfBlockMean != dfMean)
    7898             :                     {
    7899         249 :                         if (nValidCount == 0)
    7900             :                         {
    7901          20 :                             dfMean = dfBlockMean;
    7902             :                         }
    7903             :                         else
    7904             :                         {
    7905         229 :                             const double dfDelta = dfBlockMean - dfMean;
    7906         229 :                             const double dfNewValidCount =
    7907             :                                 static_cast<double>(nNewValidCount);
    7908         229 :                             dfMean +=
    7909         229 :                                 dfDelta * (dfBlockValidCount / dfNewValidCount);
    7910         229 :                             dfM2 += dfDelta * dfDelta *
    7911         229 :                                     static_cast<double>(nValidCount) *
    7912         229 :                                     dfBlockValidCount / dfNewValidCount;
    7913             :                         }
    7914             :                     }
    7915         262 :                     nValidCount = nNewValidCount;
    7916             :                 }
    7917             :             }
    7918             : #endif  // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    7919             : 
    7920             :             else
    7921             :             {
    7922             :                 // This isn't the fastest way to do this, but is easier for now.
    7923        6046 :                 for (int iY = 0; iY < nYCheck; iY++)
    7924             :                 {
    7925        5354 :                     if (nValidCount && dfMin != dfMax)
    7926             :                     {
    7927      712990 :                         for (int iX = 0; iX < nXCheck; iX++)
    7928             :                         {
    7929      708474 :                             const GPtrDiff_t iOffset =
    7930      708474 :                                 iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    7931      708474 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7932        9653 :                                 continue;
    7933             : 
    7934      698847 :                             bool bValid = true;
    7935             :                             double dfValue =
    7936      698847 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    7937      698847 :                                               iOffset, sNoDataValues, bValid);
    7938             : 
    7939      698847 :                             if (!bValid)
    7940          26 :                                 continue;
    7941             : 
    7942      698821 :                             dfMin = std::min(dfMin, dfValue);
    7943      698821 :                             dfMax = std::max(dfMax, dfValue);
    7944             : 
    7945      698821 :                             nValidCount++;
    7946      698821 :                             const double dfDelta = dfValue - dfMean;
    7947      698821 :                             dfMean += dfDelta / nValidCount;
    7948      698821 :                             dfM2 += dfDelta * (dfValue - dfMean);
    7949        4516 :                         }
    7950             :                     }
    7951             :                     else
    7952             :                     {
    7953         838 :                         int iX = 0;
    7954         838 :                         if (nValidCount == 0)
    7955             :                         {
    7956       94429 :                             for (; iX < nXCheck; iX++)
    7957             :                             {
    7958       94372 :                                 const GPtrDiff_t iOffset =
    7959       94372 :                                     iX +
    7960       94372 :                                     static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    7961       94372 :                                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7962       94281 :                                     continue;
    7963             : 
    7964          91 :                                 bool bValid = true;
    7965          91 :                                 double dfValue = GetPixelValue(
    7966             :                                     eDataType, bSignedByte, pData, iOffset,
    7967             :                                     sNoDataValues, bValid);
    7968             : 
    7969          91 :                                 if (!bValid)
    7970           0 :                                     continue;
    7971             : 
    7972          91 :                                 dfMin = dfValue;
    7973          91 :                                 dfMax = dfValue;
    7974          91 :                                 dfMean = dfValue;
    7975          91 :                                 nValidCount = 1;
    7976          91 :                                 iX++;
    7977          91 :                                 break;
    7978             :                             }
    7979             :                         }
    7980      167021 :                         for (; iX < nXCheck; iX++)
    7981             :                         {
    7982      166183 :                             const GPtrDiff_t iOffset =
    7983      166183 :                                 iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    7984      166183 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7985         376 :                                 continue;
    7986             : 
    7987      165822 :                             bool bValid = true;
    7988             :                             double dfValue =
    7989      165822 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    7990      165822 :                                               iOffset, sNoDataValues, bValid);
    7991             : 
    7992      165822 :                             if (!bValid)
    7993          15 :                                 continue;
    7994             : 
    7995      165807 :                             dfMin = std::min(dfMin, dfValue);
    7996      165807 :                             dfMax = std::max(dfMax, dfValue);
    7997             : 
    7998      165807 :                             nValidCount++;
    7999      165807 :                             if (dfMin != dfMax)
    8000             :                             {
    8001        2636 :                                 const double dfDelta = dfValue - dfMean;
    8002        2636 :                                 dfMean += dfDelta / nValidCount;
    8003        2636 :                                 dfM2 += dfDelta * (dfValue - dfMean);
    8004             :                             }
    8005             :                         }
    8006             :                     }
    8007             :                 }
    8008             :             }
    8009             : 
    8010        5715 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    8011             : 
    8012        5715 :             if (poBlock)
    8013        3322 :                 poBlock->DropLock();
    8014             : 
    8015        5715 :             if (!pfnProgress(
    8016        5715 :                     static_cast<double>(iSampleBlock) /
    8017        5715 :                         (static_cast<double>(nChunksPerRow) * nChunksPerCol),
    8018             :                     "Compute Statistics", pProgressData))
    8019             :             {
    8020           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    8021           0 :                 CPLFree(pabyMaskData);
    8022           0 :                 return CE_Failure;
    8023             :             }
    8024             :         }
    8025             : 
    8026             : #undef nBlockXSize
    8027             : #undef nBlockYSize
    8028             : #undef nBlocksPerRow
    8029             : #undef nBlocksPerColumn
    8030             : 
    8031         319 :         if (bFloat32Optim)
    8032             :         {
    8033         207 :             dfMin = static_cast<double>(fMin);
    8034         207 :             dfMax = static_cast<double>(fMax);
    8035             :         }
    8036         319 :         CPLFree(pabyMaskData);
    8037             :     }
    8038             : 
    8039         319 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    8040             :     {
    8041           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    8042           0 :         return CE_Failure;
    8043             :     }
    8044             : 
    8045             :     /* -------------------------------------------------------------------- */
    8046             :     /*      Save computed information.                                      */
    8047             :     /* -------------------------------------------------------------------- */
    8048         319 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    8049             : 
    8050         319 :     if (nValidCount > 0)
    8051             :     {
    8052         318 :         if (bApproxOK)
    8053             :         {
    8054           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    8055             :         }
    8056         310 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    8057             :         {
    8058           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    8059             :         }
    8060         318 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    8061             :     }
    8062             :     else
    8063             :     {
    8064           1 :         dfMin = 0.0;
    8065           1 :         dfMax = 0.0;
    8066             :     }
    8067             : 
    8068         319 :     SetValidPercent(nSampleCount, nValidCount);
    8069             : 
    8070             :     /* -------------------------------------------------------------------- */
    8071             :     /*      Record results.                                                 */
    8072             :     /* -------------------------------------------------------------------- */
    8073         319 :     if (pdfMin != nullptr)
    8074         316 :         *pdfMin = dfMin;
    8075         319 :     if (pdfMax != nullptr)
    8076         316 :         *pdfMax = dfMax;
    8077             : 
    8078         319 :     if (pdfMean != nullptr)
    8079         313 :         *pdfMean = dfMean;
    8080             : 
    8081         319 :     if (pdfStdDev != nullptr)
    8082         313 :         *pdfStdDev = dfStdDev;
    8083             : 
    8084         319 :     if (nValidCount > 0)
    8085         318 :         return CE_None;
    8086             : 
    8087           1 :     ReportError(
    8088             :         CE_Failure, CPLE_AppDefined,
    8089             :         "Failed to compute statistics, no valid pixels found in sampling.");
    8090           1 :     return CE_Failure;
    8091             : }
    8092             : 
    8093             : /************************************************************************/
    8094             : /*                    GDALComputeRasterStatistics()                     */
    8095             : /************************************************************************/
    8096             : 
    8097             : /**
    8098             :  * \brief Compute image statistics.
    8099             :  *
    8100             :  * @see GDALRasterBand::ComputeStatistics()
    8101             :  */
    8102             : 
    8103         230 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    8104             :                                                int bApproxOK, double *pdfMin,
    8105             :                                                double *pdfMax, double *pdfMean,
    8106             :                                                double *pdfStdDev,
    8107             :                                                GDALProgressFunc pfnProgress,
    8108             :                                                void *pProgressData)
    8109             : 
    8110             : {
    8111         230 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    8112             : 
    8113         230 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8114             : 
    8115         230 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    8116         230 :                                      pdfStdDev, pfnProgress, pProgressData);
    8117             : }
    8118             : 
    8119             : /************************************************************************/
    8120             : /*                           SetStatistics()                            */
    8121             : /************************************************************************/
    8122             : 
    8123             : /**
    8124             :  * \brief Set statistics on band.
    8125             :  *
    8126             :  * This method can be used to store min/max/mean/standard deviation
    8127             :  * statistics on a raster band.
    8128             :  *
    8129             :  * The default implementation stores them as metadata, and will only work
    8130             :  * on formats that can save arbitrary metadata.  This method cannot detect
    8131             :  * whether metadata will be properly saved and so may return CE_None even
    8132             :  * if the statistics will never be saved.
    8133             :  *
    8134             :  * This method is the same as the C function GDALSetRasterStatistics().
    8135             :  *
    8136             :  * @param dfMin minimum pixel value.
    8137             :  *
    8138             :  * @param dfMax maximum pixel value.
    8139             :  *
    8140             :  * @param dfMean mean (average) of all pixel values.
    8141             :  *
    8142             :  * @param dfStdDev Standard deviation of all pixel values.
    8143             :  *
    8144             :  * @return CE_None on success or CE_Failure on failure.
    8145             :  */
    8146             : 
    8147         593 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    8148             :                                      double dfStdDev)
    8149             : 
    8150             : {
    8151         593 :     char szValue[128] = {0};
    8152             : 
    8153         593 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    8154         593 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    8155             : 
    8156         593 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    8157         593 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    8158             : 
    8159         593 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    8160         593 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    8161             : 
    8162         593 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    8163         593 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    8164             : 
    8165         593 :     return CE_None;
    8166             : }
    8167             : 
    8168             : /************************************************************************/
    8169             : /*                      GDALSetRasterStatistics()                       */
    8170             : /************************************************************************/
    8171             : 
    8172             : /**
    8173             :  * \brief Set statistics on band.
    8174             :  *
    8175             :  * @see GDALRasterBand::SetStatistics()
    8176             :  */
    8177             : 
    8178           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    8179             :                                            double dfMax, double dfMean,
    8180             :                                            double dfStdDev)
    8181             : 
    8182             : {
    8183           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    8184             : 
    8185           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8186           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    8187             : }
    8188             : 
    8189             : /************************************************************************/
    8190             : /*                        ComputeRasterMinMax()                         */
    8191             : /************************************************************************/
    8192             : 
    8193             : template <class T, bool HAS_NODATA>
    8194           2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    8195             :                           T *pMax)
    8196             : {
    8197           2 :     T min0 = *pMin;
    8198           2 :     T max0 = *pMax;
    8199           2 :     T min1 = *pMin;
    8200           2 :     T max1 = *pMax;
    8201             :     size_t i;
    8202           2 :     for (i = 0; i + 1 < nElts; i += 2)
    8203             :     {
    8204           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    8205             :         {
    8206           0 :             min0 = std::min(min0, buffer[i]);
    8207           0 :             max0 = std::max(max0, buffer[i]);
    8208             :         }
    8209           0 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    8210             :         {
    8211           0 :             min1 = std::min(min1, buffer[i + 1]);
    8212           0 :             max1 = std::max(max1, buffer[i + 1]);
    8213             :         }
    8214             :     }
    8215           2 :     T min = std::min(min0, min1);
    8216           2 :     T max = std::max(max0, max1);
    8217           2 :     if (i < nElts)
    8218             :     {
    8219           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    8220             :         {
    8221           2 :             min = std::min(min, buffer[i]);
    8222           2 :             max = std::max(max, buffer[i]);
    8223             :         }
    8224             :     }
    8225           2 :     *pMin = min;
    8226           2 :     *pMax = max;
    8227           2 : }
    8228             : 
    8229             : template <GDALDataType eDataType, bool bSignedByte>
    8230             : static void
    8231        6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    8232             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    8233             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    8234             : {
    8235        6703 :     double dfLocalMin = dfMin;
    8236        6703 :     double dfLocalMax = dfMax;
    8237             : 
    8238       22051 :     for (int iY = 0; iY < nYCheck; iY++)
    8239             :     {
    8240    14858421 :         for (int iX = 0; iX < nXCheck; iX++)
    8241             :         {
    8242    14843085 :             const GPtrDiff_t iOffset =
    8243    14843085 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    8244    14843085 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8245      109836 :                 continue;
    8246    14760102 :             bool bValid = true;
    8247    14760102 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    8248             :                                            iOffset, sNoDataValues, bValid);
    8249    14760102 :             if (!bValid)
    8250       26871 :                 continue;
    8251             : 
    8252    14733202 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    8253    14733202 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    8254             :         }
    8255             :     }
    8256             : 
    8257        6703 :     dfMin = dfLocalMin;
    8258        6703 :     dfMax = dfLocalMax;
    8259        6703 : }
    8260             : 
    8261        6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    8262             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    8263             :                                  int nBlockXSize,
    8264             :                                  const GDALNoDataValues &sNoDataValues,
    8265             :                                  const GByte *pabyMaskData, double &dfMin,
    8266             :                                  double &dfMax)
    8267             : {
    8268        6703 :     switch (eDataType)
    8269             :     {
    8270           0 :         case GDT_Unknown:
    8271           0 :             CPLAssert(false);
    8272             :             break;
    8273         660 :         case GDT_UInt8:
    8274         660 :             if (bSignedByte)
    8275             :             {
    8276           3 :                 ComputeMinMaxGeneric<GDT_UInt8, true>(
    8277             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8278             :                     pabyMaskData, dfMin, dfMax);
    8279             :             }
    8280             :             else
    8281             :             {
    8282         657 :                 ComputeMinMaxGeneric<GDT_UInt8, false>(
    8283             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8284             :                     pabyMaskData, dfMin, dfMax);
    8285             :             }
    8286         660 :             break;
    8287           4 :         case GDT_Int8:
    8288           4 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    8289             :                                                   nBlockXSize, sNoDataValues,
    8290             :                                                   pabyMaskData, dfMin, dfMax);
    8291           4 :             break;
    8292         969 :         case GDT_UInt16:
    8293         969 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    8294             :                                                     nBlockXSize, sNoDataValues,
    8295             :                                                     pabyMaskData, dfMin, dfMax);
    8296         969 :             break;
    8297           2 :         case GDT_Int16:
    8298           2 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    8299             :                                                    nBlockXSize, sNoDataValues,
    8300             :                                                    pabyMaskData, dfMin, dfMax);
    8301           2 :             break;
    8302           3 :         case GDT_UInt32:
    8303           3 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    8304             :                                                     nBlockXSize, sNoDataValues,
    8305             :                                                     pabyMaskData, dfMin, dfMax);
    8306           3 :             break;
    8307           3 :         case GDT_Int32:
    8308           3 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    8309             :                                                    nBlockXSize, sNoDataValues,
    8310             :                                                    pabyMaskData, dfMin, dfMax);
    8311           3 :             break;
    8312           4 :         case GDT_UInt64:
    8313           4 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    8314             :                                                     nBlockXSize, sNoDataValues,
    8315             :                                                     pabyMaskData, dfMin, dfMax);
    8316           4 :             break;
    8317           4 :         case GDT_Int64:
    8318           4 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    8319             :                                                    nBlockXSize, sNoDataValues,
    8320             :                                                    pabyMaskData, dfMin, dfMax);
    8321           4 :             break;
    8322           2 :         case GDT_Float16:
    8323           2 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    8324             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8325             :                 pabyMaskData, dfMin, dfMax);
    8326           2 :             break;
    8327        4941 :         case GDT_Float32:
    8328        4941 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    8329             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8330             :                 pabyMaskData, dfMin, dfMax);
    8331        4941 :             break;
    8332           1 :         case GDT_Float64:
    8333           1 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    8334             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8335             :                 pabyMaskData, dfMin, dfMax);
    8336           1 :             break;
    8337           9 :         case GDT_CInt16:
    8338           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    8339             :                                                     nBlockXSize, sNoDataValues,
    8340             :                                                     pabyMaskData, dfMin, dfMax);
    8341           9 :             break;
    8342           9 :         case GDT_CInt32:
    8343           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    8344             :                                                     nBlockXSize, sNoDataValues,
    8345             :                                                     pabyMaskData, dfMin, dfMax);
    8346           9 :             break;
    8347           0 :         case GDT_CFloat16:
    8348           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    8349             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8350             :                 pabyMaskData, dfMin, dfMax);
    8351           0 :             break;
    8352          75 :         case GDT_CFloat32:
    8353          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    8354             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8355             :                 pabyMaskData, dfMin, dfMax);
    8356          75 :             break;
    8357          17 :         case GDT_CFloat64:
    8358          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    8359             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8360             :                 pabyMaskData, dfMin, dfMax);
    8361          17 :             break;
    8362           0 :         case GDT_TypeCount:
    8363           0 :             CPLAssert(false);
    8364             :             break;
    8365             :     }
    8366        6703 : }
    8367             : 
    8368         189 : static bool ComputeMinMaxGenericIterBlocks(
    8369             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    8370             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    8371             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    8372             :     double &dfMin, double &dfMax)
    8373             : 
    8374             : {
    8375         189 :     GByte *pabyMaskData = nullptr;
    8376             :     int nBlockXSize, nBlockYSize;
    8377         189 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    8378             : 
    8379         189 :     if (poMaskBand)
    8380             :     {
    8381             :         pabyMaskData =
    8382         125 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8383         125 :         if (!pabyMaskData)
    8384             :         {
    8385           0 :             return false;
    8386             :         }
    8387             :     }
    8388             : 
    8389        6892 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    8390        6703 :          iSampleBlock += nSampleRate)
    8391             :     {
    8392        6703 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    8393        6703 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    8394             : 
    8395        6703 :         int nXCheck = 0, nYCheck = 0;
    8396        6703 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8397             : 
    8398       13283 :         if (poMaskBand &&
    8399        6580 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    8400             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    8401             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    8402             :                                  nBlockXSize, nullptr) != CE_None)
    8403             :         {
    8404           0 :             CPLFree(pabyMaskData);
    8405           0 :             return false;
    8406             :         }
    8407             : 
    8408        6703 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    8409        6703 :         if (poBlock == nullptr)
    8410             :         {
    8411           0 :             CPLFree(pabyMaskData);
    8412           0 :             return false;
    8413             :         }
    8414             : 
    8415        6703 :         void *const pData = poBlock->GetDataRef();
    8416             : 
    8417        6703 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    8418             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    8419             :                              dfMax);
    8420             : 
    8421        6703 :         poBlock->DropLock();
    8422             :     }
    8423             : 
    8424         189 :     CPLFree(pabyMaskData);
    8425         189 :     return true;
    8426             : }
    8427             : 
    8428             : /**
    8429             :  * \brief Compute the min/max values for a band.
    8430             :  *
    8431             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    8432             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    8433             :  * get an approximate min/max.  If the band has a nodata value it will
    8434             :  * be excluded from the minimum and maximum.
    8435             :  *
    8436             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    8437             :  * an exact range.
    8438             :  *
    8439             :  * This method is the same as the C function GDALComputeRasterMinMax().
    8440             :  *
    8441             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    8442             :  * FALSE.
    8443             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    8444             :  * maximum (adfMinMax[1]) are returned.
    8445             :  *
    8446             :  * @return CE_None on success or CE_Failure on failure.
    8447             :  */
    8448             : 
    8449        1819 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    8450             : {
    8451             :     /* -------------------------------------------------------------------- */
    8452             :     /*      Does the driver already know the min/max?                       */
    8453             :     /* -------------------------------------------------------------------- */
    8454        1819 :     if (bApproxOK)
    8455             :     {
    8456          23 :         int bSuccessMin = FALSE;
    8457          23 :         int bSuccessMax = FALSE;
    8458             : 
    8459          23 :         double dfMin = GetMinimum(&bSuccessMin);
    8460          23 :         double dfMax = GetMaximum(&bSuccessMax);
    8461             : 
    8462          23 :         if (bSuccessMin && bSuccessMax)
    8463             :         {
    8464           1 :             adfMinMax[0] = dfMin;
    8465           1 :             adfMinMax[1] = dfMax;
    8466           1 :             return CE_None;
    8467             :         }
    8468             :     }
    8469             : 
    8470             :     /* -------------------------------------------------------------------- */
    8471             :     /*      If we have overview bands, use them for min/max.                */
    8472             :     /* -------------------------------------------------------------------- */
    8473             :     // cppcheck-suppress knownConditionTrueFalse
    8474        1818 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    8475             :     {
    8476             :         GDALRasterBand *poBand =
    8477           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    8478             : 
    8479           0 :         if (poBand != this)
    8480           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    8481             :     }
    8482             : 
    8483             :     /* -------------------------------------------------------------------- */
    8484             :     /*      Read actual data and compute minimum and maximum.               */
    8485             :     /* -------------------------------------------------------------------- */
    8486        1818 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8487        1818 :     GDALRasterBand *poMaskBand = nullptr;
    8488        1818 :     if (!sNoDataValues.bGotNoDataValue)
    8489             :     {
    8490        1555 :         const int l_nMaskFlags = GetMaskFlags();
    8491        1680 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8492         125 :             GetColorInterpretation() != GCI_AlphaBand)
    8493             :         {
    8494         125 :             poMaskBand = GetMaskBand();
    8495             :         }
    8496             :     }
    8497             : 
    8498        1818 :     if (!bApproxOK &&
    8499        1796 :         (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
    8500        1658 :          eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
    8501        1455 :          eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
    8502        1409 :          eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
    8503        1796 :          eDataType == GDT_Float64) &&
    8504             :         !poMaskBand)
    8505             :     {
    8506        1470 :         CPLErr eErr = ComputeRasterMinMaxLocation(
    8507         735 :             &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
    8508         735 :         if (eErr == CE_Warning)
    8509             :         {
    8510           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    8511             :                         "Failed to compute min/max, no valid pixels found in "
    8512             :                         "sampling.");
    8513           9 :             eErr = CE_Failure;
    8514             :         }
    8515         735 :         return eErr;
    8516             :     }
    8517             : 
    8518        1083 :     bool bSignedByte = false;
    8519        1083 :     if (eDataType == GDT_UInt8)
    8520             :     {
    8521         783 :         EnablePixelTypeSignedByteWarning(false);
    8522             :         const char *pszPixelType =
    8523         783 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8524         783 :         EnablePixelTypeSignedByteWarning(true);
    8525         783 :         bSignedByte =
    8526         783 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8527             :     }
    8528             : 
    8529             :     GDALRasterIOExtraArg sExtraArg;
    8530        1083 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    8531             : 
    8532        2166 :     GUInt32 nMin = (eDataType == GDT_UInt8)
    8533        1083 :                        ? 255
    8534             :                        : 65535;  // used for GByte & GUInt16 cases
    8535        1083 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    8536        1083 :     GInt16 nMinInt16 =
    8537             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    8538        1083 :     GInt16 nMaxInt16 =
    8539             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    8540        1083 :     double dfMin =
    8541             :         std::numeric_limits<double>::infinity();  // used for generic code path
    8542        1083 :     double dfMax =
    8543             :         -std::numeric_limits<double>::infinity();  // used for generic code path
    8544        1083 :     const bool bUseOptimizedPath =
    8545        1289 :         !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    8546         206 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    8547             : 
    8548             :     const auto ComputeMinMaxForBlock =
    8549       19550 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    8550             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    8551      113170 :                      int nYCheck)
    8552             :     {
    8553       19550 :         if (eDataType == GDT_UInt8 && !bSignedByte)
    8554             :         {
    8555             :             const bool bHasNoData =
    8556       11572 :                 sNoDataValues.bGotNoDataValue &&
    8557       29707 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    8558       11572 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    8559       11572 :                     sNoDataValues.dfNoDataValue;
    8560       18135 :             const GUInt32 nNoDataValue =
    8561       18135 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    8562             :                            : 0;
    8563             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8564             :             ComputeStatisticsInternal<GByte,
    8565             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8566       18135 :                 f(nXCheck, nBufferWidth, nYCheck,
    8567             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    8568       18135 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8569             :         }
    8570        1415 :         else if (eDataType == GDT_UInt16)
    8571             :         {
    8572             :             const bool bHasNoData =
    8573          84 :                 sNoDataValues.bGotNoDataValue &&
    8574        1497 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    8575          84 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    8576          84 :                     sNoDataValues.dfNoDataValue;
    8577        1413 :             const GUInt32 nNoDataValue =
    8578        1413 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    8579             :                            : 0;
    8580             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8581             :             ComputeStatisticsInternal<GUInt16,
    8582             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8583        1413 :                 f(nXCheck, nBufferWidth, nYCheck,
    8584             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    8585             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8586             :         }
    8587           2 :         else if (eDataType == GDT_Int16)
    8588             :         {
    8589             :             const bool bHasNoData =
    8590           0 :                 sNoDataValues.bGotNoDataValue &&
    8591           2 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    8592           0 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    8593           0 :                     sNoDataValues.dfNoDataValue;
    8594           2 :             if (bHasNoData)
    8595             :             {
    8596           0 :                 const int16_t nNoDataValue =
    8597           0 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    8598           0 :                 for (int iY = 0; iY < nYCheck; iY++)
    8599             :                 {
    8600           0 :                     ComputeMinMax<int16_t, true>(
    8601           0 :                         static_cast<const int16_t *>(pData) +
    8602           0 :                             static_cast<size_t>(iY) * nBufferWidth,
    8603             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    8604             :                 }
    8605             :             }
    8606             :             else
    8607             :             {
    8608           4 :                 for (int iY = 0; iY < nYCheck; iY++)
    8609             :                 {
    8610           2 :                     ComputeMinMax<int16_t, false>(
    8611           2 :                         static_cast<const int16_t *>(pData) +
    8612           2 :                             static_cast<size_t>(iY) * nBufferWidth,
    8613             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    8614             :                 }
    8615             :             }
    8616             :         }
    8617       19550 :     };
    8618             : 
    8619        1083 :     if (bApproxOK && HasArbitraryOverviews())
    8620             :     {
    8621             :         /* --------------------------------------------------------------------
    8622             :          */
    8623             :         /*      Figure out how much the image should be reduced to get an */
    8624             :         /*      approximate value. */
    8625             :         /* --------------------------------------------------------------------
    8626             :          */
    8627           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    8628           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    8629             : 
    8630           0 :         int nXReduced = nRasterXSize;
    8631           0 :         int nYReduced = nRasterYSize;
    8632           0 :         if (dfReduction > 1.0)
    8633             :         {
    8634           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    8635           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    8636             : 
    8637             :             // Catch the case of huge resizing ratios here
    8638           0 :             if (nXReduced == 0)
    8639           0 :                 nXReduced = 1;
    8640           0 :             if (nYReduced == 0)
    8641           0 :                 nYReduced = 1;
    8642             :         }
    8643             : 
    8644           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    8645           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    8646             : 
    8647             :         const CPLErr eErr =
    8648           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    8649           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    8650           0 :         if (eErr != CE_None)
    8651             :         {
    8652           0 :             CPLFree(pData);
    8653           0 :             return eErr;
    8654             :         }
    8655             : 
    8656           0 :         GByte *pabyMaskData = nullptr;
    8657           0 :         if (poMaskBand)
    8658             :         {
    8659             :             pabyMaskData =
    8660           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    8661           0 :             if (!pabyMaskData)
    8662             :             {
    8663           0 :                 CPLFree(pData);
    8664           0 :                 return CE_Failure;
    8665             :             }
    8666             : 
    8667           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    8668             :                                      pabyMaskData, nXReduced, nYReduced,
    8669           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    8670             :             {
    8671           0 :                 CPLFree(pData);
    8672           0 :                 CPLFree(pabyMaskData);
    8673           0 :                 return CE_Failure;
    8674             :             }
    8675             :         }
    8676             : 
    8677           0 :         if (bUseOptimizedPath)
    8678             :         {
    8679           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    8680             :         }
    8681             :         else
    8682             :         {
    8683           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    8684             :                                  nYReduced, nXReduced, sNoDataValues,
    8685             :                                  pabyMaskData, dfMin, dfMax);
    8686             :         }
    8687             : 
    8688           0 :         CPLFree(pData);
    8689           0 :         CPLFree(pabyMaskData);
    8690             :     }
    8691             : 
    8692             :     else  // No arbitrary overviews
    8693             :     {
    8694        1083 :         if (!InitBlockInfo())
    8695           0 :             return CE_Failure;
    8696             : 
    8697             :         /* --------------------------------------------------------------------
    8698             :          */
    8699             :         /*      Figure out the ratio of blocks we will read to get an */
    8700             :         /*      approximate value. */
    8701             :         /* --------------------------------------------------------------------
    8702             :          */
    8703        1083 :         int nSampleRate = 1;
    8704             : 
    8705        1083 :         if (bApproxOK)
    8706             :         {
    8707          22 :             nSampleRate = static_cast<int>(std::max(
    8708          44 :                 1.0,
    8709          22 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    8710             :             // We want to avoid probing only the first column of blocks for
    8711             :             // a square shaped raster, because it is not unlikely that it may
    8712             :             // be padding only (#6378).
    8713          22 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    8714           0 :                 nSampleRate += 1;
    8715             :         }
    8716             : 
    8717        1083 :         if (bUseOptimizedPath)
    8718             :         {
    8719         894 :             for (GIntBig iSampleBlock = 0;
    8720       20370 :                  iSampleBlock <
    8721       20370 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8722       19476 :                  iSampleBlock += nSampleRate)
    8723             :             {
    8724       19552 :                 const int iYBlock =
    8725       19552 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    8726       19552 :                 const int iXBlock =
    8727       19552 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    8728             : 
    8729       19552 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    8730       19552 :                 if (poBlock == nullptr)
    8731           2 :                     return CE_Failure;
    8732             : 
    8733       19550 :                 void *const pData = poBlock->GetDataRef();
    8734             : 
    8735       19550 :                 int nXCheck = 0, nYCheck = 0;
    8736       19550 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8737             : 
    8738       19550 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    8739             : 
    8740       19550 :                 poBlock->DropLock();
    8741             : 
    8742       19550 :                 if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
    8743        4110 :                     nMax == 255)
    8744          74 :                     break;
    8745             :             }
    8746             :         }
    8747             :         else
    8748             :         {
    8749         189 :             const GIntBig nTotalBlocks =
    8750         189 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8751         189 :             if (!ComputeMinMaxGenericIterBlocks(
    8752             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    8753             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    8754             :             {
    8755           0 :                 return CE_Failure;
    8756             :             }
    8757             :         }
    8758             :     }
    8759             : 
    8760        1081 :     if (bUseOptimizedPath)
    8761             :     {
    8762         892 :         if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
    8763             :         {
    8764         891 :             dfMin = nMin;
    8765         891 :             dfMax = nMax;
    8766             :         }
    8767           1 :         else if (eDataType == GDT_Int16)
    8768             :         {
    8769           1 :             dfMin = nMinInt16;
    8770           1 :             dfMax = nMaxInt16;
    8771             :         }
    8772             :     }
    8773             : 
    8774        1081 :     if (dfMin > dfMax)
    8775             :     {
    8776          24 :         adfMinMax[0] = 0;
    8777          24 :         adfMinMax[1] = 0;
    8778          24 :         ReportError(
    8779             :             CE_Failure, CPLE_AppDefined,
    8780             :             "Failed to compute min/max, no valid pixels found in sampling.");
    8781          24 :         return CE_Failure;
    8782             :     }
    8783             : 
    8784        1057 :     adfMinMax[0] = dfMin;
    8785        1057 :     adfMinMax[1] = dfMax;
    8786             : 
    8787        1057 :     return CE_None;
    8788             : }
    8789             : 
    8790             : /************************************************************************/
    8791             : /*                      GDALComputeRasterMinMax()                       */
    8792             : /************************************************************************/
    8793             : 
    8794             : /**
    8795             :  * \brief Compute the min/max values for a band.
    8796             :  *
    8797             :  * @see GDALRasterBand::ComputeRasterMinMax()
    8798             :  *
    8799             :  * @note Prior to GDAL 3.6, this function returned void
    8800             :  */
    8801             : 
    8802        1668 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    8803             :                                            double adfMinMax[2])
    8804             : 
    8805             : {
    8806        1668 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    8807             : 
    8808        1668 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8809        1668 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    8810             : }
    8811             : 
    8812             : /************************************************************************/
    8813             : /*                    ComputeRasterMinMaxLocation()                     */
    8814             : /************************************************************************/
    8815             : 
    8816             : /**
    8817             :  * \brief Compute the min/max values for a band, and their location.
    8818             :  *
    8819             :  * Pixels whose value matches the nodata value or are masked by the mask
    8820             :  * band are ignored.
    8821             :  *
    8822             :  * If the minimum or maximum value is hit in several locations, it is not
    8823             :  * specified which one will be returned.
    8824             :  *
    8825             :  * @param[out] pdfMin Pointer to the minimum value.
    8826             :  * @param[out] pdfMax Pointer to the maximum value.
    8827             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    8828             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    8829             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    8830             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    8831             :  *
    8832             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    8833             :  *         CE_Failure in case of error.
    8834             :  *
    8835             :  * @since GDAL 3.11
    8836             :  */
    8837             : 
    8838         751 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    8839             :                                                    double *pdfMax, int *pnMinX,
    8840             :                                                    int *pnMinY, int *pnMaxX,
    8841             :                                                    int *pnMaxY)
    8842             : {
    8843         751 :     int nMinX = -1;
    8844         751 :     int nMinY = -1;
    8845         751 :     int nMaxX = -1;
    8846         751 :     int nMaxY = -1;
    8847         751 :     double dfMin = std::numeric_limits<double>::infinity();
    8848         751 :     double dfMax = -std::numeric_limits<double>::infinity();
    8849         751 :     if (pdfMin)
    8850         748 :         *pdfMin = dfMin;
    8851         751 :     if (pdfMax)
    8852         748 :         *pdfMax = dfMax;
    8853         751 :     if (pnMinX)
    8854          14 :         *pnMinX = nMinX;
    8855         751 :     if (pnMinY)
    8856          14 :         *pnMinY = nMinY;
    8857         751 :     if (pnMaxX)
    8858          14 :         *pnMaxX = nMaxX;
    8859         751 :     if (pnMaxY)
    8860          14 :         *pnMaxY = nMaxY;
    8861             : 
    8862         751 :     if (GDALDataTypeIsComplex(eDataType))
    8863             :     {
    8864           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    8865             :                  "Complex data type not supported");
    8866           0 :         return CE_Failure;
    8867             :     }
    8868             : 
    8869         751 :     if (!InitBlockInfo())
    8870           0 :         return CE_Failure;
    8871             : 
    8872         751 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8873         751 :     GDALRasterBand *poMaskBand = nullptr;
    8874         751 :     if (!sNoDataValues.bGotNoDataValue)
    8875             :     {
    8876         578 :         const int l_nMaskFlags = GetMaskFlags();
    8877         579 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8878           1 :             GetColorInterpretation() != GCI_AlphaBand)
    8879             :         {
    8880           1 :             poMaskBand = GetMaskBand();
    8881             :         }
    8882             :     }
    8883             : 
    8884         751 :     bool bSignedByte = false;
    8885         751 :     if (eDataType == GDT_UInt8)
    8886             :     {
    8887           7 :         EnablePixelTypeSignedByteWarning(false);
    8888             :         const char *pszPixelType =
    8889           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8890           7 :         EnablePixelTypeSignedByteWarning(true);
    8891           7 :         bSignedByte =
    8892           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8893             :     }
    8894             : 
    8895         751 :     GByte *pabyMaskData = nullptr;
    8896         751 :     if (poMaskBand)
    8897             :     {
    8898             :         pabyMaskData =
    8899           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8900           1 :         if (!pabyMaskData)
    8901             :         {
    8902           0 :             return CE_Failure;
    8903             :         }
    8904             :     }
    8905             : 
    8906         751 :     const GIntBig nTotalBlocks =
    8907         751 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8908         751 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    8909         751 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    8910        7857 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    8911             :     {
    8912        7109 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    8913        7109 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    8914             : 
    8915        7109 :         int nXCheck = 0, nYCheck = 0;
    8916        7109 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8917             : 
    8918        7111 :         if (poMaskBand &&
    8919           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    8920           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    8921             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    8922           2 :                                  nBlockXSize, nullptr) != CE_None)
    8923             :         {
    8924           0 :             CPLFree(pabyMaskData);
    8925           0 :             return CE_Failure;
    8926             :         }
    8927             : 
    8928        7109 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    8929        7109 :         if (poBlock == nullptr)
    8930             :         {
    8931           0 :             CPLFree(pabyMaskData);
    8932           0 :             return CE_Failure;
    8933             :         }
    8934             : 
    8935        7109 :         void *const pData = poBlock->GetDataRef();
    8936             : 
    8937        7109 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    8938             :         {
    8939        5059 :             for (int iY = 0; iY < nYCheck; ++iY)
    8940             :             {
    8941      238290 :                 for (int iX = 0; iX < nXCheck; ++iX)
    8942             :                 {
    8943      233478 :                     const GPtrDiff_t iOffset =
    8944      233478 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    8945      233478 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8946           2 :                         continue;
    8947      233476 :                     bool bValid = true;
    8948             :                     double dfValue =
    8949      233476 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    8950             :                                       sNoDataValues, bValid);
    8951      233476 :                     if (!bValid)
    8952           0 :                         continue;
    8953      233476 :                     if (dfValue < dfMin)
    8954             :                     {
    8955         606 :                         dfMin = dfValue;
    8956         606 :                         nMinX = iXBlock * nBlockXSize + iX;
    8957         606 :                         nMinY = iYBlock * nBlockYSize + iY;
    8958             :                     }
    8959      233476 :                     if (dfValue > dfMax)
    8960             :                     {
    8961        1515 :                         dfMax = dfValue;
    8962        1515 :                         nMaxX = iXBlock * nBlockXSize + iX;
    8963        1515 :                         nMaxY = iYBlock * nBlockYSize + iY;
    8964             :                     }
    8965             :                 }
    8966         247 :             }
    8967             :         }
    8968             :         else
    8969             :         {
    8970        6862 :             size_t pos_min = 0;
    8971        6862 :             size_t pos_max = 0;
    8972        6862 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    8973        6862 :             if (bNeedsMin && bNeedsMax)
    8974             :             {
    8975       13716 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    8976        6858 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8977        6858 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8978       13716 :                     sNoDataValues.dfNoDataValue);
    8979             :             }
    8980           4 :             else if (bNeedsMin)
    8981             :             {
    8982           1 :                 pos_min = gdal::min_element(
    8983           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8984           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8985             :                     sNoDataValues.dfNoDataValue);
    8986             :             }
    8987           3 :             else if (bNeedsMax)
    8988             :             {
    8989           2 :                 pos_max = gdal::max_element(
    8990           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8991           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8992             :                     sNoDataValues.dfNoDataValue);
    8993             :             }
    8994             : 
    8995        6862 :             if (bNeedsMin)
    8996             :             {
    8997        6859 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    8998        6859 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    8999        6859 :                 bool bValid = true;
    9000             :                 const double dfMinValueBlock =
    9001        6859 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    9002             :                                   sNoDataValues, bValid);
    9003        6859 :                 if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
    9004             :                 {
    9005        1042 :                     dfMin = dfMinValueBlock;
    9006        1042 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    9007        1042 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    9008             :                 }
    9009             :             }
    9010             : 
    9011        6862 :             if (bNeedsMax)
    9012             :             {
    9013        6860 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    9014        6860 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    9015        6860 :                 bool bValid = true;
    9016             :                 const double dfMaxValueBlock =
    9017        6860 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    9018             :                                   sNoDataValues, bValid);
    9019        6860 :                 if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
    9020             :                 {
    9021         962 :                     dfMax = dfMaxValueBlock;
    9022         962 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    9023         962 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    9024             :                 }
    9025             :             }
    9026             :         }
    9027             : 
    9028        7109 :         poBlock->DropLock();
    9029             : 
    9030        7109 :         if (eDataType == GDT_UInt8)
    9031             :         {
    9032          10 :             if (bNeedsMin && dfMin == 0)
    9033             :             {
    9034           1 :                 bNeedsMin = false;
    9035             :             }
    9036          10 :             if (bNeedsMax && dfMax == 255)
    9037             :             {
    9038           4 :                 bNeedsMax = false;
    9039             :             }
    9040          10 :             if (!bNeedsMin && !bNeedsMax)
    9041             :             {
    9042           3 :                 break;
    9043             :             }
    9044             :         }
    9045             :     }
    9046             : 
    9047         751 :     CPLFree(pabyMaskData);
    9048             : 
    9049         751 :     if (pdfMin)
    9050         748 :         *pdfMin = dfMin;
    9051         751 :     if (pdfMax)
    9052         748 :         *pdfMax = dfMax;
    9053         751 :     if (pnMinX)
    9054          14 :         *pnMinX = nMinX;
    9055         751 :     if (pnMinY)
    9056          14 :         *pnMinY = nMinY;
    9057         751 :     if (pnMaxX)
    9058          14 :         *pnMaxX = nMaxX;
    9059         751 :     if (pnMaxY)
    9060          14 :         *pnMaxY = nMaxY;
    9061         751 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    9062         751 :                                                                   : CE_None;
    9063             : }
    9064             : 
    9065             : /************************************************************************/
    9066             : /*                  GDALComputeRasterMinMaxLocation()                   */
    9067             : /************************************************************************/
    9068             : 
    9069             : /**
    9070             :  * \brief Compute the min/max values for a band, and their location.
    9071             :  *
    9072             :  * @see GDALRasterBand::ComputeRasterMinMax()
    9073             :  * @since GDAL 3.11
    9074             :  */
    9075             : 
    9076          14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    9077             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    9078             :                                        int *pnMaxX, int *pnMaxY)
    9079             : 
    9080             : {
    9081          14 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    9082             : 
    9083          14 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9084          14 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    9085          14 :                                                pnMaxX, pnMaxY);
    9086             : }
    9087             : 
    9088             : /************************************************************************/
    9089             : /*                        SetDefaultHistogram()                         */
    9090             : /************************************************************************/
    9091             : 
    9092             : /* FIXME : add proper documentation */
    9093             : /**
    9094             :  * \brief Set default histogram.
    9095             :  *
    9096             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    9097             :  * GDALSetDefaultHistogramEx()
    9098             :  */
    9099           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    9100             :                                            double /* dfMax */,
    9101             :                                            int /* nBuckets */,
    9102             :                                            GUIntBig * /* panHistogram */)
    9103             : 
    9104             : {
    9105           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    9106           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    9107             :                     "SetDefaultHistogram() not implemented for this format.");
    9108             : 
    9109           0 :     return CE_Failure;
    9110             : }
    9111             : 
    9112             : /************************************************************************/
    9113             : /*                      GDALSetDefaultHistogram()                       */
    9114             : /************************************************************************/
    9115             : 
    9116             : /**
    9117             :  * \brief Set default histogram.
    9118             :  *
    9119             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    9120             :  * 2 billion.
    9121             :  *
    9122             :  * @see GDALRasterBand::SetDefaultHistogram()
    9123             :  * @see GDALSetRasterHistogramEx()
    9124             :  */
    9125             : 
    9126           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    9127             :                                            double dfMax, int nBuckets,
    9128             :                                            int *panHistogram)
    9129             : 
    9130             : {
    9131           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    9132             : 
    9133           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9134             : 
    9135             :     GUIntBig *panHistogramTemp =
    9136           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    9137           0 :     if (panHistogramTemp == nullptr)
    9138             :     {
    9139           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    9140             :                             "Out of memory in GDALSetDefaultHistogram().");
    9141           0 :         return CE_Failure;
    9142             :     }
    9143             : 
    9144           0 :     for (int i = 0; i < nBuckets; ++i)
    9145             :     {
    9146           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    9147             :     }
    9148             : 
    9149             :     const CPLErr eErr =
    9150           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    9151             : 
    9152           0 :     CPLFree(panHistogramTemp);
    9153             : 
    9154           0 :     return eErr;
    9155             : }
    9156             : 
    9157             : /************************************************************************/
    9158             : /*                     GDALSetDefaultHistogramEx()                      */
    9159             : /************************************************************************/
    9160             : 
    9161             : /**
    9162             :  * \brief Set default histogram.
    9163             :  *
    9164             :  * @see GDALRasterBand::SetDefaultHistogram()
    9165             :  *
    9166             :  */
    9167             : 
    9168           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    9169             :                                              double dfMin, double dfMax,
    9170             :                                              int nBuckets,
    9171             :                                              GUIntBig *panHistogram)
    9172             : 
    9173             : {
    9174           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    9175             : 
    9176           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9177           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    9178             : }
    9179             : 
    9180             : /************************************************************************/
    9181             : /*                           GetDefaultRAT()                            */
    9182             : /************************************************************************/
    9183             : 
    9184             : /**
    9185             :  * \brief Fetch default Raster Attribute Table.
    9186             :  *
    9187             :  * A RAT will be returned if there is a default one associated with the
    9188             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    9189             :  * band and should not be deleted by the application.
    9190             :  *
    9191             :  * This method is the same as the C function GDALGetDefaultRAT().
    9192             :  *
    9193             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    9194             :  */
    9195             : 
    9196         180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    9197             : 
    9198             : {
    9199         180 :     return nullptr;
    9200             : }
    9201             : 
    9202             : /************************************************************************/
    9203             : /*                         GDALGetDefaultRAT()                          */
    9204             : /************************************************************************/
    9205             : 
    9206             : /**
    9207             :  * \brief Fetch default Raster Attribute Table.
    9208             :  *
    9209             :  * @see GDALRasterBand::GetDefaultRAT()
    9210             :  */
    9211             : 
    9212        1249 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    9213             : 
    9214             : {
    9215        1249 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    9216             : 
    9217        1249 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9218        1249 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    9219             : }
    9220             : 
    9221             : /************************************************************************/
    9222             : /*                           SetDefaultRAT()                            */
    9223             : /************************************************************************/
    9224             : 
    9225             : /**
    9226             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    9227             :  * \brief Set default Raster Attribute Table.
    9228             :  *
    9229             :  * Associates a default RAT with the band.  If not implemented for the
    9230             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    9231             :  * of the RAT is made, the original remains owned by the caller.
    9232             :  *
    9233             :  * This method is the same as the C function GDALSetDefaultRAT().
    9234             :  *
    9235             :  * @param poRAT the RAT to assign to the band.
    9236             :  *
    9237             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    9238             :  * failing.
    9239             :  */
    9240             : 
    9241             : /**/
    9242             : /**/
    9243             : 
    9244             : CPLErr
    9245           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    9246             : {
    9247           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    9248             :     {
    9249           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    9250           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    9251             :                     "SetDefaultRAT() not implemented for this format.");
    9252           0 :         CPLPopErrorHandler();
    9253             :     }
    9254           0 :     return CE_Failure;
    9255             : }
    9256             : 
    9257             : /************************************************************************/
    9258             : /*                         GDALSetDefaultRAT()                          */
    9259             : /************************************************************************/
    9260             : 
    9261             : /**
    9262             :  * \brief Set default Raster Attribute Table.
    9263             :  *
    9264             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    9265             :  */
    9266             : 
    9267          39 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    9268             :                                      GDALRasterAttributeTableH hRAT)
    9269             : 
    9270             : {
    9271          39 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    9272             : 
    9273          39 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9274             : 
    9275          39 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    9276             : }
    9277             : 
    9278             : /************************************************************************/
    9279             : /*                             HasNoData()                              */
    9280             : /************************************************************************/
    9281             : 
    9282      133565 : bool GDALRasterBand::HasNoData() const
    9283             : {
    9284      133565 :     int bHaveNoDataRaw = FALSE;
    9285      133565 :     bool bHaveNoData = false;
    9286      133565 :     GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
    9287      133565 :     if (eDataType == GDT_Int64)
    9288             :     {
    9289         212 :         CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
    9290         212 :         bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9291             :     }
    9292      133353 :     else if (eDataType == GDT_UInt64)
    9293             :     {
    9294         160 :         CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    9295         160 :         bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9296             :     }
    9297             :     else
    9298             :     {
    9299      133193 :         const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
    9300      133193 :         if (bHaveNoDataRaw &&
    9301      133193 :             GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    9302             :         {
    9303        1184 :             bHaveNoData = true;
    9304             :         }
    9305             :     }
    9306      133565 :     return bHaveNoData;
    9307             : }
    9308             : 
    9309             : /************************************************************************/
    9310             : /*                            GetMaskBand()                             */
    9311             : /************************************************************************/
    9312             : 
    9313             : /**
    9314             :  * \brief Return the mask band associated with the band.
    9315             :  *
    9316             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9317             :  * that returns one of four default implementations :
    9318             :  * <ul>
    9319             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9320             :  * </li>
    9321             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9322             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9323             :  * GMF_NODATA | GMF_PER_DATASET.
    9324             :  * </li>
    9325             :  * <li>If the band has a nodata value set, an instance of the new
    9326             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9327             :  * GMF_NODATA.
    9328             :  * </li>
    9329             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    9330             :  * to apply to this band (specific rules yet to be determined) and that is of
    9331             :  * type GDT_UInt8 then that alpha band will be returned, and the flags
    9332             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9333             :  * </li>
    9334             :  * <li>If neither of the above apply, an instance of the new
    9335             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9336             :  * pixels. The null flags will return GMF_ALL_VALID.
    9337             :  * </li>
    9338             :  * </ul>
    9339             :  *
    9340             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    9341             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    9342             :  *
    9343             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9344             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9345             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9346             :  * main dataset.
    9347             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9348             :  * level, where xx matches the band number of a band of the main dataset. The
    9349             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9350             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9351             :  * a band, then the other rules explained above will be used to generate a
    9352             :  * on-the-fly mask band.
    9353             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9354             :  *
    9355             :  * This method is the same as the C function GDALGetMaskBand().
    9356             :  *
    9357             :  * @return a valid mask band.
    9358             :  *
    9359             :  *
    9360             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9361             :  *
    9362             :  */
    9363      814214 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    9364             : 
    9365             : {
    9366      814214 :     if (poMask != nullptr)
    9367             :     {
    9368      714428 :         if (poMask.IsOwned())
    9369             :         {
    9370      334370 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    9371             :             {
    9372       33697 :                 if (HasNoData())
    9373             :                 {
    9374           9 :                     InvalidateMaskBand();
    9375             :                 }
    9376             :             }
    9377      300673 :             else if (auto poNoDataMaskBand =
    9378      300673 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    9379             :             {
    9380         412 :                 int bHaveNoDataRaw = FALSE;
    9381         412 :                 bool bIsSame = false;
    9382         412 :                 if (eDataType == GDT_Int64)
    9383          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    9384          27 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    9385          10 :                               bHaveNoDataRaw;
    9386         395 :                 else if (eDataType == GDT_UInt64)
    9387          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    9388          27 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    9389          10 :                               bHaveNoDataRaw;
    9390             :                 else
    9391             :                 {
    9392             :                     const double dfNoDataValue =
    9393         378 :                         GetNoDataValue(&bHaveNoDataRaw);
    9394         378 :                     if (bHaveNoDataRaw)
    9395             :                     {
    9396         375 :                         bIsSame =
    9397         375 :                             std::isnan(dfNoDataValue)
    9398         375 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    9399         340 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    9400             :                                       dfNoDataValue;
    9401             :                     }
    9402             :                 }
    9403         412 :                 if (!bIsSame)
    9404          23 :                     InvalidateMaskBand();
    9405             :             }
    9406             :         }
    9407             : 
    9408      714428 :         if (poMask)
    9409      714396 :             return poMask.get();
    9410             :     }
    9411             : 
    9412             :     /* -------------------------------------------------------------------- */
    9413             :     /*      Check for a mask in a .msk file.                                */
    9414             :     /* -------------------------------------------------------------------- */
    9415       99818 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    9416             :     {
    9417          47 :         poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
    9418          47 :         if (poMask != nullptr)
    9419             :         {
    9420          45 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    9421          45 :             return poMask.get();
    9422             :         }
    9423             :     }
    9424             : 
    9425             :     /* -------------------------------------------------------------------- */
    9426             :     /*      Check for NODATA_VALUES metadata.                               */
    9427             :     /* -------------------------------------------------------------------- */
    9428       99773 :     if (poDS != nullptr)
    9429             :     {
    9430             :         const char *pszGDALNoDataValues =
    9431       99753 :             poDS->GetMetadataItem("NODATA_VALUES");
    9432       99753 :         if (pszGDALNoDataValues != nullptr)
    9433             :         {
    9434          71 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    9435             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    9436             : 
    9437             :             // Make sure we have as many values as bands.
    9438         140 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    9439          69 :                 poDS->GetRasterCount() != 0)
    9440             :             {
    9441             :                 // Make sure that all bands have the same data type
    9442             :                 // This is clearly not a fundamental condition, just a
    9443             :                 // condition to make implementation easier.
    9444          69 :                 GDALDataType eDT = GDT_Unknown;
    9445          69 :                 int i = 0;  // Used after for.
    9446         272 :                 for (; i < poDS->GetRasterCount(); ++i)
    9447             :                 {
    9448         203 :                     if (i == 0)
    9449          69 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    9450         134 :                     else if (eDT !=
    9451         134 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    9452             :                     {
    9453           0 :                         break;
    9454             :                     }
    9455             :                 }
    9456          69 :                 if (i == poDS->GetRasterCount())
    9457             :                 {
    9458          69 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    9459             :                     try
    9460             :                     {
    9461          69 :                         poMask.reset(
    9462         138 :                             std::make_unique<GDALNoDataValuesMaskBand>(poDS));
    9463             :                     }
    9464           0 :                     catch (const std::bad_alloc &)
    9465             :                     {
    9466           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9467           0 :                         poMask.reset();
    9468             :                     }
    9469          69 :                     CSLDestroy(papszGDALNoDataValues);
    9470          69 :                     return poMask.get();
    9471             :                 }
    9472             :                 else
    9473             :                 {
    9474           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    9475             :                                 "All bands should have the same type in "
    9476             :                                 "order the NODATA_VALUES metadata item "
    9477             :                                 "to be used as a mask.");
    9478             :                 }
    9479             :             }
    9480             :             else
    9481             :             {
    9482           2 :                 ReportError(
    9483             :                     CE_Warning, CPLE_AppDefined,
    9484             :                     "NODATA_VALUES metadata item doesn't have the same number "
    9485             :                     "of values as the number of bands.  "
    9486             :                     "Ignoring it for mask.");
    9487             :             }
    9488             : 
    9489           2 :             CSLDestroy(papszGDALNoDataValues);
    9490             :         }
    9491             :     }
    9492             : 
    9493             :     /* -------------------------------------------------------------------- */
    9494             :     /*      Check for nodata case.                                          */
    9495             :     /* -------------------------------------------------------------------- */
    9496       99704 :     if (HasNoData())
    9497             :     {
    9498        1174 :         nMaskFlags = GMF_NODATA;
    9499             :         try
    9500             :         {
    9501        1174 :             poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
    9502             :         }
    9503           0 :         catch (const std::bad_alloc &)
    9504             :         {
    9505           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9506           0 :             poMask.reset();
    9507             :         }
    9508        1174 :         return poMask.get();
    9509             :     }
    9510             : 
    9511             :     /* -------------------------------------------------------------------- */
    9512             :     /*      Check for alpha case.                                           */
    9513             :     /* -------------------------------------------------------------------- */
    9514       98511 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    9515      197667 :         this == poDS->GetRasterBand(1) &&
    9516         626 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    9517             :     {
    9518         233 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
    9519             :         {
    9520         189 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9521         189 :             poMask.resetNotOwned(poDS->GetRasterBand(2));
    9522         189 :             return poMask.get();
    9523             :         }
    9524          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    9525             :         {
    9526          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9527             :             try
    9528             :             {
    9529          23 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9530          46 :                     poDS->GetRasterBand(2)));
    9531             :             }
    9532           0 :             catch (const std::bad_alloc &)
    9533             :             {
    9534           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9535           0 :                 poMask.reset();
    9536             :             }
    9537          23 :             return poMask.get();
    9538             :         }
    9539             :     }
    9540             : 
    9541       98299 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    9542        3141 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    9543      197355 :          this == poDS->GetRasterBand(3)) &&
    9544        2454 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    9545             :     {
    9546        1578 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
    9547             :         {
    9548        1522 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9549        1522 :             poMask.resetNotOwned(poDS->GetRasterBand(4));
    9550        1522 :             return poMask.get();
    9551             :         }
    9552          56 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    9553             :         {
    9554          42 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9555             :             try
    9556             :             {
    9557          42 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9558          84 :                     poDS->GetRasterBand(4)));
    9559             :             }
    9560           0 :             catch (const std::bad_alloc &)
    9561             :             {
    9562           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9563           0 :                 poMask.reset();
    9564             :             }
    9565          42 :             return poMask.get();
    9566             :         }
    9567             :     }
    9568             : 
    9569             :     /* -------------------------------------------------------------------- */
    9570             :     /*      Fallback to all valid case.                                     */
    9571             :     /* -------------------------------------------------------------------- */
    9572       96754 :     nMaskFlags = GMF_ALL_VALID;
    9573             :     try
    9574             :     {
    9575       96754 :         poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
    9576             :     }
    9577           0 :     catch (const std::bad_alloc &)
    9578             :     {
    9579           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9580           0 :         poMask.reset();
    9581             :     }
    9582             : 
    9583       96754 :     return poMask.get();
    9584             : }
    9585             : 
    9586             : /************************************************************************/
    9587             : /*                          GDALGetMaskBand()                           */
    9588             : /************************************************************************/
    9589             : 
    9590             : /**
    9591             :  * \brief Return the mask band associated with the band.
    9592             :  *
    9593             :  * @see GDALRasterBand::GetMaskBand()
    9594             :  */
    9595             : 
    9596       11049 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    9597             : 
    9598             : {
    9599       11049 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    9600             : 
    9601       11049 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9602       11049 :     return poBand->GetMaskBand();
    9603             : }
    9604             : 
    9605             : /************************************************************************/
    9606             : /*                            GetMaskFlags()                            */
    9607             : /************************************************************************/
    9608             : 
    9609             : /**
    9610             :  * \brief Return the status flags of the mask band associated with the band.
    9611             :  *
    9612             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    9613             :  * the following available definitions that may be extended in the future:
    9614             :  * <ul>
    9615             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    9616             :  * 255. When used this will normally be the only flag set.
    9617             :  * </li>
    9618             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    9619             :  * dataset.
    9620             :  * </li>
    9621             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    9622             :  * and may have values other than 0 and 255.
    9623             :  * </li>
    9624             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    9625             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    9626             :  * </li>
    9627             :  * </ul>
    9628             :  *
    9629             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9630             :  * that returns one of four default implementations:
    9631             :  * <ul>
    9632             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9633             :  * </li>
    9634             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9635             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9636             :  * GMF_NODATA | GMF_PER_DATASET.
    9637             :  * </li>
    9638             :  * <li>If the band has a nodata value set, an instance of the new
    9639             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9640             :  * GMF_NODATA.
    9641             :  * </li>
    9642             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    9643             :  * seems to apply to this band (specific rules yet to be determined) and that is
    9644             :  * of type GDT_UInt8 then that alpha band will be returned, and the flags
    9645             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9646             :  * </li>
    9647             :  * <li>If neither of the above apply, an instance of the new
    9648             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9649             :  * pixels. The null flags will return GMF_ALL_VALID.
    9650             :  * </li>
    9651             :  * </ul>
    9652             :  *
    9653             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9654             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9655             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9656             :  * main dataset.
    9657             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9658             :  * level, where xx matches the band number of a band of the main dataset. The
    9659             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9660             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9661             :  * a band, then the other rules explained above will be used to generate a
    9662             :  * on-the-fly mask band.
    9663             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9664             :  *
    9665             :  * This method is the same as the C function GDALGetMaskFlags().
    9666             :  *
    9667             :  *
    9668             :  * @return a valid mask band.
    9669             :  *
    9670             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9671             :  *
    9672             :  */
    9673      159812 : int GDALRasterBand::GetMaskFlags()
    9674             : 
    9675             : {
    9676             :     // If we don't have a band yet, force this now so that the masks value
    9677             :     // will be initialized.
    9678             : 
    9679      159812 :     if (poMask == nullptr)
    9680       98095 :         GetMaskBand();
    9681             : 
    9682      159812 :     return nMaskFlags;
    9683             : }
    9684             : 
    9685             : /************************************************************************/
    9686             : /*                          GDALGetMaskFlags()                          */
    9687             : /************************************************************************/
    9688             : 
    9689             : /**
    9690             :  * \brief Return the status flags of the mask band associated with the band.
    9691             :  *
    9692             :  * @see GDALRasterBand::GetMaskFlags()
    9693             :  */
    9694             : 
    9695        9131 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    9696             : 
    9697             : {
    9698        9131 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    9699             : 
    9700        9131 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9701        9131 :     return poBand->GetMaskFlags();
    9702             : }
    9703             : 
    9704             : /************************************************************************/
    9705             : /*                         InvalidateMaskBand()                         */
    9706             : /************************************************************************/
    9707             : 
    9708             : //! @cond Doxygen_Suppress
    9709     1858980 : void GDALRasterBand::InvalidateMaskBand()
    9710             : {
    9711     1858980 :     poMask.reset();
    9712     1858980 :     nMaskFlags = 0;
    9713     1858980 : }
    9714             : 
    9715             : //! @endcond
    9716             : 
    9717             : /************************************************************************/
    9718             : /*                           CreateMaskBand()                           */
    9719             : /************************************************************************/
    9720             : 
    9721             : /**
    9722             :  * \brief Adds a mask band to the current band
    9723             :  *
    9724             :  * The default implementation of the CreateMaskBand() method is implemented
    9725             :  * based on similar rules to the .ovr handling implemented using the
    9726             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    9727             :  * be created with the same basename as the original file, and it will have
    9728             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    9729             :  * The mask images will be deflate compressed tiled images with the same
    9730             :  * block size as the original image if possible.
    9731             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9732             :  * level, where xx matches the band number of a band of the main dataset. The
    9733             :  * value of those items will be the one of the nFlagsIn parameter.
    9734             :  *
    9735             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    9736             :  * it might be invalidated by CreateMaskBand(). So you have to call
    9737             :  * GetMaskBand() again.
    9738             :  *
    9739             :  * This method is the same as the C function GDALCreateMaskBand().
    9740             :  *
    9741             :  *
    9742             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    9743             :  *
    9744             :  * @return CE_None on success or CE_Failure on an error.
    9745             :  *
    9746             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9747             :  * @see GDALDataset::CreateMaskBand()
    9748             :  *
    9749             :  */
    9750             : 
    9751          10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    9752             : 
    9753             : {
    9754          10 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    9755             :     {
    9756          10 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    9757          10 :         if (eErr != CE_None)
    9758           1 :             return eErr;
    9759             : 
    9760           9 :         InvalidateMaskBand();
    9761             : 
    9762           9 :         return CE_None;
    9763             :     }
    9764             : 
    9765           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    9766             :                 "CreateMaskBand() not supported for this band.");
    9767             : 
    9768           0 :     return CE_Failure;
    9769             : }
    9770             : 
    9771             : /************************************************************************/
    9772             : /*                         GDALCreateMaskBand()                         */
    9773             : /************************************************************************/
    9774             : 
    9775             : /**
    9776             :  * \brief Adds a mask band to the current band
    9777             :  *
    9778             :  * @see GDALRasterBand::CreateMaskBand()
    9779             :  */
    9780             : 
    9781          36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    9782             : 
    9783             : {
    9784          36 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    9785             : 
    9786          36 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9787          36 :     return poBand->CreateMaskBand(nFlags);
    9788             : }
    9789             : 
    9790             : /************************************************************************/
    9791             : /*                             IsMaskBand()                             */
    9792             : /************************************************************************/
    9793             : 
    9794             : /**
    9795             :  * \brief Returns whether a band is a mask band.
    9796             :  *
    9797             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9798             :  * mask band, an alpha band, or an implicit mask band.
    9799             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9800             :  *
    9801             :  * This method is the same as the C function GDALIsMaskBand().
    9802             :  *
    9803             :  * @return true if the band is a mask band.
    9804             :  *
    9805             :  * @see GDALDataset::CreateMaskBand()
    9806             :  *
    9807             :  * @since GDAL 3.5.0
    9808             :  *
    9809             :  */
    9810             : 
    9811         450 : bool GDALRasterBand::IsMaskBand() const
    9812             : {
    9813             :     // The GeoTIFF driver, among others, override this method to
    9814             :     // also handle external .msk bands.
    9815         450 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    9816         450 :            GCI_AlphaBand;
    9817             : }
    9818             : 
    9819             : /************************************************************************/
    9820             : /*                           GDALIsMaskBand()                           */
    9821             : /************************************************************************/
    9822             : 
    9823             : /**
    9824             :  * \brief Returns whether a band is a mask band.
    9825             :  *
    9826             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9827             :  * mask band, an alpha band, or an implicit mask band.
    9828             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9829             :  *
    9830             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    9831             :  *
    9832             :  * @return true if the band is a mask band.
    9833             :  *
    9834             :  * @see GDALRasterBand::IsMaskBand()
    9835             :  *
    9836             :  * @since GDAL 3.5.0
    9837             :  *
    9838             :  */
    9839             : 
    9840          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    9841             : 
    9842             : {
    9843          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    9844             : 
    9845          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9846          37 :     return poBand->IsMaskBand();
    9847             : }
    9848             : 
    9849             : /************************************************************************/
    9850             : /*                         GetMaskValueRange()                          */
    9851             : /************************************************************************/
    9852             : 
    9853             : /**
    9854             :  * \brief Returns the range of values that a mask band can take.
    9855             :  *
    9856             :  * @return the range of values that a mask band can take.
    9857             :  *
    9858             :  * @since GDAL 3.5.0
    9859             :  *
    9860             :  */
    9861             : 
    9862           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    9863             : {
    9864           0 :     return GMVR_UNKNOWN;
    9865             : }
    9866             : 
    9867             : /************************************************************************/
    9868             : /*                     HasConflictingMaskSources()                      */
    9869             : /************************************************************************/
    9870             : 
    9871             : /**
    9872             :  * \brief Returns whether a raster band has conflicting mask sources.
    9873             :  *
    9874             :  * That is, if more than one of the following conditions is met:
    9875             :  * - it has a binary mask band (that is not an alpha band)
    9876             :  * - it has an external mask flags (.msk file)
    9877             :  * - it has a nodata value
    9878             :  * - it belongs to a dataset with the NODATA_VALUES metadata item set
    9879             :  * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
    9880             :  *
    9881             :  * @param[out] posDetailMessage Pointer to a string that will contain the
    9882             :  *                              details of the conflict.
    9883             :  * @param bMentionPrioritarySource Whether the mask source used should be
    9884             :  *                                 mentioned in *posDetailMessage.
    9885             :  * @since GDAL 3.13.0
    9886             :  */
    9887             : 
    9888         164 : bool GDALRasterBand::HasConflictingMaskSources(
    9889             :     std::string *posDetailMessage, bool bMentionPrioritarySource) const
    9890             : {
    9891         164 :     const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
    9892             :     const bool bHasBinaryMaskBand =
    9893         164 :         ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
    9894         186 :           (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
    9895          22 :         (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
    9896         164 :     const bool bHasNoData = HasNoData();
    9897             :     const bool bHasNODATA_VALUES =
    9898         164 :         poDS && poDS->GetMetadataItem("NODATA_VALUES");
    9899             :     const bool bHasAlphaBand =
    9900         324 :         poDS &&
    9901         160 :         poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
    9902         164 :             GCI_AlphaBand;
    9903             :     const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
    9904         164 :                                   bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
    9905             :     const size_t nCount =
    9906         164 :         std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
    9907         164 :     if (nCount >= 2)
    9908             :     {
    9909          23 :         if (posDetailMessage)
    9910             :         {
    9911          17 :             *posDetailMessage = "Raster band ";
    9912          17 :             *posDetailMessage += std::to_string(nBand);
    9913          17 :             if (poDS && poDS->GetDescription()[0])
    9914             :             {
    9915          11 :                 *posDetailMessage += " of dataset ";
    9916          11 :                 *posDetailMessage += poDS->GetDescription();
    9917             :             }
    9918          17 :             *posDetailMessage += " has several conflicting mask sources:\n";
    9919          17 :             if (bHasExternalMask)
    9920           1 :                 *posDetailMessage += "- internal binary mask band\n";
    9921          17 :             if (bHasExternalMask)
    9922           1 :                 *posDetailMessage += "- external mask band (.msk)\n";
    9923          17 :             if (bHasNoData)
    9924          13 :                 *posDetailMessage += "- nodata value\n";
    9925          17 :             if (bHasNODATA_VALUES)
    9926           9 :                 *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
    9927          17 :             if (bHasAlphaBand)
    9928             :                 *posDetailMessage +=
    9929           7 :                     "- related to a raster band that is an alpha band\n";
    9930          17 :             if (bMentionPrioritarySource)
    9931             :                 *posDetailMessage +=
    9932           6 :                     "Only the first listed one will be taken into account.";
    9933             :         }
    9934          23 :         return true;
    9935             :     }
    9936         141 :     return false;
    9937             : }
    9938             : 
    9939             : /************************************************************************/
    9940             : /*                     GetIndexColorTranslationTo()                     */
    9941             : /************************************************************************/
    9942             : 
    9943             : /**
    9944             :  * \brief Compute translation table for color tables.
    9945             :  *
    9946             :  * When the raster band has a palette index, it may be useful to compute
    9947             :  * the "translation" of this palette to the palette of another band.
    9948             :  * The translation tries to do exact matching first, and then approximate
    9949             :  * matching if no exact matching is possible.
    9950             :  * This method returns a table such that table[i] = j where i is an index
    9951             :  * of the 'this' rasterband and j the corresponding index for the reference
    9952             :  * rasterband.
    9953             :  *
    9954             :  * This method is thought as internal to GDAL and is used for drivers
    9955             :  * like RPFTOC.
    9956             :  *
    9957             :  * The implementation only supports 1-byte palette rasterbands.
    9958             :  *
    9959             :  * @param poReferenceBand the raster band
    9960             :  * @param pTranslationTable an already allocated translation table (at least 256
    9961             :  * bytes), or NULL to let the method allocate it
    9962             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    9963             :  *                              is approximate. May be NULL.
    9964             :  *
    9965             :  * @return a translation table if the two bands are palette index and that they
    9966             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    9967             :  * NULL was passed for pTranslationTable.
    9968             :  */
    9969             : 
    9970             : unsigned char *
    9971           4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    9972             :                                            unsigned char *pTranslationTable,
    9973             :                                            int *pApproximateMatching)
    9974             : {
    9975           4 :     if (poReferenceBand == nullptr)
    9976           0 :         return nullptr;
    9977             : 
    9978             :     // cppcheck-suppress knownConditionTrueFalse
    9979           4 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    9980             :         // cppcheck-suppress knownConditionTrueFalse
    9981           4 :         GetColorInterpretation() == GCI_PaletteIndex &&
    9982          12 :         poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
    9983           4 :         GetRasterDataType() == GDT_UInt8)
    9984             :     {
    9985           4 :         const GDALColorTable *srcColorTable = GetColorTable();
    9986           4 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    9987           4 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    9988             :         {
    9989           4 :             const int nEntries = srcColorTable->GetColorEntryCount();
    9990           4 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    9991             : 
    9992           4 :             int bHasNoDataValueSrc = FALSE;
    9993           4 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    9994           4 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    9995           4 :                   dfNoDataValueSrc <= 255 &&
    9996           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    9997           0 :                 bHasNoDataValueSrc = FALSE;
    9998           4 :             const int noDataValueSrc =
    9999           4 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
   10000             : 
   10001           4 :             int bHasNoDataValueRef = FALSE;
   10002             :             const double dfNoDataValueRef =
   10003           4 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
   10004           4 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
   10005           3 :                   dfNoDataValueRef <= 255 &&
   10006           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
   10007           1 :                 bHasNoDataValueRef = FALSE;
   10008           4 :             const int noDataValueRef =
   10009           4 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
   10010             : 
   10011           4 :             bool samePalette = false;
   10012             : 
   10013           4 :             if (pApproximateMatching)
   10014           3 :                 *pApproximateMatching = FALSE;
   10015             : 
   10016           4 :             if (nEntries == nRefEntries &&
   10017           3 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
   10018           3 :                 (bHasNoDataValueSrc == FALSE ||
   10019             :                  noDataValueSrc == noDataValueRef))
   10020             :             {
   10021           3 :                 samePalette = true;
   10022         654 :                 for (int i = 0; i < nEntries; ++i)
   10023             :                 {
   10024         651 :                     if (noDataValueSrc == i)
   10025           3 :                         continue;
   10026             :                     const GDALColorEntry *entry =
   10027         648 :                         srcColorTable->GetColorEntry(i);
   10028             :                     const GDALColorEntry *entryRef =
   10029         648 :                         destColorTable->GetColorEntry(i);
   10030         648 :                     if (entry->c1 != entryRef->c1 ||
   10031         648 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
   10032             :                     {
   10033           0 :                         samePalette = false;
   10034             :                     }
   10035             :                 }
   10036             :             }
   10037             : 
   10038           4 :             if (!samePalette)
   10039             :             {
   10040           1 :                 if (pTranslationTable == nullptr)
   10041             :                 {
   10042             :                     pTranslationTable = static_cast<unsigned char *>(
   10043           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
   10044           1 :                     if (pTranslationTable == nullptr)
   10045           1 :                         return nullptr;
   10046             :                 }
   10047             : 
   10048             :                 // Trying to remap the product palette on the subdataset
   10049             :                 // palette.
   10050           5 :                 for (int i = 0; i < nEntries; ++i)
   10051             :                 {
   10052           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
   10053             :                         noDataValueSrc == i)
   10054           0 :                         continue;
   10055             :                     const GDALColorEntry *entry =
   10056           4 :                         srcColorTable->GetColorEntry(i);
   10057           4 :                     bool bMatchFound = false;
   10058          13 :                     for (int j = 0; j < nRefEntries; ++j)
   10059             :                     {
   10060          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
   10061           0 :                             continue;
   10062             :                         const GDALColorEntry *entryRef =
   10063          10 :                             destColorTable->GetColorEntry(j);
   10064          10 :                         if (entry->c1 == entryRef->c1 &&
   10065           2 :                             entry->c2 == entryRef->c2 &&
   10066           2 :                             entry->c3 == entryRef->c3)
   10067             :                         {
   10068           1 :                             pTranslationTable[i] =
   10069             :                                 static_cast<unsigned char>(j);
   10070           1 :                             bMatchFound = true;
   10071           1 :                             break;
   10072             :                         }
   10073             :                     }
   10074           4 :                     if (!bMatchFound)
   10075             :                     {
   10076             :                         // No exact match. Looking for closest color now.
   10077           3 :                         int best_j = 0;
   10078           3 :                         int best_distance = 0;
   10079           3 :                         if (pApproximateMatching)
   10080           0 :                             *pApproximateMatching = TRUE;
   10081          12 :                         for (int j = 0; j < nRefEntries; ++j)
   10082             :                         {
   10083             :                             const GDALColorEntry *entryRef =
   10084           9 :                                 destColorTable->GetColorEntry(j);
   10085           9 :                             int distance = (entry->c1 - entryRef->c1) *
   10086           9 :                                                (entry->c1 - entryRef->c1) +
   10087           9 :                                            (entry->c2 - entryRef->c2) *
   10088           9 :                                                (entry->c2 - entryRef->c2) +
   10089           9 :                                            (entry->c3 - entryRef->c3) *
   10090           9 :                                                (entry->c3 - entryRef->c3);
   10091           9 :                             if (j == 0 || distance < best_distance)
   10092             :                             {
   10093           7 :                                 best_j = j;
   10094           7 :                                 best_distance = distance;
   10095             :                             }
   10096             :                         }
   10097           3 :                         pTranslationTable[i] =
   10098             :                             static_cast<unsigned char>(best_j);
   10099             :                     }
   10100             :                 }
   10101           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
   10102           0 :                     pTranslationTable[noDataValueSrc] =
   10103             :                         static_cast<unsigned char>(noDataValueRef);
   10104             : 
   10105           1 :                 return pTranslationTable;
   10106             :             }
   10107             :         }
   10108             :     }
   10109           3 :     return nullptr;
   10110             : }
   10111             : 
   10112             : /************************************************************************/
   10113             : /*                          SetFlushBlockErr()                          */
   10114             : /************************************************************************/
   10115             : 
   10116             : /**
   10117             :  * \brief Store that an error occurred while writing a dirty block.
   10118             :  *
   10119             :  * This function stores the fact that an error occurred while writing a dirty
   10120             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
   10121             :  * flushed when the block cache get full, it is not convenient/possible to
   10122             :  * report that a dirty block could not be written correctly. This function
   10123             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
   10124             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
   10125             :  * places where the user can easily match the error with the relevant dataset.
   10126             :  */
   10127             : 
   10128           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
   10129             : {
   10130           0 :     eFlushBlockErr = eErr;
   10131           0 : }
   10132             : 
   10133             : /************************************************************************/
   10134             : /*                           IncDirtyBlocks()                           */
   10135             : /************************************************************************/
   10136             : 
   10137             : /**
   10138             :  * \brief Increment/decrement the number of dirty blocks
   10139             :  */
   10140             : 
   10141      800682 : void GDALRasterBand::IncDirtyBlocks(int nInc)
   10142             : {
   10143      800682 :     if (poBandBlockCache)
   10144      800682 :         poBandBlockCache->IncDirtyBlocks(nInc);
   10145      800682 : }
   10146             : 
   10147             : /************************************************************************/
   10148             : /*                            ReportError()                             */
   10149             : /************************************************************************/
   10150             : 
   10151             : #ifndef DOXYGEN_XML
   10152             : /**
   10153             :  * \brief Emits an error related to a raster band.
   10154             :  *
   10155             :  * This function is a wrapper for regular CPLError(). The only difference
   10156             :  * with CPLError() is that it prepends the error message with the dataset
   10157             :  * name and the band number.
   10158             :  *
   10159             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
   10160             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
   10161             :  * @param fmt a printf() style format string.  Any additional arguments
   10162             :  * will be treated as arguments to fill in this format in a manner
   10163             :  * similar to printf().
   10164             :  *
   10165             :  */
   10166             : 
   10167        2499 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
   10168             :                                  const char *fmt, ...) const
   10169             : {
   10170             :     va_list args;
   10171             : 
   10172        2499 :     va_start(args, fmt);
   10173             : 
   10174        2499 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
   10175        2499 :     pszDSName = CPLGetFilename(pszDSName);
   10176        2499 :     if (pszDSName[0] != '\0')
   10177             :     {
   10178        2406 :         CPLError(eErrClass, err_no, "%s",
   10179        4812 :                  CPLString()
   10180        2406 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
   10181        4812 :                      .append(CPLString().vPrintf(fmt, args))
   10182             :                      .c_str());
   10183             :     }
   10184             :     else
   10185             :     {
   10186          93 :         CPLErrorV(eErrClass, err_no, fmt, args);
   10187             :     }
   10188             : 
   10189        2499 :     va_end(args);
   10190        2499 : }
   10191             : #endif
   10192             : 
   10193             : /************************************************************************/
   10194             : /*                         GetVirtualMemAuto()                          */
   10195             : /************************************************************************/
   10196             : 
   10197             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
   10198             :  *
   10199             :  * Only supported on Linux and Unix systems with mmap() for now.
   10200             :  *
   10201             :  * This method allows creating a virtual memory object for a GDALRasterBand,
   10202             :  * that exposes the whole image data as a virtual array.
   10203             :  *
   10204             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
   10205             :  * specialized implementation, such as for raw files, may also directly use
   10206             :  * mechanisms of the operating system to create a view of the underlying file
   10207             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
   10208             :  *
   10209             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
   10210             :  * offer a specialized implementation with direct file mapping, provided that
   10211             :  * some requirements are met :
   10212             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
   10213             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
   10214             :  *     must match the native ordering of the CPU.
   10215             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
   10216             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
   10217             :  * the file in sequential order, and be equally spaced (which is generally the
   10218             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
   10219             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
   10220             :  *
   10221             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
   10222             :  * CPLVirtualMemFree() must be called before the raster band object is
   10223             :  * destroyed.
   10224             :  *
   10225             :  * If p is such a pointer and base_type the type matching
   10226             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
   10227             :  * accessed with
   10228             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
   10229             :  *
   10230             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
   10231             :  *
   10232             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
   10233             :  * read/write the band.
   10234             :  *
   10235             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
   10236             :  * one pixel value in the buffer to the start of the next pixel value within a
   10237             :  * scanline.
   10238             :  *
   10239             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
   10240             :  * one scanline in the buffer to the start of the next.
   10241             :  *
   10242             :  * @param papszOptions NULL terminated list of options.
   10243             :  *                     If a specialized implementation exists, defining
   10244             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
   10245             :  * used. On the contrary, defining
   10246             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
   10247             :  * being used (thus only allowing efficient implementations to be used). When
   10248             :  * requiring or falling back to the default implementation, the following
   10249             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
   10250             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
   10251             :  * to FALSE)
   10252             :  *
   10253             :  * @return a virtual memory object that must be unreferenced by
   10254             :  * CPLVirtualMemFree(), or NULL in case of failure.
   10255             :  *
   10256             :  */
   10257             : 
   10258           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
   10259             :                                                  int *pnPixelSpace,
   10260             :                                                  GIntBig *pnLineSpace,
   10261             :                                                  CSLConstList papszOptions)
   10262             : {
   10263           9 :     const char *pszImpl = CSLFetchNameValueDef(
   10264             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
   10265           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
   10266           8 :         EQUAL(pszImpl, "FALSE"))
   10267             :     {
   10268           1 :         return nullptr;
   10269             :     }
   10270             : 
   10271           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
   10272           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
   10273           8 :     if (pnPixelSpace)
   10274           8 :         *pnPixelSpace = nPixelSpace;
   10275           8 :     if (pnLineSpace)
   10276           8 :         *pnLineSpace = nLineSpace;
   10277             :     const size_t nCacheSize =
   10278           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
   10279             :     const size_t nPageSizeHint =
   10280           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
   10281           8 :     const bool bSingleThreadUsage = CPLTestBool(
   10282             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
   10283           8 :     return GDALRasterBandGetVirtualMem(
   10284             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
   10285             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
   10286             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
   10287           8 :         papszOptions);
   10288             : }
   10289             : 
   10290             : /************************************************************************/
   10291             : /*                       GDALGetVirtualMemAuto()                        */
   10292             : /************************************************************************/
   10293             : 
   10294             : /**
   10295             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
   10296             :  *
   10297             :  * @see GDALRasterBand::GetVirtualMemAuto()
   10298             :  */
   10299             : 
   10300          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
   10301             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
   10302             :                                      CSLConstList papszOptions)
   10303             : {
   10304          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
   10305             : 
   10306          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10307             : 
   10308          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
   10309          31 :                                      const_cast<char **>(papszOptions));
   10310             : }
   10311             : 
   10312             : /************************************************************************/
   10313             : /*                     GDALGetDataCoverageStatus()                      */
   10314             : /************************************************************************/
   10315             : 
   10316             : /**
   10317             :  * \brief Get the coverage status of a sub-window of the raster.
   10318             :  *
   10319             :  * Returns whether a sub-window of the raster contains only data, only empty
   10320             :  * blocks or a mix of both. This function can be used to determine quickly
   10321             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10322             :  * be sparse.
   10323             :  *
   10324             :  * Empty blocks are blocks that are generally not physically present in the
   10325             :  * file, and when read through GDAL, contain only pixels whose value is the
   10326             :  * nodata value when it is set, or whose value is 0 when the nodata value is
   10327             :  * not set.
   10328             :  *
   10329             :  * The query is done in an efficient way without reading the actual pixel
   10330             :  * values. If not possible, or not implemented at all by the driver,
   10331             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10332             :  * be returned.
   10333             :  *
   10334             :  * The values that can be returned by the function are the following,
   10335             :  * potentially combined with the binary or operator :
   10336             :  * <ul>
   10337             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10338             :  * GetDataCoverageStatus(). This flag should be returned together with
   10339             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10340             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10341             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10342             :  * the queried window. This is typically identified by the concept of missing
   10343             :  * block in formats that supports it.
   10344             :  * </li>
   10345             :  * </ul>
   10346             :  *
   10347             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10348             :  * should be interpreted more as hint of potential presence of data. For example
   10349             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10350             :  * nodata value), instead of using the missing block mechanism,
   10351             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10352             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10353             :  *
   10354             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10355             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10356             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10357             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10358             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10359             :  * the function will exit, so that you can potentially refine the requested area
   10360             :  * to find which particular region(s) have missing blocks.
   10361             :  *
   10362             :  * @see GDALRasterBand::GetDataCoverageStatus()
   10363             :  *
   10364             :  * @param hBand raster band
   10365             :  *
   10366             :  * @param nXOff The pixel offset to the top left corner of the region
   10367             :  * of the band to be queried. This would be zero to start from the left side.
   10368             :  *
   10369             :  * @param nYOff The line offset to the top left corner of the region
   10370             :  * of the band to be queried. This would be zero to start from the top.
   10371             :  *
   10372             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10373             :  *
   10374             :  * @param nYSize The height of the region of the band to be queried in lines.
   10375             :  *
   10376             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10377             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10378             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10379             :  * as the computation of the coverage matches the mask, the computation will be
   10380             :  * stopped. *pdfDataPct will not be valid in that case.
   10381             :  *
   10382             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10383             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10384             :  * sub-window that have valid values. The implementation might not always be
   10385             :  * able to compute it, in which case it will be set to a negative value.
   10386             :  *
   10387             :  * @return a binary-or'ed combination of possible values
   10388             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10389             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10390             :  */
   10391             : 
   10392          29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
   10393             :                                           int nYOff, int nXSize, int nYSize,
   10394             :                                           int nMaskFlagStop, double *pdfDataPct)
   10395             : {
   10396          29 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
   10397             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
   10398             : 
   10399          29 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10400             : 
   10401          29 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
   10402          29 :                                          nMaskFlagStop, pdfDataPct);
   10403             : }
   10404             : 
   10405             : /************************************************************************/
   10406             : /*                       GetDataCoverageStatus()                        */
   10407             : /************************************************************************/
   10408             : 
   10409             : /**
   10410             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
   10411             :  *                                           int nYOff,
   10412             :  *                                           int nXSize,
   10413             :  *                                           int nYSize,
   10414             :  *                                           int nMaskFlagStop,
   10415             :  *                                           double* pdfDataPct)
   10416             :  * \brief Get the coverage status of a sub-window of the raster.
   10417             :  *
   10418             :  * Returns whether a sub-window of the raster contains only data, only empty
   10419             :  * blocks or a mix of both. This function can be used to determine quickly
   10420             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10421             :  * be sparse.
   10422             :  *
   10423             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10424             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10425             :  *
   10426             :  * The query is done in an efficient way without reading the actual pixel
   10427             :  * values. If not possible, or not implemented at all by the driver,
   10428             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10429             :  * be returned.
   10430             :  *
   10431             :  * The values that can be returned by the function are the following,
   10432             :  * potentially combined with the binary or operator :
   10433             :  * <ul>
   10434             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10435             :  * GetDataCoverageStatus(). This flag should be returned together with
   10436             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10437             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10438             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10439             :  * the queried window. This is typically identified by the concept of missing
   10440             :  * block in formats that supports it.
   10441             :  * </li>
   10442             :  * </ul>
   10443             :  *
   10444             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10445             :  * should be interpreted more as hint of potential presence of data. For example
   10446             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10447             :  * nodata value), instead of using the missing block mechanism,
   10448             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10449             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10450             :  *
   10451             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10452             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10453             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10454             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10455             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10456             :  * the function will exit, so that you can potentially refine the requested area
   10457             :  * to find which particular region(s) have missing blocks.
   10458             :  *
   10459             :  * @see GDALGetDataCoverageStatus()
   10460             :  *
   10461             :  * @param nXOff The pixel offset to the top left corner of the region
   10462             :  * of the band to be queried. This would be zero to start from the left side.
   10463             :  *
   10464             :  * @param nYOff The line offset to the top left corner of the region
   10465             :  * of the band to be queried. This would be zero to start from the top.
   10466             :  *
   10467             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10468             :  *
   10469             :  * @param nYSize The height of the region of the band to be queried in lines.
   10470             :  *
   10471             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10472             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10473             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10474             :  * as the computation of the coverage matches the mask, the computation will be
   10475             :  * stopped. *pdfDataPct will not be valid in that case.
   10476             :  *
   10477             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10478             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10479             :  * sub-window that have valid values. The implementation might not always be
   10480             :  * able to compute it, in which case it will be set to a negative value.
   10481             :  *
   10482             :  * @return a binary-or'ed combination of possible values
   10483             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10484             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10485             :  */
   10486             : 
   10487             : /**
   10488             :  * \brief Get the coverage status of a sub-window of the raster.
   10489             :  *
   10490             :  * Returns whether a sub-window of the raster contains only data, only empty
   10491             :  * blocks or a mix of both. This function can be used to determine quickly
   10492             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10493             :  * be sparse.
   10494             :  *
   10495             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10496             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10497             :  *
   10498             :  * The query is done in an efficient way without reading the actual pixel
   10499             :  * values. If not possible, or not implemented at all by the driver,
   10500             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10501             :  * be returned.
   10502             :  *
   10503             :  * The values that can be returned by the function are the following,
   10504             :  * potentially combined with the binary or operator :
   10505             :  * <ul>
   10506             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10507             :  * GetDataCoverageStatus(). This flag should be returned together with
   10508             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10509             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10510             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10511             :  * the queried window. This is typically identified by the concept of missing
   10512             :  * block in formats that supports it.
   10513             :  * </li>
   10514             :  * </ul>
   10515             :  *
   10516             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10517             :  * should be interpreted more as hint of potential presence of data. For example
   10518             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10519             :  * nodata value), instead of using the missing block mechanism,
   10520             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10521             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10522             :  *
   10523             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10524             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10525             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10526             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10527             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10528             :  * the function will exit, so that you can potentially refine the requested area
   10529             :  * to find which particular region(s) have missing blocks.
   10530             :  *
   10531             :  * @see GDALGetDataCoverageStatus()
   10532             :  *
   10533             :  * @param nXOff The pixel offset to the top left corner of the region
   10534             :  * of the band to be queried. This would be zero to start from the left side.
   10535             :  *
   10536             :  * @param nYOff The line offset to the top left corner of the region
   10537             :  * of the band to be queried. This would be zero to start from the top.
   10538             :  *
   10539             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10540             :  *
   10541             :  * @param nYSize The height of the region of the band to be queried in lines.
   10542             :  *
   10543             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10544             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10545             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10546             :  * as the computation of the coverage matches the mask, the computation will be
   10547             :  * stopped. *pdfDataPct will not be valid in that case.
   10548             :  *
   10549             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10550             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10551             :  * sub-window that have valid values. The implementation might not always be
   10552             :  * able to compute it, in which case it will be set to a negative value.
   10553             :  *
   10554             :  * @return a binary-or'ed combination of possible values
   10555             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10556             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10557             :  */
   10558             : 
   10559        4723 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
   10560             :                                           int nYSize, int nMaskFlagStop,
   10561             :                                           double *pdfDataPct)
   10562             : {
   10563        4723 :     if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
   10564        4723 :         nYSize > nRasterYSize - nYOff)
   10565             :     {
   10566           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
   10567           0 :         if (pdfDataPct)
   10568           0 :             *pdfDataPct = 0.0;
   10569             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10570           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
   10571             :     }
   10572        4723 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
   10573        4723 :                                   pdfDataPct);
   10574             : }
   10575             : 
   10576             : /************************************************************************/
   10577             : /*                       IGetDataCoverageStatus()                       */
   10578             : /************************************************************************/
   10579             : 
   10580         690 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
   10581             :                                            int /*nXSize*/, int /*nYSize*/,
   10582             :                                            int /*nMaskFlagStop*/,
   10583             :                                            double *pdfDataPct)
   10584             : {
   10585         690 :     if (pdfDataPct != nullptr)
   10586           0 :         *pdfDataPct = 100.0;
   10587             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10588         690 :            GDAL_DATA_COVERAGE_STATUS_DATA;
   10589             : }
   10590             : 
   10591             : //! @cond Doxygen_Suppress
   10592             : /************************************************************************/
   10593             : /*                           EnterReadWrite()                           */
   10594             : /************************************************************************/
   10595             : 
   10596     7818120 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
   10597             : {
   10598     7818120 :     if (poDS != nullptr)
   10599     7050620 :         return poDS->EnterReadWrite(eRWFlag);
   10600      767502 :     return FALSE;
   10601             : }
   10602             : 
   10603             : /************************************************************************/
   10604             : /*                           LeaveReadWrite()                           */
   10605             : /************************************************************************/
   10606             : 
   10607     1135070 : void GDALRasterBand::LeaveReadWrite()
   10608             : {
   10609     1135070 :     if (poDS != nullptr)
   10610     1135070 :         poDS->LeaveReadWrite();
   10611     1135070 : }
   10612             : 
   10613             : /************************************************************************/
   10614             : /*                             InitRWLock()                             */
   10615             : /************************************************************************/
   10616             : 
   10617     3980450 : void GDALRasterBand::InitRWLock()
   10618             : {
   10619     3980450 :     if (poDS != nullptr)
   10620     3980050 :         poDS->InitRWLock();
   10621     3980450 : }
   10622             : 
   10623             : //! @endcond
   10624             : 
   10625             : // clang-format off
   10626             : 
   10627             : /**
   10628             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
   10629             :  * \brief Set metadata.
   10630             :  *
   10631             :  * CAUTION: depending on the format, older values of the updated information
   10632             :  * might still be found in the file in a "ghost" state, even if no longer
   10633             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10634             :  * format (this is not a exhaustive list)
   10635             :  *
   10636             :  * The C function GDALSetMetadata() does the same thing as this method.
   10637             :  *
   10638             :  * @param papszMetadata the metadata in name=value string list format to
   10639             :  * apply.
   10640             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
   10641             :  * domain.
   10642             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
   10643             :  * metadata has been accepted, but is likely not maintained persistently
   10644             :  * by the underlying object between sessions.
   10645             :  */
   10646             : 
   10647             : /**
   10648             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
   10649             :  * \brief Set single metadata item.
   10650             :  *
   10651             :  * CAUTION: depending on the format, older values of the updated information
   10652             :  * might still be found in the file in a "ghost" state, even if no longer
   10653             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10654             :  * format (this is not a exhaustive list)
   10655             :  *
   10656             :  * The C function GDALSetMetadataItem() does the same thing as this method.
   10657             :  *
   10658             :  * @param pszName the key for the metadata item to fetch.
   10659             :  * @param pszValue the value to assign to the key.
   10660             :  * @param pszDomain the domain to set within, use NULL for the default domain.
   10661             :  *
   10662             :  * @return CE_None on success, or an error code on failure.
   10663             :  */
   10664             : 
   10665             : // clang-format on
   10666             : 
   10667             : //! @cond Doxygen_Suppress
   10668             : /************************************************************************/
   10669             : /*                  EnablePixelTypeSignedByteWarning()                  */
   10670             : /************************************************************************/
   10671             : 
   10672      157381 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
   10673             : {
   10674      157381 :     m_bEnablePixelTypeSignedByteWarning = b;
   10675      157381 : }
   10676             : 
   10677        4920 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
   10678             : {
   10679        4920 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
   10680        4920 : }
   10681             : 
   10682             : //! @endcond
   10683             : 
   10684             : /************************************************************************/
   10685             : /*                          GetMetadataItem()                           */
   10686             : /************************************************************************/
   10687             : 
   10688      621986 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
   10689             :                                             const char *pszDomain)
   10690             : {
   10691             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
   10692      621986 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
   10693      462880 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
   10694      322247 :         EQUAL(pszName, "PIXELTYPE"))
   10695             :     {
   10696           2 :         CPLError(CE_Warning, CPLE_AppDefined,
   10697             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
   10698             :                  "used to signal signed 8-bit raster. Change your code to "
   10699             :                  "test for the new GDT_Int8 data type instead.");
   10700             :     }
   10701      621986 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
   10702             : }
   10703             : 
   10704             : /************************************************************************/
   10705             : /*                            WindowIterator                            */
   10706             : /************************************************************************/
   10707             : 
   10708             : //! @cond Doxygen_Suppress
   10709             : 
   10710         692 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
   10711             :                                                int nRasterYSize,
   10712             :                                                int nBlockXSize, int nBlockYSize,
   10713         692 :                                                int nRow, int nCol)
   10714             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
   10715             :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
   10716         692 :       m_col(nCol)
   10717             : {
   10718         692 : }
   10719             : 
   10720         751 : bool GDALRasterBand::WindowIterator::operator==(
   10721             :     const WindowIterator &other) const
   10722             : {
   10723         310 :     return m_row == other.m_row && m_col == other.m_col &&
   10724         310 :            m_nRasterXSize == other.m_nRasterXSize &&
   10725         310 :            m_nRasterYSize == other.m_nRasterYSize &&
   10726        1371 :            m_nBlockXSize == other.m_nBlockXSize &&
   10727        1061 :            m_nBlockYSize == other.m_nBlockYSize;
   10728             : }
   10729             : 
   10730         725 : bool GDALRasterBand::WindowIterator::operator!=(
   10731             :     const WindowIterator &other) const
   10732             : {
   10733         725 :     return !(*this == other);
   10734             : }
   10735             : 
   10736             : GDALRasterBand::WindowIterator::value_type
   10737         440 : GDALRasterBand::WindowIterator::operator*() const
   10738             : {
   10739             :     GDALRasterWindow ret;
   10740         440 :     ret.nXOff = m_col * m_nBlockXSize;
   10741         440 :     ret.nYOff = m_row * m_nBlockYSize;
   10742         440 :     ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
   10743         440 :     ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
   10744             : 
   10745         440 :     return ret;
   10746             : }
   10747             : 
   10748         431 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
   10749             : {
   10750         431 :     m_col++;
   10751         431 :     if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
   10752             :     {
   10753         335 :         m_col = 0;
   10754         335 :         m_row++;
   10755             :     }
   10756         431 :     return *this;
   10757             : }
   10758             : 
   10759         163 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
   10760         163 :     const GDALRasterBand &band, size_t maxSize)
   10761         163 :     : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
   10762         163 :                             band.nBlockYSize, maxSize)
   10763             : {
   10764         163 : }
   10765             : 
   10766         200 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
   10767         200 :     const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
   10768         200 :     : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
   10769         200 :                             std::min(band1.GetYSize(), band2.GetYSize()),
   10770         200 :                             std::lcm(band1.nBlockXSize, band2.nBlockXSize),
   10771         200 :                             std::lcm(band1.nBlockYSize, band2.nBlockYSize),
   10772         600 :                             maxSize)
   10773             : {
   10774         400 :     if (band1.GetXSize() != band2.GetXSize() ||
   10775         200 :         band1.GetYSize() != band2.GetYSize())
   10776             :     {
   10777           0 :         CPLError(CE_Warning, CPLE_AppDefined,
   10778             :                  "WindowIteratorWrapper called on bands of different "
   10779             :                  "dimensions. Selecting smallest one");
   10780             :     }
   10781         200 : }
   10782             : 
   10783         363 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
   10784             :                                                              int nRasterYSize,
   10785             :                                                              int nBlockXSize,
   10786             :                                                              int nBlockYSize,
   10787         363 :                                                              size_t maxSize)
   10788             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
   10789         363 :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
   10790             : {
   10791             : #ifdef CSA_BUILD
   10792             :     assert(this);
   10793             : #endif
   10794         363 :     int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
   10795         363 :     int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
   10796             : 
   10797         363 :     if (nXSize < 1 || nYSize < 1)
   10798             :     {
   10799             :         // If invalid block size is reported, assume scanlines
   10800           8 :         nXSize = m_nRasterXSize;
   10801           8 :         nYSize = 1;
   10802             :     }
   10803             : 
   10804         363 :     if (maxSize == 0)
   10805             :     {
   10806          69 :         m_nBlockXSize = nXSize;
   10807          69 :         m_nBlockYSize = nYSize;
   10808          69 :         return;
   10809             :     }
   10810             : 
   10811         294 :     const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
   10812         294 :     const double dfBlocksPerChunk =
   10813         294 :         static_cast<double>(maxSize) /
   10814         294 :         (static_cast<double>(nXSize) * static_cast<double>(nYSize));
   10815             : 
   10816         294 :     if (dfBlocksPerChunk < dfBlocksPerRow)
   10817             :     {
   10818          14 :         m_nBlockXSize = static_cast<int>(std::min<double>(
   10819          14 :             m_nRasterXSize,
   10820          14 :             nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
   10821          14 :         m_nBlockYSize = nYSize;
   10822             :     }
   10823             :     else
   10824             :     {
   10825         280 :         m_nBlockXSize = m_nRasterXSize;
   10826         280 :         m_nBlockYSize = static_cast<int>(std::min<double>(
   10827         280 :             m_nRasterYSize,
   10828         280 :             nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
   10829             :     }
   10830             :     if constexpr (sizeof(size_t) < sizeof(uint64_t))
   10831             :     {
   10832             :         if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
   10833             :         {
   10834             :             m_nBlockXSize = m_nRasterXSize;
   10835             :             m_nBlockYSize = 1;
   10836             :         }
   10837             :     }
   10838             : }
   10839             : 
   10840             : GDALRasterBand::WindowIterator
   10841         332 : GDALRasterBand::WindowIteratorWrapper::begin() const
   10842             : {
   10843         332 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10844         332 :                           m_nBlockYSize, 0, 0);
   10845             : }
   10846             : 
   10847             : GDALRasterBand::WindowIterator
   10848         332 : GDALRasterBand::WindowIteratorWrapper::end() const
   10849             : {
   10850         332 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10851         332 :                           m_nBlockYSize,
   10852         332 :                           DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
   10853             : }
   10854             : 
   10855          63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
   10856             : {
   10857          63 :     return static_cast<uint64_t>(
   10858          63 :                cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
   10859          63 :            static_cast<uint64_t>(
   10860          63 :                cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
   10861             : }
   10862             : 
   10863             : //! @endcond
   10864             : 
   10865             : /** Return an object whose begin() and end() methods can be used to iterate
   10866             :  *  over GDALRasterWindow objects that are aligned with blocks in this raster
   10867             :  *  band. The iteration order is from left to right, then from top to bottom.
   10868             :  *
   10869             : \code{.cpp}
   10870             :     std::vector<double> pixelValues;
   10871             :     for (const auto& window : poBand->IterateWindows()) {
   10872             :         CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
   10873             :                                          window.nXSize, window.nYSize);
   10874             :         // check eErr
   10875             :     }
   10876             : \endcode
   10877             :  *
   10878             :  *
   10879             :  *  @param maxSize The maximum number of pixels in each window. If set to
   10880             :  *         zero (the default), or a number smaller than the block size,
   10881             :  *         the window size will be the same as the block size.
   10882             :  *  @since GDAL 3.12
   10883             :  */
   10884             : GDALRasterBand::WindowIteratorWrapper
   10885         163 : GDALRasterBand::IterateWindows(size_t maxSize) const
   10886             : {
   10887         163 :     return WindowIteratorWrapper(*this, maxSize);
   10888             : }
   10889             : 
   10890             : /************************************************************************/
   10891             : /*                MayMultiBlockReadingBeMultiThreaded()                 */
   10892             : /************************************************************************/
   10893             : 
   10894             : /** Return whether a RasterIO(GF_Read) request spanning over multiple
   10895             :  * blocks may be accelerated internally using multi-threading.
   10896             :  *
   10897             :  * This can be used to determine the best chunk size to read a raster band.
   10898             :  *
   10899             :  * Note that such optimizations may require that the window is perfectly aligned
   10900             :  * on block boundaries and does not involve resampling or data type translation
   10901             :  * occurs, etc.
   10902             :  *
   10903             :  * @since GDAL 3.13
   10904             :  */
   10905           0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
   10906             : {
   10907           0 :     return false;
   10908             : }
   10909             : 
   10910             : /************************************************************************/
   10911             : /*                      GDALMDArrayFromRasterBand                       */
   10912             : /************************************************************************/
   10913             : 
   10914             : class GDALMDArrayFromRasterBand final : public GDALMDArray
   10915             : {
   10916             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
   10917             : 
   10918             :     GDALDataset *m_poDS;
   10919             :     GDALRasterBand *m_poBand;
   10920             :     GDALExtendedDataType m_dt;
   10921             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
   10922             :     std::string m_osUnit;
   10923             :     std::vector<GByte> m_pabyNoData{};
   10924             :     std::shared_ptr<GDALMDArray> m_varX{};
   10925             :     std::shared_ptr<GDALMDArray> m_varY{};
   10926             :     std::string m_osFilename{};
   10927             :     mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
   10928             : 
   10929             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
   10930             :                    const size_t *count, const GInt64 *arrayStep,
   10931             :                    const GPtrDiff_t *bufferStride,
   10932             :                    const GDALExtendedDataType &bufferDataType,
   10933             :                    void *pBuffer) const;
   10934             : 
   10935             :   protected:
   10936          36 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
   10937          72 :         : GDALAbstractMDArray(std::string(),
   10938          72 :                               std::string(poDS->GetDescription()) +
   10939             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
   10940          72 :           GDALMDArray(std::string(),
   10941          72 :                       std::string(poDS->GetDescription()) +
   10942             :                           CPLSPrintf(" band %d", poBand->GetBand())),
   10943             :           m_poDS(poDS), m_poBand(poBand),
   10944             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
   10945         180 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
   10946             :     {
   10947          36 :         m_poDS->Reference();
   10948             : 
   10949          36 :         int bHasNoData = false;
   10950          36 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
   10951             :         {
   10952           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
   10953           0 :             if (bHasNoData)
   10954             :             {
   10955           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   10956           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
   10957             :                                 m_dt.GetNumericDataType(), 0, 1);
   10958             :             }
   10959             :         }
   10960          36 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
   10961             :         {
   10962           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
   10963           0 :             if (bHasNoData)
   10964             :             {
   10965           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   10966           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
   10967             :                                 m_dt.GetNumericDataType(), 0, 1);
   10968             :             }
   10969             :         }
   10970             :         else
   10971             :         {
   10972          36 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
   10973          36 :             if (bHasNoData)
   10974             :             {
   10975           1 :                 m_pabyNoData.resize(m_dt.GetSize());
   10976           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
   10977             :                                 m_dt.GetNumericDataType(), 0, 1);
   10978             :             }
   10979             :         }
   10980             : 
   10981          36 :         const int nXSize = poBand->GetXSize();
   10982          36 :         const int nYSize = poBand->GetYSize();
   10983             : 
   10984          36 :         auto poSRS = m_poDS->GetSpatialRef();
   10985          72 :         std::string osTypeY;
   10986          72 :         std::string osTypeX;
   10987          72 :         std::string osDirectionY;
   10988          72 :         std::string osDirectionX;
   10989          36 :         if (poSRS && poSRS->GetAxesCount() == 2)
   10990             :         {
   10991          24 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
   10992          24 :             OGRAxisOrientation eOrientation1 = OAO_Other;
   10993          24 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
   10994          24 :             OGRAxisOrientation eOrientation2 = OAO_Other;
   10995          24 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
   10996          24 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
   10997             :             {
   10998           8 :                 if (mapping == std::vector<int>{1, 2})
   10999             :                 {
   11000           8 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11001           8 :                     osDirectionY = "NORTH";
   11002           8 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11003           8 :                     osDirectionX = "EAST";
   11004             :                 }
   11005             :             }
   11006          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
   11007             :             {
   11008          16 :                 if (mapping == std::vector<int>{2, 1})
   11009             :                 {
   11010          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11011          16 :                     osDirectionY = "NORTH";
   11012          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11013          16 :                     osDirectionX = "EAST";
   11014             :                 }
   11015             :             }
   11016             :         }
   11017             : 
   11018         180 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
   11019             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
   11020          72 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
   11021         108 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
   11022             : 
   11023          36 :         GDALGeoTransform gt;
   11024          36 :         if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
   11025             :         {
   11026          50 :             m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
   11027          50 :                                                         gt[0], gt[1], 0.5);
   11028          25 :             m_dims[1]->SetIndexingVariable(m_varX);
   11029             : 
   11030          50 :             m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
   11031          50 :                                                         gt[3], gt[5], 0.5);
   11032          25 :             m_dims[0]->SetIndexingVariable(m_varY);
   11033             :         }
   11034          36 :     }
   11035             : 
   11036             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
   11037             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11038             :                const GDALExtendedDataType &bufferDataType,
   11039             :                void *pDstBuffer) const override;
   11040             : 
   11041           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
   11042             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11043             :                 const GDALExtendedDataType &bufferDataType,
   11044             :                 const void *pSrcBuffer) override
   11045             :     {
   11046           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
   11047             :                          bufferStride, bufferDataType,
   11048           1 :                          const_cast<void *>(pSrcBuffer));
   11049             :     }
   11050             : 
   11051             :   public:
   11052          72 :     ~GDALMDArrayFromRasterBand() override
   11053          36 :     {
   11054          36 :         m_poDS->ReleaseRef();
   11055          72 :     }
   11056             : 
   11057          36 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
   11058             :                                                GDALRasterBand *poBand)
   11059             :     {
   11060             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
   11061          72 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
   11062          36 :         array->SetSelf(array);
   11063          72 :         return array;
   11064             :     }
   11065             : 
   11066           5 :     bool IsWritable() const override
   11067             :     {
   11068           5 :         return m_poDS->GetAccess() == GA_Update;
   11069             :     }
   11070             : 
   11071         122 :     const std::string &GetFilename() const override
   11072             :     {
   11073         122 :         return m_osFilename;
   11074             :     }
   11075             : 
   11076             :     const std::vector<std::shared_ptr<GDALDimension>> &
   11077         345 :     GetDimensions() const override
   11078             :     {
   11079         345 :         return m_dims;
   11080             :     }
   11081             : 
   11082         158 :     const GDALExtendedDataType &GetDataType() const override
   11083             :     {
   11084         158 :         return m_dt;
   11085             :     }
   11086             : 
   11087           5 :     const std::string &GetUnit() const override
   11088             :     {
   11089           5 :         return m_osUnit;
   11090             :     }
   11091             : 
   11092          32 :     const void *GetRawNoDataValue() const override
   11093             :     {
   11094          32 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
   11095             :     }
   11096             : 
   11097           4 :     double GetOffset(bool *pbHasOffset,
   11098             :                      GDALDataType *peStorageType) const override
   11099             :     {
   11100           4 :         int bHasOffset = false;
   11101           4 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
   11102           4 :         if (pbHasOffset)
   11103           4 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
   11104           4 :         if (peStorageType)
   11105           1 :             *peStorageType = GDT_Unknown;
   11106           4 :         return dfRes;
   11107             :     }
   11108             : 
   11109           4 :     double GetScale(bool *pbHasScale,
   11110             :                     GDALDataType *peStorageType) const override
   11111             :     {
   11112           4 :         int bHasScale = false;
   11113           4 :         double dfRes = m_poBand->GetScale(&bHasScale);
   11114           4 :         if (pbHasScale)
   11115           4 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
   11116           4 :         if (peStorageType)
   11117           1 :             *peStorageType = GDT_Unknown;
   11118           4 :         return dfRes;
   11119             :     }
   11120             : 
   11121          88 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
   11122             :     {
   11123          88 :         auto poSrcSRS = m_poDS->GetSpatialRef();
   11124          88 :         if (!poSrcSRS)
   11125           2 :             return nullptr;
   11126         172 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
   11127             : 
   11128         172 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
   11129          86 :         constexpr int iYDim = 0;
   11130          86 :         constexpr int iXDim = 1;
   11131         258 :         for (auto &m : axisMapping)
   11132             :         {
   11133         172 :             if (m == 1)
   11134          86 :                 m = iXDim + 1;
   11135          86 :             else if (m == 2)
   11136          86 :                 m = iYDim + 1;
   11137             :             else
   11138           0 :                 m = 0;
   11139             :         }
   11140          86 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
   11141          86 :         return poSRS;
   11142             :     }
   11143             : 
   11144          32 :     std::vector<GUInt64> GetBlockSize() const override
   11145             :     {
   11146          32 :         int nBlockXSize = 0;
   11147          32 :         int nBlockYSize = 0;
   11148          32 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
   11149          32 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
   11150          32 :                                     static_cast<GUInt64>(nBlockXSize)};
   11151             :     }
   11152             : 
   11153             :     std::vector<std::shared_ptr<GDALAttribute>>
   11154          23 :     GetAttributes(CSLConstList) const override
   11155             :     {
   11156          23 :         std::vector<std::shared_ptr<GDALAttribute>> res;
   11157          23 :         auto papszMD = m_poBand->GetMetadata();
   11158          25 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
   11159             :         {
   11160           2 :             char *pszKey = nullptr;
   11161           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
   11162           2 :             if (pszKey && pszValue)
   11163             :             {
   11164             :                 res.emplace_back(
   11165           2 :                     std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
   11166             :             }
   11167           2 :             CPLFree(pszKey);
   11168             :         }
   11169          23 :         return res;
   11170             :     }
   11171             : 
   11172           6 :     int GetOverviewCount() const override
   11173             :     {
   11174           6 :         return m_poBand->GetOverviewCount();
   11175             :     }
   11176             : 
   11177           4 :     std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
   11178             :     {
   11179           4 :         const int nOverviews = GetOverviewCount();
   11180           4 :         if (idx < 0 || idx >= nOverviews)
   11181           2 :             return nullptr;
   11182           2 :         m_apoOverviews.resize(nOverviews);
   11183           2 :         if (!m_apoOverviews[idx])
   11184             :         {
   11185           1 :             if (auto poOvrBand = m_poBand->GetOverview(idx))
   11186             :             {
   11187           1 :                 if (auto poOvrDS = poOvrBand->GetDataset())
   11188             :                 {
   11189           1 :                     m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
   11190             :                 }
   11191             :             }
   11192             :         }
   11193           2 :         return m_apoOverviews[idx];
   11194             :     }
   11195             : };
   11196             : 
   11197          39 : bool GDALMDArrayFromRasterBand::IRead(
   11198             :     const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
   11199             :     const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
   11200             :     void *pDstBuffer) const
   11201             : {
   11202          39 :     return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
   11203          39 :                      bufferDataType, pDstBuffer);
   11204             : }
   11205             : 
   11206             : /************************************************************************/
   11207             : /*                             ReadWrite()                              */
   11208             : /************************************************************************/
   11209             : 
   11210          40 : bool GDALMDArrayFromRasterBand::ReadWrite(
   11211             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
   11212             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11213             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
   11214             : {
   11215          40 :     constexpr size_t iDimX = 1;
   11216          40 :     constexpr size_t iDimY = 0;
   11217          40 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
   11218             :                                   arrayStartIdx, count, arrayStep, bufferStride,
   11219          40 :                                   bufferDataType, pBuffer);
   11220             : }
   11221             : 
   11222             : /************************************************************************/
   11223             : /*                       GDALMDRasterIOFromBand()                       */
   11224             : /************************************************************************/
   11225             : 
   11226          73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
   11227             :                             size_t iDimX, size_t iDimY,
   11228             :                             const GUInt64 *arrayStartIdx, const size_t *count,
   11229             :                             const GInt64 *arrayStep,
   11230             :                             const GPtrDiff_t *bufferStride,
   11231             :                             const GDALExtendedDataType &bufferDataType,
   11232             :                             void *pBuffer)
   11233             : {
   11234          73 :     const auto eDT(bufferDataType.GetNumericDataType());
   11235          73 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
   11236          73 :     const int nX =
   11237          73 :         arrayStep[iDimX] > 0
   11238          73 :             ? static_cast<int>(arrayStartIdx[iDimX])
   11239           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
   11240           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
   11241          73 :     const int nY =
   11242          73 :         arrayStep[iDimY] > 0
   11243          73 :             ? static_cast<int>(arrayStartIdx[iDimY])
   11244           6 :             : static_cast<int>(arrayStartIdx[iDimY] -
   11245           6 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
   11246          73 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
   11247          73 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
   11248          73 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
   11249          73 :     int nStrideXSign = 1;
   11250          73 :     if (arrayStep[iDimX] < 0)
   11251             :     {
   11252           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
   11253           2 :         nStrideXSign = -1;
   11254             :     }
   11255          73 :     int nStrideYSign = 1;
   11256          73 :     if (arrayStep[iDimY] < 0)
   11257             :     {
   11258           6 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
   11259           6 :         nStrideYSign = -1;
   11260             :     }
   11261             : 
   11262         146 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
   11263          73 :                             static_cast<int>(count[iDimX]),
   11264          73 :                             static_cast<int>(count[iDimY]), eDT,
   11265             :                             static_cast<GSpacing>(
   11266          73 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
   11267             :                             static_cast<GSpacing>(
   11268          73 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
   11269          73 :                             nullptr) == CE_None;
   11270             : }
   11271             : 
   11272             : /************************************************************************/
   11273             : /*                             AsMDArray()                              */
   11274             : /************************************************************************/
   11275             : 
   11276             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
   11277             :  *
   11278             :  * The band must be linked to a GDALDataset. If this dataset is not already
   11279             :  * marked as shared, it will be, so that the returned array holds a reference
   11280             :  * to it.
   11281             :  *
   11282             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   11283             :  * returned array will have an associated indexing variable.
   11284             :  *
   11285             :  * This is the same as the C function GDALRasterBandAsMDArray().
   11286             :  *
   11287             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
   11288             :  *
   11289             :  * @return a new array, or nullptr.
   11290             :  *
   11291             :  * @since GDAL 3.1
   11292             :  */
   11293          35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
   11294             : {
   11295          35 :     if (!poDS)
   11296             :     {
   11297           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
   11298           0 :         return nullptr;
   11299             :     }
   11300          35 :     if (!poDS->GetShared())
   11301             :     {
   11302          33 :         poDS->MarkAsShared();
   11303             :     }
   11304             :     return GDALMDArrayFromRasterBand::Create(
   11305          35 :         poDS, const_cast<GDALRasterBand *>(this));
   11306             : }
   11307             : 
   11308             : /************************************************************************/
   11309             : /*                         InterpolateAtPoint()                         */
   11310             : /************************************************************************/
   11311             : 
   11312             : /**
   11313             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11314             :  * taking pixel/line coordinates as input.
   11315             :  *
   11316             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
   11317             :  * @param dfLine line coordinate as a double, where interpolation should be done.
   11318             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   11319             :  * @param pdfRealValue pointer to real part of interpolated value
   11320             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   11321             :  *
   11322             :  * @return CE_None on success, or an error code on failure.
   11323             :  * @since GDAL 3.10
   11324             :  */
   11325             : 
   11326         168 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
   11327             :                                           GDALRIOResampleAlg eInterpolation,
   11328             :                                           double *pdfRealValue,
   11329             :                                           double *pdfImagValue) const
   11330             : {
   11331         168 :     if (eInterpolation != GRIORA_NearestNeighbour &&
   11332          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
   11333             :         eInterpolation != GRIORA_CubicSpline)
   11334             :     {
   11335           2 :         CPLError(CE_Failure, CPLE_AppDefined,
   11336             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
   11337             :                  "methods "
   11338             :                  "allowed");
   11339             : 
   11340           2 :         return CE_Failure;
   11341             :     }
   11342             : 
   11343         166 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
   11344         166 :     if (!m_poPointsCache)
   11345          86 :         m_poPointsCache = new GDALDoublePointsCache();
   11346             : 
   11347             :     const bool res =
   11348         166 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
   11349             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
   11350             : 
   11351         166 :     return res ? CE_None : CE_Failure;
   11352             : }
   11353             : 
   11354             : /************************************************************************/
   11355             : /*                    GDALRasterInterpolateAtPoint()                    */
   11356             : /************************************************************************/
   11357             : 
   11358             : /**
   11359             :  * \brief Interpolates the value between pixels using
   11360             :  * a resampling algorithm
   11361             :  *
   11362             :  * @see GDALRasterBand::InterpolateAtPoint()
   11363             :  * @since GDAL 3.10
   11364             :  */
   11365             : 
   11366         145 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
   11367             :                                     double dfLine,
   11368             :                                     GDALRIOResampleAlg eInterpolation,
   11369             :                                     double *pdfRealValue, double *pdfImagValue)
   11370             : {
   11371         145 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
   11372             : 
   11373         145 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   11374         145 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
   11375         145 :                                       pdfRealValue, pdfImagValue);
   11376             : }
   11377             : 
   11378             : /************************************************************************/
   11379             : /*                      InterpolateAtGeolocation()                      */
   11380             : /************************************************************************/
   11381             : 
   11382             : /**
   11383             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11384             :  * taking georeferenced coordinates as input.
   11385             :  *
   11386             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   11387             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   11388             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   11389             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   11390             :  * array (generally WGS 84) if there is a geolocation array.
   11391             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   11392             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   11393             :  * be a easting, and dfGeolocY a northing.
   11394             :  *
   11395             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   11396             :  * expressed in that CRS, and that tuple must be conformant with the
   11397             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   11398             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   11399             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   11400             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   11401             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   11402             :  *
   11403             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
   11404             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
   11405             :  * it for details on how that transformation is done.
   11406             :  *
   11407             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   11408             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11409             :  * where interpolation should be done.
   11410             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   11411             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11412             :  * where interpolation should be done.
   11413             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   11414             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   11415             :  * @param pdfRealValue pointer to real part of interpolated value
   11416             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   11417             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
   11418             :  *
   11419             :  * @return CE_None on success, or an error code on failure.
   11420             :  * @since GDAL 3.11
   11421             :  */
   11422             : 
   11423          15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
   11424             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
   11425             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
   11426             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
   11427             : {
   11428             :     double dfPixel;
   11429             :     double dfLine;
   11430          15 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
   11431             :                                      &dfLine,
   11432          15 :                                      papszTransformerOptions) != CE_None)
   11433             :     {
   11434           1 :         return CE_Failure;
   11435             :     }
   11436          14 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
   11437          14 :                               pdfImagValue);
   11438             : }
   11439             : 
   11440             : /************************************************************************/
   11441             : /*                 GDALRasterInterpolateAtGeolocation()                 */
   11442             : /************************************************************************/
   11443             : 
   11444             : /**
   11445             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11446             :  * taking georeferenced coordinates as input.
   11447             :  *
   11448             :  * @see GDALRasterBand::InterpolateAtGeolocation()
   11449             :  * @since GDAL 3.11
   11450             :  */
   11451             : 
   11452          15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
   11453             :                                           double dfGeolocX, double dfGeolocY,
   11454             :                                           OGRSpatialReferenceH hSRS,
   11455             :                                           GDALRIOResampleAlg eInterpolation,
   11456             :                                           double *pdfRealValue,
   11457             :                                           double *pdfImagValue,
   11458             :                                           CSLConstList papszTransformerOptions)
   11459             : {
   11460          15 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
   11461             : 
   11462          15 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   11463          15 :     return poBand->InterpolateAtGeolocation(
   11464          15 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
   11465          15 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
   11466             : }
   11467             : 
   11468             : /************************************************************************/
   11469             : /*                   GDALRasterBand::SplitRasterIO()                    */
   11470             : /************************************************************************/
   11471             : 
   11472             : //! @cond Doxygen_Suppress
   11473             : 
   11474             : /** Implements IRasterIO() by dividing the request in 2.
   11475             :  *
   11476             :  * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
   11477             :  *
   11478             :  * Return CE_Warning if the split could not be done, CE_None in case of
   11479             :  * success and CE_Failure in case of error.
   11480             :  *
   11481             :  * @since 3.12
   11482             :  */
   11483         999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
   11484             :                                      [[maybe_unused]] int nXSize,
   11485             :                                      [[maybe_unused]] int nYSize, void *pData,
   11486             :                                      int nBufXSize, int nBufYSize,
   11487             :                                      GDALDataType eBufType,
   11488             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
   11489             :                                      GDALRasterIOExtraArg *psExtraArg)
   11490             : {
   11491         999 :     CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
   11492             : 
   11493         999 :     GByte *pabyData = static_cast<GByte *>(pData);
   11494         999 :     if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
   11495             :     {
   11496             :         GDALRasterIOExtraArg sArg;
   11497         499 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11498         499 :         const int nHalfHeight = nBufYSize / 2;
   11499             : 
   11500         499 :         sArg.pfnProgress = GDALScaledProgress;
   11501         499 :         sArg.pProgressData = GDALCreateScaledProgress(
   11502             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11503         499 :         if (sArg.pProgressData == nullptr)
   11504         499 :             sArg.pfnProgress = nullptr;
   11505         998 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
   11506             :                                 pabyData, nBufXSize, nHalfHeight, eBufType,
   11507         499 :                                 nPixelSpace, nLineSpace, &sArg);
   11508         499 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11509             : 
   11510         499 :         if (eErr == CE_None)
   11511             :         {
   11512         499 :             sArg.pfnProgress = GDALScaledProgress;
   11513         499 :             sArg.pProgressData = GDALCreateScaledProgress(
   11514             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11515         499 :             if (sArg.pProgressData == nullptr)
   11516         499 :                 sArg.pfnProgress = nullptr;
   11517         998 :             eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
   11518             :                              nBufYSize - nHalfHeight,
   11519         499 :                              pabyData + nHalfHeight * nLineSpace, nBufXSize,
   11520             :                              nBufYSize - nHalfHeight, eBufType, nPixelSpace,
   11521         499 :                              nLineSpace, &sArg);
   11522         499 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11523             :         }
   11524         499 :         return eErr;
   11525             :     }
   11526         500 :     else if (nBufXSize >= 2)
   11527             :     {
   11528             :         GDALRasterIOExtraArg sArg;
   11529         500 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11530         500 :         const int nHalfWidth = nBufXSize / 2;
   11531             : 
   11532         500 :         sArg.pfnProgress = GDALScaledProgress;
   11533         500 :         sArg.pProgressData = GDALCreateScaledProgress(
   11534             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11535         500 :         if (sArg.pProgressData == nullptr)
   11536         500 :             sArg.pfnProgress = nullptr;
   11537        1000 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
   11538             :                                 pabyData, nHalfWidth, nBufYSize, eBufType,
   11539         500 :                                 nPixelSpace, nLineSpace, &sArg);
   11540         500 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11541             : 
   11542         500 :         if (eErr == CE_None)
   11543             :         {
   11544         500 :             sArg.pfnProgress = GDALScaledProgress;
   11545         500 :             sArg.pProgressData = GDALCreateScaledProgress(
   11546             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11547         500 :             if (sArg.pProgressData == nullptr)
   11548         500 :                 sArg.pfnProgress = nullptr;
   11549        1000 :             eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
   11550             :                              nBufXSize - nHalfWidth, nBufYSize,
   11551         500 :                              pabyData + nHalfWidth * nPixelSpace,
   11552             :                              nBufXSize - nHalfWidth, nBufYSize, eBufType,
   11553         500 :                              nPixelSpace, nLineSpace, &sArg);
   11554         500 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11555             :         }
   11556         500 :         return eErr;
   11557             :     }
   11558             : 
   11559           0 :     return CE_Warning;
   11560             : }
   11561             : 
   11562             : //! @endcond
   11563             : 
   11564             : /************************************************************************/
   11565             : /*                      ThrowIfNotSameDimensions()                      */
   11566             : /************************************************************************/
   11567             : 
   11568             : //! @cond Doxygen_Suppress
   11569             : /* static */
   11570         169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
   11571             :                                               const GDALRasterBand &second)
   11572             : {
   11573         320 :     if (first.GetXSize() != second.GetXSize() ||
   11574         151 :         first.GetYSize() != second.GetYSize())
   11575             :     {
   11576          36 :         throw std::runtime_error("Bands do not have the same dimensions");
   11577             :     }
   11578         133 : }
   11579             : 
   11580             : //! @endcond
   11581             : 
   11582             : /************************************************************************/
   11583             : /*                       GDALRasterBandUnaryOp()                        */
   11584             : /************************************************************************/
   11585             : 
   11586             : /** Apply a unary operation on this band.
   11587             :  *
   11588             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11589             :  * dataset.
   11590             :  *
   11591             :  * @since 3.12
   11592             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11593             :  */
   11594             : GDALComputedRasterBandH
   11595           6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
   11596             :                       GDALRasterAlgebraUnaryOperation eOp)
   11597             : {
   11598           6 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11599           6 :     GDALComputedRasterBand::Operation cppOp{};
   11600           6 :     switch (eOp)
   11601             :     {
   11602           2 :         case GRAUO_LOGICAL_NOT:
   11603             :             return new GDALComputedRasterBand(
   11604             :                 GDALComputedRasterBand::Operation::OP_NE,
   11605           2 :                 *(GDALRasterBand::FromHandle(hBand)), true);
   11606           1 :         case GRAUO_ABS:
   11607           1 :             cppOp = GDALComputedRasterBand::Operation::OP_ABS;
   11608           1 :             break;
   11609           1 :         case GRAUO_SQRT:
   11610           1 :             cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
   11611           1 :             break;
   11612           1 :         case GRAUO_LOG:
   11613             : #ifndef HAVE_MUPARSER
   11614             :             CPLError(
   11615             :                 CE_Failure, CPLE_NotSupported,
   11616             :                 "log(band) not available on a GDAL build without muparser");
   11617             :             return nullptr;
   11618             : #else
   11619           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG;
   11620           1 :             break;
   11621             : #endif
   11622           1 :         case GRAUO_LOG10:
   11623           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
   11624           1 :             break;
   11625             :     }
   11626             :     return new GDALComputedRasterBand(cppOp,
   11627           4 :                                       *(GDALRasterBand::FromHandle(hBand)));
   11628             : }
   11629             : 
   11630             : /************************************************************************/
   11631             : /*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
   11632             : /************************************************************************/
   11633             : 
   11634             : static GDALComputedRasterBand::Operation
   11635         120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
   11636             :     GDALRasterAlgebraBinaryOperation eOp)
   11637             : {
   11638         120 :     switch (eOp)
   11639             :     {
   11640          26 :         case GRABO_ADD:
   11641          26 :             return GDALComputedRasterBand::Operation::OP_ADD;
   11642           2 :         case GRABO_SUB:
   11643           2 :             return GDALComputedRasterBand::Operation::OP_SUBTRACT;
   11644          24 :         case GRABO_MUL:
   11645          24 :             return GDALComputedRasterBand::Operation::OP_MULTIPLY;
   11646           3 :         case GRABO_DIV:
   11647           3 :             return GDALComputedRasterBand::Operation::OP_DIVIDE;
   11648           6 :         case GRABO_GT:
   11649           6 :             return GDALComputedRasterBand::Operation::OP_GT;
   11650           8 :         case GRABO_GE:
   11651           8 :             return GDALComputedRasterBand::Operation::OP_GE;
   11652           6 :         case GRABO_LT:
   11653           6 :             return GDALComputedRasterBand::Operation::OP_LT;
   11654           6 :         case GRABO_LE:
   11655           6 :             return GDALComputedRasterBand::Operation::OP_LE;
   11656           6 :         case GRABO_EQ:
   11657           6 :             return GDALComputedRasterBand::Operation::OP_EQ;
   11658           6 :         case GRABO_NE:
   11659           6 :             break;
   11660          12 :         case GRABO_LOGICAL_AND:
   11661          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
   11662          12 :         case GRABO_LOGICAL_OR:
   11663          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
   11664           3 :         case GRABO_POW:
   11665           3 :             return GDALComputedRasterBand::Operation::OP_POW;
   11666             :     }
   11667           6 :     return GDALComputedRasterBand::Operation::OP_NE;
   11668             : }
   11669             : 
   11670             : /************************************************************************/
   11671             : /*                     GDALRasterBandBinaryOpBand()                     */
   11672             : /************************************************************************/
   11673             : 
   11674             : /** Apply a binary operation on this band with another one.
   11675             :  *
   11676             :  * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
   11677             :  * "hBand1 - hBand2".
   11678             :  *
   11679             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11680             :  * datasets.
   11681             :  *
   11682             :  * @since 3.12
   11683             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11684             :  */
   11685             : GDALComputedRasterBandH
   11686          57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
   11687             :                            GDALRasterAlgebraBinaryOperation eOp,
   11688             :                            GDALRasterBandH hOtherBand)
   11689             : {
   11690          57 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11691          57 :     VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
   11692             : #ifndef HAVE_MUPARSER
   11693             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11694             :     {
   11695             :         CPLError(
   11696             :             CE_Failure, CPLE_NotSupported,
   11697             :             "Band comparison operators not available on a GDAL build without "
   11698             :             "muparser");
   11699             :         return nullptr;
   11700             :     }
   11701             :     else if (eOp == GRABO_POW)
   11702             :     {
   11703             :         CPLError(
   11704             :             CE_Failure, CPLE_NotSupported,
   11705             :             "pow(band, band) not available on a GDAL build without muparser");
   11706             :         return nullptr;
   11707             :     }
   11708             : #endif
   11709          57 :     auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
   11710          57 :     auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
   11711             :     try
   11712             :     {
   11713          57 :         GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
   11714             :     }
   11715          13 :     catch (const std::exception &e)
   11716             :     {
   11717          13 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   11718          13 :         return nullptr;
   11719             :     }
   11720             :     return new GDALComputedRasterBand(
   11721          44 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
   11722          44 :         secondBand);
   11723             : }
   11724             : 
   11725             : /************************************************************************/
   11726             : /*                    GDALRasterBandBinaryOpDouble()                    */
   11727             : /************************************************************************/
   11728             : 
   11729             : /** Apply a binary operation on this band with a constant
   11730             :  *
   11731             :  * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
   11732             :  * "hBand - constant".
   11733             :  *
   11734             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11735             :  * dataset.
   11736             :  *
   11737             :  * @since 3.12
   11738             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11739             :  */
   11740             : GDALComputedRasterBandH
   11741          59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
   11742             :                              GDALRasterAlgebraBinaryOperation eOp,
   11743             :                              double constant)
   11744             : {
   11745          59 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11746             : #ifndef HAVE_MUPARSER
   11747             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11748             :     {
   11749             :         CPLError(
   11750             :             CE_Failure, CPLE_NotSupported,
   11751             :             "Band comparison operators not available on a GDAL build without "
   11752             :             "muparser");
   11753             :         return nullptr;
   11754             :     }
   11755             : #endif
   11756             :     return new GDALComputedRasterBand(
   11757          59 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11758          59 :         *(GDALRasterBand::FromHandle(hBand)), constant);
   11759             : }
   11760             : 
   11761             : /************************************************************************/
   11762             : /*                 GDALRasterBandBinaryOpDoubleToBand()                 */
   11763             : /************************************************************************/
   11764             : 
   11765             : /** Apply a binary operation on the constant with this band
   11766             :  *
   11767             :  * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
   11768             :  * "constant - hBand".
   11769             :  *
   11770             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11771             :  * dataset.
   11772             :  *
   11773             :  * @since 3.12
   11774             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11775             :  */
   11776             : GDALComputedRasterBandH
   11777          18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
   11778             :                                    GDALRasterAlgebraBinaryOperation eOp,
   11779             :                                    GDALRasterBandH hBand)
   11780             : {
   11781          18 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11782             : #ifndef HAVE_MUPARSER
   11783             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11784             :     {
   11785             :         CPLError(
   11786             :             CE_Failure, CPLE_NotSupported,
   11787             :             "Band comparison operators not available on a GDAL build without "
   11788             :             "muparser");
   11789             :         return nullptr;
   11790             :     }
   11791             : #endif
   11792          18 :     switch (eOp)
   11793             :     {
   11794          15 :         case GRABO_ADD:
   11795             :         case GRABO_MUL:
   11796             :         {
   11797             :             return new GDALComputedRasterBand(
   11798          15 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11799          15 :                 *(GDALRasterBand::FromHandle(hBand)), constant);
   11800             :         }
   11801             : 
   11802           2 :         case GRABO_DIV:
   11803             :         case GRABO_GT:
   11804             :         case GRABO_GE:
   11805             :         case GRABO_LT:
   11806             :         case GRABO_LE:
   11807             :         case GRABO_EQ:
   11808             :         case GRABO_NE:
   11809             :         case GRABO_LOGICAL_AND:
   11810             :         case GRABO_LOGICAL_OR:
   11811             :         case GRABO_POW:
   11812             :         {
   11813             :             return new GDALComputedRasterBand(
   11814           2 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
   11815           2 :                 *(GDALRasterBand::FromHandle(hBand)));
   11816             :         }
   11817             : 
   11818           1 :         case GRABO_SUB:
   11819             :         {
   11820           1 :             break;
   11821             :         }
   11822             :     }
   11823             : 
   11824             :     return new GDALComputedRasterBand(
   11825             :         GDALComputedRasterBand::Operation::OP_ADD,
   11826           2 :         GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
   11827           1 :                                *(GDALRasterBand::FromHandle(hBand)), -1.0),
   11828           1 :         constant);
   11829             : }
   11830             : 
   11831             : /************************************************************************/
   11832             : /*                             operator+()                              */
   11833             : /************************************************************************/
   11834             : 
   11835             : /** Add this band with another one.
   11836             :  *
   11837             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11838             :  * datasets.
   11839             :  *
   11840             :  * @since 3.12
   11841             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11842             :  */
   11843             : GDALComputedRasterBand
   11844           8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
   11845             : {
   11846           8 :     ThrowIfNotSameDimensions(*this, other);
   11847             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11848           7 :                                   *this, other);
   11849             : }
   11850             : 
   11851             : /************************************************************************/
   11852             : /*                             operator+()                              */
   11853             : /************************************************************************/
   11854             : 
   11855             : /** Add this band with a constant.
   11856             :  *
   11857             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11858             :  * dataset.
   11859             :  *
   11860             :  * @since 3.12
   11861             :  */
   11862          13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
   11863             : {
   11864             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11865          13 :                                   *this, constant);
   11866             : }
   11867             : 
   11868             : /************************************************************************/
   11869             : /*                             operator+()                              */
   11870             : /************************************************************************/
   11871             : 
   11872             : /** Add a band with a constant.
   11873             :  *
   11874             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11875             :  * dataset.
   11876             :  *
   11877             :  * @since 3.12
   11878             :  */
   11879           1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
   11880             : {
   11881           1 :     return other + constant;
   11882             : }
   11883             : 
   11884             : /************************************************************************/
   11885             : /*                             operator-()                              */
   11886             : /************************************************************************/
   11887             : 
   11888             : /** Return a band whose value is the opposite value of the band for each
   11889             :  * pixel.
   11890             :  *
   11891             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11892             :  * dataset.
   11893             :  *
   11894             :  * @since 3.12
   11895             :  */
   11896           2 : GDALComputedRasterBand GDALRasterBand::operator-() const
   11897             : {
   11898           2 :     return 0 - *this;
   11899             : }
   11900             : 
   11901             : /************************************************************************/
   11902             : /*                             operator-()                              */
   11903             : /************************************************************************/
   11904             : 
   11905             : /** Subtract this band with another one.
   11906             :  *
   11907             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11908             :  * datasets.
   11909             :  *
   11910             :  * @since 3.12
   11911             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11912             :  */
   11913             : GDALComputedRasterBand
   11914           2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
   11915             : {
   11916           2 :     ThrowIfNotSameDimensions(*this, other);
   11917             :     return GDALComputedRasterBand(
   11918           2 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
   11919             : }
   11920             : 
   11921             : /************************************************************************/
   11922             : /*                             operator-()                              */
   11923             : /************************************************************************/
   11924             : 
   11925             : /** Subtract this band with a constant.
   11926             :  *
   11927             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11928             :  * dataset.
   11929             :  *
   11930             :  * @since 3.12
   11931             :  */
   11932           1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
   11933             : {
   11934             :     return GDALComputedRasterBand(
   11935           1 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
   11936             : }
   11937             : 
   11938             : /************************************************************************/
   11939             : /*                             operator-()                              */
   11940             : /************************************************************************/
   11941             : 
   11942             : /** Subtract a constant with a band.
   11943             :  *
   11944             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11945             :  * dataset.
   11946             :  *
   11947             :  * @since 3.12
   11948             :  */
   11949           3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
   11950             : {
   11951           6 :     return other * (-1.0) + constant;
   11952             : }
   11953             : 
   11954             : /************************************************************************/
   11955             : /*                             operator*()                              */
   11956             : /************************************************************************/
   11957             : 
   11958             : /** Multiply this band with another one.
   11959             :  *
   11960             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11961             :  * datasets.
   11962             :  *
   11963             :  * @since 3.12
   11964             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11965             :  */
   11966             : GDALComputedRasterBand
   11967           2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
   11968             : {
   11969           2 :     ThrowIfNotSameDimensions(*this, other);
   11970             :     return GDALComputedRasterBand(
   11971           2 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
   11972             : }
   11973             : 
   11974             : /************************************************************************/
   11975             : /*                             operator*()                              */
   11976             : /************************************************************************/
   11977             : 
   11978             : /** Multiply this band by a constant.
   11979             :  *
   11980             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11981             :  * dataset.
   11982             :  *
   11983             :  * @since 3.12
   11984             :  */
   11985          14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
   11986             : {
   11987             :     return GDALComputedRasterBand(
   11988          14 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
   11989             : }
   11990             : 
   11991             : /************************************************************************/
   11992             : /*                             operator*()                              */
   11993             : /************************************************************************/
   11994             : 
   11995             : /** Multiply a band with a constant.
   11996             :  *
   11997             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11998             :  * dataset.
   11999             :  *
   12000             :  * @since 3.12
   12001             :  */
   12002           2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
   12003             : {
   12004           2 :     return other * constant;
   12005             : }
   12006             : 
   12007             : /************************************************************************/
   12008             : /*                             operator/()                              */
   12009             : /************************************************************************/
   12010             : 
   12011             : /** Divide this band with another one.
   12012             :  *
   12013             :  * The resulting band is lazy evaluated. A reference is taken on both input
   12014             :  * datasets.
   12015             :  *
   12016             :  * @since 3.12
   12017             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   12018             :  */
   12019             : GDALComputedRasterBand
   12020           2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
   12021             : {
   12022           2 :     ThrowIfNotSameDimensions(*this, other);
   12023             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12024           2 :                                   *this, other);
   12025             : }
   12026             : 
   12027             : /************************************************************************/
   12028             : /*                             operator/()                              */
   12029             : /************************************************************************/
   12030             : 
   12031             : /** Divide this band by a constant.
   12032             :  *
   12033             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12034             :  * dataset.
   12035             :  *
   12036             :  * @since 3.12
   12037             :  */
   12038           0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
   12039             : {
   12040             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12041           0 :                                   *this, constant);
   12042             : }
   12043             : 
   12044             : /************************************************************************/
   12045             : /*                             operator/()                              */
   12046             : /************************************************************************/
   12047             : 
   12048             : /** Divide a constant by a band.
   12049             :  *
   12050             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12051             :  * dataset.
   12052             :  *
   12053             :  * @since 3.12
   12054             :  */
   12055           1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
   12056             : {
   12057             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12058           1 :                                   constant, other);
   12059             : }
   12060             : 
   12061             : /************************************************************************/
   12062             : /*                         ThrowIfNotMuparser()                         */
   12063             : /************************************************************************/
   12064             : 
   12065             : #ifndef HAVE_MUPARSER
   12066             : static GDALComputedRasterBand ThrowIfNotMuparser()
   12067             : {
   12068             :     throw std::runtime_error("Operator not available on a "
   12069             :                              "GDAL build without muparser");
   12070             : }
   12071             : #endif
   12072             : 
   12073             : /************************************************************************/
   12074             : /*                             operator>()                              */
   12075             : /************************************************************************/
   12076             : 
   12077             : /** Return a band whose value is 1 if the pixel value of the left operand
   12078             :  * is greater than the pixel value of the right operand.
   12079             :  *
   12080             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12081             :  * dataset.
   12082             :  *
   12083             :  * @since 3.12
   12084             :  */
   12085             : GDALComputedRasterBand
   12086           3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
   12087             : {
   12088             : #ifndef HAVE_MUPARSER
   12089             :     (void)other;
   12090             :     return ThrowIfNotMuparser();
   12091             : #else
   12092           3 :     ThrowIfNotSameDimensions(*this, other);
   12093             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12094           2 :                                   *this, other);
   12095             : #endif
   12096             : }
   12097             : 
   12098             : /************************************************************************/
   12099             : /*                             operator>()                              */
   12100             : /************************************************************************/
   12101             : 
   12102             : /** Return a band whose value is 1 if the pixel value of the left operand
   12103             :  * is greater than the constant.
   12104             :  *
   12105             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12106             :  * dataset.
   12107             :  *
   12108             :  * @since 3.12
   12109             :  */
   12110           3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
   12111             : {
   12112             : #ifndef HAVE_MUPARSER
   12113             :     (void)constant;
   12114             :     return ThrowIfNotMuparser();
   12115             : #else
   12116             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12117           3 :                                   *this, constant);
   12118             : #endif
   12119             : }
   12120             : 
   12121             : /************************************************************************/
   12122             : /*                             operator>()                              */
   12123             : /************************************************************************/
   12124             : 
   12125             : /** Return a band whose value is 1 if the constant is greater than the pixel
   12126             :  * value of the right operand.
   12127             :  *
   12128             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12129             :  * dataset.
   12130             :  *
   12131             :  * @since 3.12
   12132             :  */
   12133           2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
   12134             : {
   12135             : #ifndef HAVE_MUPARSER
   12136             :     (void)constant;
   12137             :     (void)other;
   12138             :     return ThrowIfNotMuparser();
   12139             : #else
   12140             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12141           2 :                                   constant, other);
   12142             : #endif
   12143             : }
   12144             : 
   12145             : /************************************************************************/
   12146             : /*                             operator>=()                             */
   12147             : /************************************************************************/
   12148             : 
   12149             : /** Return a band whose value is 1 if the pixel value of the left operand
   12150             :  * is greater or equal to the pixel value of the right operand.
   12151             :  *
   12152             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12153             :  * dataset.
   12154             :  *
   12155             :  * @since 3.12
   12156             :  */
   12157             : GDALComputedRasterBand
   12158           4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
   12159             : {
   12160             : #ifndef HAVE_MUPARSER
   12161             :     (void)other;
   12162             :     return ThrowIfNotMuparser();
   12163             : #else
   12164           4 :     ThrowIfNotSameDimensions(*this, other);
   12165             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12166           3 :                                   *this, other);
   12167             : #endif
   12168             : }
   12169             : 
   12170             : /************************************************************************/
   12171             : /*                             operator>=()                             */
   12172             : /************************************************************************/
   12173             : 
   12174             : /** Return a band whose value is 1 if the pixel value of the left operand
   12175             :  * is greater or equal to the constant.
   12176             :  *
   12177             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12178             :  * dataset.
   12179             :  *
   12180             :  * @since 3.12
   12181             :  */
   12182           3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
   12183             : {
   12184             : #ifndef HAVE_MUPARSER
   12185             :     (void)constant;
   12186             :     return ThrowIfNotMuparser();
   12187             : #else
   12188             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12189           3 :                                   *this, constant);
   12190             : #endif
   12191             : }
   12192             : 
   12193             : /************************************************************************/
   12194             : /*                             operator>=()                             */
   12195             : /************************************************************************/
   12196             : 
   12197             : /** Return a band whose value is 1 if the constant is greater or equal to
   12198             :  * the pixel value of the right operand.
   12199             :  *
   12200             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12201             :  * dataset.
   12202             :  *
   12203             :  * @since 3.12
   12204             :  */
   12205           2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
   12206             : {
   12207             : #ifndef HAVE_MUPARSER
   12208             :     (void)constant;
   12209             :     (void)other;
   12210             :     return ThrowIfNotMuparser();
   12211             : #else
   12212             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12213           2 :                                   constant, other);
   12214             : #endif
   12215             : }
   12216             : 
   12217             : /************************************************************************/
   12218             : /*                             operator<()                              */
   12219             : /************************************************************************/
   12220             : 
   12221             : /** Return a band whose value is 1 if the pixel value of the left operand
   12222             :  * is lesser than the pixel value of the right operand.
   12223             :  *
   12224             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12225             :  * dataset.
   12226             :  *
   12227             :  * @since 3.12
   12228             :  */
   12229             : GDALComputedRasterBand
   12230           3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
   12231             : {
   12232             : #ifndef HAVE_MUPARSER
   12233             :     (void)other;
   12234             :     return ThrowIfNotMuparser();
   12235             : #else
   12236           3 :     ThrowIfNotSameDimensions(*this, other);
   12237             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12238           2 :                                   *this, other);
   12239             : #endif
   12240             : }
   12241             : 
   12242             : /************************************************************************/
   12243             : /*                             operator<()                              */
   12244             : /************************************************************************/
   12245             : 
   12246             : /** Return a band whose value is 1 if the pixel value of the left operand
   12247             :  * is lesser than the constant.
   12248             :  *
   12249             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12250             :  * dataset.
   12251             :  *
   12252             :  * @since 3.12
   12253             :  */
   12254           3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
   12255             : {
   12256             : #ifndef HAVE_MUPARSER
   12257             :     (void)constant;
   12258             :     return ThrowIfNotMuparser();
   12259             : #else
   12260             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12261           3 :                                   *this, constant);
   12262             : #endif
   12263             : }
   12264             : 
   12265             : /************************************************************************/
   12266             : /*                             operator<()                              */
   12267             : /************************************************************************/
   12268             : 
   12269             : /** Return a band whose value is 1 if the constant is lesser than the pixel
   12270             :  * value of the right operand.
   12271             :  *
   12272             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12273             :  * dataset.
   12274             :  *
   12275             :  * @since 3.12
   12276             :  */
   12277           2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
   12278             : {
   12279             : #ifndef HAVE_MUPARSER
   12280             :     (void)constant;
   12281             :     (void)other;
   12282             :     return ThrowIfNotMuparser();
   12283             : #else
   12284             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12285           2 :                                   constant, other);
   12286             : #endif
   12287             : }
   12288             : 
   12289             : /************************************************************************/
   12290             : /*                             operator<=()                             */
   12291             : /************************************************************************/
   12292             : 
   12293             : /** Return a band whose value is 1 if the pixel value of the left operand
   12294             :  * is lesser or equal to the pixel value of the right operand.
   12295             :  *
   12296             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12297             :  * dataset.
   12298             :  *
   12299             :  * @since 3.12
   12300             :  */
   12301             : GDALComputedRasterBand
   12302           4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
   12303             : {
   12304             : #ifndef HAVE_MUPARSER
   12305             :     (void)other;
   12306             :     return ThrowIfNotMuparser();
   12307             : #else
   12308           4 :     ThrowIfNotSameDimensions(*this, other);
   12309             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12310           3 :                                   *this, other);
   12311             : #endif
   12312             : }
   12313             : 
   12314             : /************************************************************************/
   12315             : /*                             operator<=()                             */
   12316             : /************************************************************************/
   12317             : 
   12318             : /** Return a band whose value is 1 if the pixel value of the left operand
   12319             :  * is lesser or equal to the constant.
   12320             :  *
   12321             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12322             :  * dataset.
   12323             :  *
   12324             :  * @since 3.12
   12325             :  */
   12326           3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
   12327             : {
   12328             : #ifndef HAVE_MUPARSER
   12329             :     (void)constant;
   12330             :     return ThrowIfNotMuparser();
   12331             : #else
   12332             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12333           3 :                                   *this, constant);
   12334             : #endif
   12335             : }
   12336             : 
   12337             : /************************************************************************/
   12338             : /*                             operator<=()                             */
   12339             : /************************************************************************/
   12340             : 
   12341             : /** Return a band whose value is 1 if the constant is lesser or equal to
   12342             :  * the pixel value of the right operand.
   12343             :  *
   12344             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12345             :  * dataset.
   12346             :  *
   12347             :  * @since 3.12
   12348             :  */
   12349           2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
   12350             : {
   12351             : #ifndef HAVE_MUPARSER
   12352             :     (void)constant;
   12353             :     (void)other;
   12354             :     return ThrowIfNotMuparser();
   12355             : #else
   12356             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12357           2 :                                   constant, other);
   12358             : #endif
   12359             : }
   12360             : 
   12361             : /************************************************************************/
   12362             : /*                             operator==()                             */
   12363             : /************************************************************************/
   12364             : 
   12365             : /** Return a band whose value is 1 if the pixel value of the left operand
   12366             :  * is equal to the pixel value of the right operand.
   12367             :  *
   12368             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12369             :  * dataset.
   12370             :  *
   12371             :  * @since 3.12
   12372             :  */
   12373             : GDALComputedRasterBand
   12374           3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
   12375             : {
   12376             : #ifndef HAVE_MUPARSER
   12377             :     (void)other;
   12378             :     return ThrowIfNotMuparser();
   12379             : #else
   12380           3 :     ThrowIfNotSameDimensions(*this, other);
   12381             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12382           2 :                                   *this, other);
   12383             : #endif
   12384             : }
   12385             : 
   12386             : /************************************************************************/
   12387             : /*                             operator==()                             */
   12388             : /************************************************************************/
   12389             : 
   12390             : /** Return a band whose value is 1 if the pixel value of the left operand
   12391             :  * is equal to the constant.
   12392             :  *
   12393             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12394             :  * dataset.
   12395             :  *
   12396             :  * @since 3.12
   12397             :  */
   12398           8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
   12399             : {
   12400             : #ifndef HAVE_MUPARSER
   12401             :     (void)constant;
   12402             :     return ThrowIfNotMuparser();
   12403             : #else
   12404             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12405           8 :                                   *this, constant);
   12406             : #endif
   12407             : }
   12408             : 
   12409             : /************************************************************************/
   12410             : /*                             operator==()                             */
   12411             : /************************************************************************/
   12412             : 
   12413             : /** Return a band whose value is 1 if the constant is equal to
   12414             :  * the pixel value of the right operand.
   12415             :  *
   12416             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12417             :  * dataset.
   12418             :  *
   12419             :  * @since 3.12
   12420             :  */
   12421           2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
   12422             : {
   12423             : #ifndef HAVE_MUPARSER
   12424             :     (void)constant;
   12425             :     (void)other;
   12426             :     return ThrowIfNotMuparser();
   12427             : #else
   12428             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12429           2 :                                   constant, other);
   12430             : #endif
   12431             : }
   12432             : 
   12433             : /************************************************************************/
   12434             : /*                             operator!=()                             */
   12435             : /************************************************************************/
   12436             : 
   12437             : /** Return a band whose value is 1 if the pixel value of the left operand
   12438             :  * is different from the pixel value of the right operand.
   12439             :  *
   12440             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12441             :  * dataset.
   12442             :  *
   12443             :  * @since 3.12
   12444             :  */
   12445             : GDALComputedRasterBand
   12446           3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
   12447             : {
   12448             : #ifndef HAVE_MUPARSER
   12449             :     (void)other;
   12450             :     return ThrowIfNotMuparser();
   12451             : #else
   12452           3 :     ThrowIfNotSameDimensions(*this, other);
   12453             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12454           2 :                                   *this, other);
   12455             : #endif
   12456             : }
   12457             : 
   12458             : /************************************************************************/
   12459             : /*                             operator!=()                             */
   12460             : /************************************************************************/
   12461             : 
   12462             : /** Return a band whose value is 1 if the pixel value of the left operand
   12463             :  * is different from the constant.
   12464             :  *
   12465             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12466             :  * dataset.
   12467             :  *
   12468             :  * @since 3.12
   12469             :  */
   12470           6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
   12471             : {
   12472             : #ifndef HAVE_MUPARSER
   12473             :     (void)constant;
   12474             :     return ThrowIfNotMuparser();
   12475             : #else
   12476             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12477           6 :                                   *this, constant);
   12478             : #endif
   12479             : }
   12480             : 
   12481             : /************************************************************************/
   12482             : /*                             operator!=()                             */
   12483             : /************************************************************************/
   12484             : 
   12485             : /** Return a band whose value is 1 if the constant is different from
   12486             :  * the pixel value of the right operand.
   12487             :  *
   12488             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12489             :  * dataset.
   12490             :  *
   12491             :  * @since 3.12
   12492             :  */
   12493           2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
   12494             : {
   12495             : #ifndef HAVE_MUPARSER
   12496             :     (void)constant;
   12497             :     (void)other;
   12498             :     return ThrowIfNotMuparser();
   12499             : #else
   12500             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12501           2 :                                   constant, other);
   12502             : #endif
   12503             : }
   12504             : 
   12505             : #if defined(__GNUC__)
   12506             : #pragma GCC diagnostic push
   12507             : #pragma GCC diagnostic ignored "-Weffc++"
   12508             : #endif
   12509             : 
   12510             : /************************************************************************/
   12511             : /*                             operator&&()                             */
   12512             : /************************************************************************/
   12513             : 
   12514             : /** Return a band whose value is 1 if the pixel value of the left and right
   12515             :  * operands is true.
   12516             :  *
   12517             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12518             :  * dataset.
   12519             :  *
   12520             :  * @since 3.12
   12521             :  */
   12522             : GDALComputedRasterBand
   12523           3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
   12524             : {
   12525             : #ifndef HAVE_MUPARSER
   12526             :     (void)other;
   12527             :     return ThrowIfNotMuparser();
   12528             : #else
   12529           3 :     ThrowIfNotSameDimensions(*this, other);
   12530             :     return GDALComputedRasterBand(
   12531           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
   12532             : #endif
   12533             : }
   12534             : 
   12535             : /************************************************************************/
   12536             : /*                             operator&&()                             */
   12537             : /************************************************************************/
   12538             : 
   12539             : /** Return a band whose value is 1 if the pixel value of the left operand
   12540             :  * is true, as well as the constant
   12541             :  *
   12542             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12543             :  * dataset.
   12544             :  *
   12545             :  * @since 3.12
   12546             :  */
   12547           2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
   12548             : {
   12549             : #ifndef HAVE_MUPARSER
   12550             :     (void)constant;
   12551             :     return ThrowIfNotMuparser();
   12552             : #else
   12553             :     return GDALComputedRasterBand(
   12554           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
   12555             : #endif
   12556             : }
   12557             : 
   12558             : /************************************************************************/
   12559             : /*                             operator&&()                             */
   12560             : /************************************************************************/
   12561             : 
   12562             : /** Return a band whose value is 1 if the constant is true, as well as
   12563             :  * the pixel value of the right operand.
   12564             :  *
   12565             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12566             :  * dataset.
   12567             :  *
   12568             :  * @since 3.12
   12569             :  */
   12570           2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
   12571             : {
   12572             : #ifndef HAVE_MUPARSER
   12573             :     (void)constant;
   12574             :     (void)other;
   12575             :     return ThrowIfNotMuparser();
   12576             : #else
   12577             :     return GDALComputedRasterBand(
   12578           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
   12579             : #endif
   12580             : }
   12581             : 
   12582             : /************************************************************************/
   12583             : /*                             operator||()                             */
   12584             : /************************************************************************/
   12585             : 
   12586             : /** Return a band whose value is 1 if the pixel value of the left or right
   12587             :  * operands is true.
   12588             :  *
   12589             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12590             :  * dataset.
   12591             :  *
   12592             :  * @since 3.12
   12593             :  */
   12594             : GDALComputedRasterBand
   12595           4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
   12596             : {
   12597             : #ifndef HAVE_MUPARSER
   12598             :     (void)other;
   12599             :     return ThrowIfNotMuparser();
   12600             : #else
   12601           4 :     ThrowIfNotSameDimensions(*this, other);
   12602             :     return GDALComputedRasterBand(
   12603           3 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
   12604             : #endif
   12605             : }
   12606             : 
   12607             : /************************************************************************/
   12608             : /*                             operator||()                             */
   12609             : /************************************************************************/
   12610             : 
   12611             : /** Return a band whose value is 1 if the pixel value of the left operand
   12612             :  * is true, or if the constant is true
   12613             :  *
   12614             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12615             :  * dataset.
   12616             :  *
   12617             :  * @since 3.12
   12618             :  */
   12619           4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
   12620             : {
   12621             : #ifndef HAVE_MUPARSER
   12622             :     (void)constant;
   12623             :     return ThrowIfNotMuparser();
   12624             : #else
   12625             :     return GDALComputedRasterBand(
   12626           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
   12627             : #endif
   12628             : }
   12629             : 
   12630             : /************************************************************************/
   12631             : /*                             operator||()                             */
   12632             : /************************************************************************/
   12633             : 
   12634             : /** Return a band whose value is 1 if the constant is true, or
   12635             :  * the pixel value of the right operand is true
   12636             :  *
   12637             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12638             :  * dataset.
   12639             :  *
   12640             :  * @since 3.12
   12641             :  */
   12642           4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
   12643             : {
   12644             : #ifndef HAVE_MUPARSER
   12645             :     (void)constant;
   12646             :     (void)other;
   12647             :     return ThrowIfNotMuparser();
   12648             : #else
   12649             :     return GDALComputedRasterBand(
   12650           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
   12651             : #endif
   12652             : }
   12653             : 
   12654             : #if defined(__GNUC__)
   12655             : #pragma GCC diagnostic pop
   12656             : #endif
   12657             : 
   12658             : /************************************************************************/
   12659             : /*                             operator!()                              */
   12660             : /************************************************************************/
   12661             : 
   12662             : /** Return a band whose value is the logical negation of the pixel value
   12663             :  *
   12664             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12665             :  * dataset.
   12666             :  *
   12667             :  * @since 3.12
   12668             :  */
   12669           2 : GDALComputedRasterBand GDALRasterBand::operator!() const
   12670             : {
   12671             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12672           2 :                                   *this, true);
   12673             : }
   12674             : 
   12675             : namespace gdal
   12676             : {
   12677             : 
   12678             : /************************************************************************/
   12679             : /*                             IfThenElse()                             */
   12680             : /************************************************************************/
   12681             : 
   12682             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12683             :  * is not zero, or the one from elseBand otherwise.
   12684             :  *
   12685             :  * Variants of this method exits where thenBand and/or elseBand can be double
   12686             :  * values.
   12687             :  *
   12688             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12689             :  * datasets.
   12690             :  *
   12691             :  * This method is the same as the C function GDALRasterBandIfThenElse()
   12692             :  *
   12693             :  * @since 3.12
   12694             :  */
   12695           5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12696             :                                   const GDALRasterBand &thenBand,
   12697             :                                   const GDALRasterBand &elseBand)
   12698             : {
   12699             : #ifndef HAVE_MUPARSER
   12700             :     (void)condBand;
   12701             :     (void)thenBand;
   12702             :     (void)elseBand;
   12703             :     return ThrowIfNotMuparser();
   12704             : #else
   12705           5 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12706           4 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12707             :     return GDALComputedRasterBand(
   12708             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12709           6 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12710             : #endif
   12711             : }
   12712             : 
   12713             : //! @cond Doxygen_Suppress
   12714             : 
   12715             : /************************************************************************/
   12716             : /*                             IfThenElse()                             */
   12717             : /************************************************************************/
   12718             : 
   12719             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12720             :  * is not zero, or the one from elseBand otherwise.
   12721             :  *
   12722             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12723             :  * datasets.
   12724             :  *
   12725             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12726             :  * with thenBand = (condBand * 0) + thenValue
   12727             :  *
   12728             :  * @since 3.12
   12729             :  */
   12730           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12731             :                                   double thenValue,
   12732             :                                   const GDALRasterBand &elseBand)
   12733             : {
   12734             : #ifndef HAVE_MUPARSER
   12735             :     (void)condBand;
   12736             :     (void)thenValue;
   12737             :     (void)elseBand;
   12738             :     return ThrowIfNotMuparser();
   12739             : #else
   12740           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12741             :     auto thenBand =
   12742           1 :         (condBand * 0)
   12743           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12744           1 :         thenValue;
   12745             :     return GDALComputedRasterBand(
   12746             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12747           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12748             : #endif
   12749             : }
   12750             : 
   12751             : /************************************************************************/
   12752             : /*                             IfThenElse()                             */
   12753             : /************************************************************************/
   12754             : 
   12755             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12756             :  * is not zero, or the one from elseValue otherwise.
   12757             :  *
   12758             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12759             :  * datasets.
   12760             :  *
   12761             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12762             :  * with elseBand = (condBand * 0) + elseValue
   12763             : 
   12764             :  * @since 3.12
   12765             :  */
   12766           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12767             :                                   const GDALRasterBand &thenBand,
   12768             :                                   double elseValue)
   12769             : {
   12770             : #ifndef HAVE_MUPARSER
   12771             :     (void)condBand;
   12772             :     (void)thenBand;
   12773             :     (void)elseValue;
   12774             :     return ThrowIfNotMuparser();
   12775             : #else
   12776           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12777             :     auto elseBand =
   12778           1 :         (condBand * 0)
   12779           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12780           1 :         elseValue;
   12781             :     return GDALComputedRasterBand(
   12782             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12783           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12784             : #endif
   12785             : }
   12786             : 
   12787             : /************************************************************************/
   12788             : /*                             IfThenElse()                             */
   12789             : /************************************************************************/
   12790             : 
   12791             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12792             :  * is not zero, or the one from elseValue otherwise.
   12793             :  *
   12794             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12795             :  * datasets.
   12796             :  *
   12797             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12798             :  * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
   12799             :  *
   12800             :  * @since 3.12
   12801             :  */
   12802           3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12803             :                                   double thenValue, double elseValue)
   12804             : {
   12805             : #ifndef HAVE_MUPARSER
   12806             :     (void)condBand;
   12807             :     (void)thenValue;
   12808             :     (void)elseValue;
   12809             :     return ThrowIfNotMuparser();
   12810             : #else
   12811             :     auto thenBand =
   12812           3 :         (condBand * 0)
   12813           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12814           6 :         thenValue;
   12815             :     auto elseBand =
   12816           3 :         (condBand * 0)
   12817           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12818           3 :         elseValue;
   12819             :     return GDALComputedRasterBand(
   12820             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12821           9 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12822             : #endif
   12823             : }
   12824             : 
   12825             : //! @endcond
   12826             : 
   12827             : }  // namespace gdal
   12828             : 
   12829             : /************************************************************************/
   12830             : /*                      GDALRasterBandIfThenElse()                      */
   12831             : /************************************************************************/
   12832             : 
   12833             : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
   12834             :  * is not zero, or the one from hElseBand otherwise.
   12835             :  *
   12836             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12837             :  * datasets.
   12838             :  *
   12839             :  * This function is the same as the C++ method gdal::IfThenElse()
   12840             :  *
   12841             :  * @since 3.12
   12842             :  */
   12843          12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
   12844             :                                                  GDALRasterBandH hThenBand,
   12845             :                                                  GDALRasterBandH hElseBand)
   12846             : {
   12847          12 :     VALIDATE_POINTER1(hCondBand, __func__, nullptr);
   12848          12 :     VALIDATE_POINTER1(hThenBand, __func__, nullptr);
   12849          12 :     VALIDATE_POINTER1(hElseBand, __func__, nullptr);
   12850             : #ifndef HAVE_MUPARSER
   12851             :     CPLError(CE_Failure, CPLE_NotSupported,
   12852             :              "Band comparison operators not available on a GDAL build without "
   12853             :              "muparser");
   12854             :     return nullptr;
   12855             : #else
   12856             : 
   12857          12 :     auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
   12858          12 :     auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
   12859          12 :     auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
   12860             :     try
   12861             :     {
   12862          12 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12863          11 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12864             :     }
   12865           2 :     catch (const std::exception &e)
   12866             :     {
   12867           2 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   12868           2 :         return nullptr;
   12869             :     }
   12870             :     return new GDALComputedRasterBand(
   12871             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12872          10 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12873             : #endif
   12874             : }
   12875             : 
   12876             : /************************************************************************/
   12877             : /*                       GDALRasterBand::AsType()                       */
   12878             : /************************************************************************/
   12879             : 
   12880             : /** Cast this band to another type.
   12881             :  *
   12882             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12883             :  * dataset.
   12884             :  *
   12885             :  * This method is the same as the C function GDALRasterBandAsDataType()
   12886             :  *
   12887             :  * @since 3.12
   12888             :  */
   12889          10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
   12890             : {
   12891          10 :     if (dt == GDT_Unknown)
   12892             :     {
   12893           1 :         throw std::runtime_error("AsType(GDT_Unknown) is not supported");
   12894             :     }
   12895             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
   12896           9 :                                   *this, dt);
   12897             : }
   12898             : 
   12899             : /************************************************************************/
   12900             : /*                      GDALRasterBandAsDataType()                      */
   12901             : /************************************************************************/
   12902             : 
   12903             : /** Cast this band to another type.
   12904             :  *
   12905             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12906             :  * dataset.
   12907             :  *
   12908             :  * This function is the same as the C++ method GDALRasterBand::AsType()
   12909             :  *
   12910             :  * @since 3.12
   12911             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12912             :  */
   12913          16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
   12914             :                                                  GDALDataType eDT)
   12915             : {
   12916          16 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   12917          16 :     if (eDT == GDT_Unknown)
   12918             :     {
   12919           1 :         CPLError(CE_Failure, CPLE_NotSupported,
   12920             :                  "GDALRasterBandAsDataType(GDT_Unknown) not supported");
   12921           1 :         return nullptr;
   12922             :     }
   12923             :     return new GDALComputedRasterBand(
   12924             :         GDALComputedRasterBand::Operation::OP_CAST,
   12925          15 :         *(GDALRasterBand::FromHandle(hBand)), eDT);
   12926             : }
   12927             : 
   12928             : /************************************************************************/
   12929             : /*                           GetBandVector()                            */
   12930             : /************************************************************************/
   12931             : 
   12932             : static std::vector<const GDALRasterBand *>
   12933          10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
   12934             : {
   12935          10 :     std::vector<const GDALRasterBand *> bands;
   12936          27 :     for (size_t i = 0; i < nBandCount; ++i)
   12937             :     {
   12938          20 :         if (i > 0)
   12939             :         {
   12940          10 :             GDALRasterBand::ThrowIfNotSameDimensions(
   12941          10 :                 *(GDALRasterBand::FromHandle(pahBands[0])),
   12942          10 :                 *(GDALRasterBand::FromHandle(pahBands[i])));
   12943             :         }
   12944          17 :         bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
   12945             :     }
   12946           7 :     return bands;
   12947             : }
   12948             : 
   12949             : /************************************************************************/
   12950             : /*                       GDALOperationOnNBands()                        */
   12951             : /************************************************************************/
   12952             : 
   12953             : static GDALComputedRasterBandH
   12954          11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
   12955             :                       GDALRasterBandH *pahBands)
   12956             : {
   12957          11 :     VALIDATE_POINTER1(pahBands, __func__, nullptr);
   12958          11 :     if (nBandCount == 0)
   12959             :     {
   12960           1 :         CPLError(CE_Failure, CPLE_AppDefined,
   12961             :                  "At least one band should be passed");
   12962           1 :         return nullptr;
   12963             :     }
   12964             : 
   12965          20 :     std::vector<const GDALRasterBand *> bands;
   12966             :     try
   12967             :     {
   12968          10 :         bands = GetBandVector(nBandCount, pahBands);
   12969             :     }
   12970           3 :     catch (const std::exception &e)
   12971             :     {
   12972           3 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   12973           3 :         return nullptr;
   12974             :     }
   12975           7 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
   12976             : }
   12977             : 
   12978             : /************************************************************************/
   12979             : /*                        GDALMaximumOfNBands()                         */
   12980             : /************************************************************************/
   12981             : 
   12982             : /** Return a band whose each pixel value is the maximum of the corresponding
   12983             :  * pixel values in the input bands.
   12984             :  *
   12985             :  * The resulting band is lazy evaluated. A reference is taken on input
   12986             :  * datasets.
   12987             :  *
   12988             :  * This function is the same as the C ++ method gdal::max()
   12989             :  *
   12990             :  * @since 3.12
   12991             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12992             :  */
   12993           4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
   12994             :                                             GDALRasterBandH *pahBands)
   12995             : {
   12996           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
   12997           4 :                                  nBandCount, pahBands);
   12998             : }
   12999             : 
   13000             : /************************************************************************/
   13001             : /*                             gdal::max()                              */
   13002             : /************************************************************************/
   13003             : 
   13004             : namespace gdal
   13005             : {
   13006             : /** Return a band whose each pixel value is the maximum of the corresponding
   13007             :  * pixel values in the inputs (bands or constants)
   13008             :  *
   13009             :  * The resulting band is lazy evaluated. A reference is taken on input
   13010             :  * datasets.
   13011             :  *
   13012             :  * Two or more bands can be passed.
   13013             :  *
   13014             :  * This method is the same as the C function GDALMaximumOfNBands()
   13015             :  *
   13016             :  * @since 3.12
   13017             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13018             :  */
   13019           1 : GDALComputedRasterBand max(const GDALRasterBand &first,
   13020             :                            const GDALRasterBand &second)
   13021             : {
   13022           1 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13023             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
   13024           1 :                                   first, second);
   13025             : }
   13026             : }  // namespace gdal
   13027             : 
   13028             : /************************************************************************/
   13029             : /*                     GDALRasterBandMaxConstant()                      */
   13030             : /************************************************************************/
   13031             : 
   13032             : /** Return a band whose each pixel value is the maximum of the corresponding
   13033             :  * pixel values in the input band and the constant.
   13034             :  *
   13035             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13036             :  * dataset.
   13037             :  *
   13038             :  * This function is the same as the C ++ method gdal::max()
   13039             :  *
   13040             :  * @since 3.12
   13041             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13042             :  */
   13043           2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
   13044             :                                                   double dfConstant)
   13045             : {
   13046           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   13047             :         GDALComputedRasterBand::Operation::OP_MAX,
   13048           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   13049           6 :         dfConstant));
   13050             : }
   13051             : 
   13052             : /************************************************************************/
   13053             : /*                        GDALMinimumOfNBands()                         */
   13054             : /************************************************************************/
   13055             : 
   13056             : /** Return a band whose each pixel value is the minimum of the corresponding
   13057             :  * pixel values in the input bands.
   13058             :  *
   13059             :  * The resulting band is lazy evaluated. A reference is taken on input
   13060             :  * datasets.
   13061             :  *
   13062             :  * This function is the same as the C ++ method gdal::min()
   13063             :  *
   13064             :  * @since 3.12
   13065             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13066             :  */
   13067           4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
   13068             :                                             GDALRasterBandH *pahBands)
   13069             : {
   13070           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
   13071           4 :                                  nBandCount, pahBands);
   13072             : }
   13073             : 
   13074             : /************************************************************************/
   13075             : /*                             gdal::min()                              */
   13076             : /************************************************************************/
   13077             : 
   13078             : namespace gdal
   13079             : {
   13080             : /** Return a band whose each pixel value is the minimum of the corresponding
   13081             :  * pixel values in the inputs (bands or constants)
   13082             :  *
   13083             :  * The resulting band is lazy evaluated. A reference is taken on input
   13084             :  * datasets.
   13085             :  *
   13086             :  * Two or more bands can be passed.
   13087             :  *
   13088             :  * This method is the same as the C function GDALMinimumOfNBands()
   13089             :  *
   13090             :  * @since 3.12
   13091             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13092             :  */
   13093           0 : GDALComputedRasterBand min(const GDALRasterBand &first,
   13094             :                            const GDALRasterBand &second)
   13095             : {
   13096           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13097             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
   13098           0 :                                   first, second);
   13099             : }
   13100             : }  // namespace gdal
   13101             : 
   13102             : /************************************************************************/
   13103             : /*                     GDALRasterBandMinConstant()                      */
   13104             : /************************************************************************/
   13105             : 
   13106             : /** Return a band whose each pixel value is the minimum of the corresponding
   13107             :  * pixel values in the input band and the constant.
   13108             :  *
   13109             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13110             :  * dataset.
   13111             :  *
   13112             :  * This function is the same as the C ++ method gdal::min()
   13113             :  *
   13114             :  * @since 3.12
   13115             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13116             :  */
   13117           2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
   13118             :                                                   double dfConstant)
   13119             : {
   13120           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   13121             :         GDALComputedRasterBand::Operation::OP_MIN,
   13122           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   13123           6 :         dfConstant));
   13124             : }
   13125             : 
   13126             : /************************************************************************/
   13127             : /*                          GDALMeanOfNBands()                          */
   13128             : /************************************************************************/
   13129             : 
   13130             : /** Return a band whose each pixel value is the arithmetic mean of the
   13131             :  * corresponding pixel values in the input bands.
   13132             :  *
   13133             :  * The resulting band is lazy evaluated. A reference is taken on input
   13134             :  * datasets.
   13135             :  *
   13136             :  * This function is the same as the C ++ method gdal::mean()
   13137             :  *
   13138             :  * @since 3.12
   13139             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13140             :  */
   13141           3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
   13142             :                                          GDALRasterBandH *pahBands)
   13143             : {
   13144           3 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
   13145           3 :                                  nBandCount, pahBands);
   13146             : }
   13147             : 
   13148             : /************************************************************************/
   13149             : /*                             gdal::mean()                             */
   13150             : /************************************************************************/
   13151             : 
   13152             : namespace gdal
   13153             : {
   13154             : 
   13155             : /** Return a band whose each pixel value is the arithmetic mean of the
   13156             :  * corresponding pixel values in the input bands.
   13157             :  *
   13158             :  * The resulting band is lazy evaluated. A reference is taken on input
   13159             :  * datasets.
   13160             :  *
   13161             :  * Two or more bands can be passed.
   13162             :  *
   13163             :  * This method is the same as the C function GDALMeanOfNBands()
   13164             :  *
   13165             :  * @since 3.12
   13166             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13167             :  */
   13168           0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
   13169             :                             const GDALRasterBand &second)
   13170             : {
   13171           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13172             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
   13173           0 :                                   first, second);
   13174             : }
   13175             : }  // namespace gdal
   13176             : 
   13177             : /************************************************************************/
   13178             : /*                             gdal::abs()                              */
   13179             : /************************************************************************/
   13180             : 
   13181             : namespace gdal
   13182             : {
   13183             : 
   13184             : /** Return a band whose each pixel value is the absolute value (or module
   13185             :  * for complex data type) of the corresponding pixel value in the input band.
   13186             :  *
   13187             :  * The resulting band is lazy evaluated. A reference is taken on input
   13188             :  * datasets.
   13189             :  *
   13190             :  * @since 3.12
   13191             :  */
   13192           1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
   13193             : {
   13194             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   13195           1 :                                   band);
   13196             : }
   13197             : }  // namespace gdal
   13198             : 
   13199             : /************************************************************************/
   13200             : /*                             gdal::fabs()                             */
   13201             : /************************************************************************/
   13202             : 
   13203             : namespace gdal
   13204             : {
   13205             : 
   13206             : /** Return a band whose each pixel value is the absolute value (or module
   13207             :  * for complex data type) of the corresponding pixel value in the input band.
   13208             :  *
   13209             :  * The resulting band is lazy evaluated. A reference is taken on input
   13210             :  * datasets.
   13211             :  *
   13212             :  * @since 3.12
   13213             :  */
   13214           1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
   13215             : {
   13216             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   13217           1 :                                   band);
   13218             : }
   13219             : }  // namespace gdal
   13220             : 
   13221             : /************************************************************************/
   13222             : /*                             gdal::sqrt()                             */
   13223             : /************************************************************************/
   13224             : 
   13225             : namespace gdal
   13226             : {
   13227             : 
   13228             : /** Return a band whose each pixel value is the square root of the
   13229             :  * corresponding pixel value in the input band.
   13230             :  *
   13231             :  * The resulting band is lazy evaluated. A reference is taken on input
   13232             :  * datasets.
   13233             :  *
   13234             :  * @since 3.12
   13235             :  */
   13236           1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
   13237             : {
   13238             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
   13239           1 :                                   band);
   13240             : }
   13241             : }  // namespace gdal
   13242             : 
   13243             : /************************************************************************/
   13244             : /*                             gdal::log()                              */
   13245             : /************************************************************************/
   13246             : 
   13247             : namespace gdal
   13248             : {
   13249             : 
   13250             : /** Return a band whose each pixel value is the natural logarithm of the
   13251             :  * corresponding pixel value in the input band.
   13252             :  *
   13253             :  * The resulting band is lazy evaluated. A reference is taken on input
   13254             :  * datasets.
   13255             :  *
   13256             :  * @since 3.12
   13257             :  */
   13258           1 : GDALComputedRasterBand log(const GDALRasterBand &band)
   13259             : {
   13260             : #ifndef HAVE_MUPARSER
   13261             :     (void)band;
   13262             :     return ThrowIfNotMuparser();
   13263             : #else
   13264             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
   13265           1 :                                   band);
   13266             : #endif
   13267             : }
   13268             : }  // namespace gdal
   13269             : 
   13270             : /************************************************************************/
   13271             : /*                            gdal::log10()                             */
   13272             : /************************************************************************/
   13273             : 
   13274             : namespace gdal
   13275             : {
   13276             : 
   13277             : /** Return a band whose each pixel value is the logarithm base 10 of the
   13278             :  * corresponding pixel value in the input band.
   13279             :  *
   13280             :  * The resulting band is lazy evaluated. A reference is taken on input
   13281             :  * datasets.
   13282             :  *
   13283             :  * @since 3.12
   13284             :  */
   13285           1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
   13286             : {
   13287             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
   13288           1 :                                   band);
   13289             : }
   13290             : }  // namespace gdal
   13291             : 
   13292             : /************************************************************************/
   13293             : /*                             gdal::pow()                              */
   13294             : /************************************************************************/
   13295             : 
   13296             : namespace gdal
   13297             : {
   13298             : 
   13299             : #ifndef DOXYGEN_SKIP
   13300             : /** Return a band whose each pixel value is the constant raised to the power of
   13301             :  * the corresponding pixel value in the input band.
   13302             :  *
   13303             :  * The resulting band is lazy evaluated. A reference is taken on input
   13304             :  * datasets.
   13305             :  *
   13306             :  * @since 3.12
   13307             :  */
   13308           1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
   13309             : {
   13310             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13311           1 :                                   constant, band);
   13312             : }
   13313             : #endif
   13314             : 
   13315             : }  // namespace gdal
   13316             : 
   13317             : /************************************************************************/
   13318             : /*                             gdal::pow()                              */
   13319             : /************************************************************************/
   13320             : 
   13321             : namespace gdal
   13322             : {
   13323             : 
   13324             : /** Return a band whose each pixel value is the the corresponding pixel value
   13325             :  * in the input band raised to the power of the constant.
   13326             :  *
   13327             :  * The resulting band is lazy evaluated. A reference is taken on input
   13328             :  * datasets.
   13329             :  *
   13330             :  * @since 3.12
   13331             :  */
   13332           1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
   13333             : {
   13334             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13335           1 :                                   band, constant);
   13336             : }
   13337             : }  // namespace gdal
   13338             : 
   13339             : /************************************************************************/
   13340             : /*                             gdal::pow()                              */
   13341             : /************************************************************************/
   13342             : 
   13343             : namespace gdal
   13344             : {
   13345             : 
   13346             : #ifndef DOXYGEN_SKIP
   13347             : /** Return a band whose each pixel value is the the corresponding pixel value
   13348             :  * in the input band1 raised to the power of the corresponding pixel value
   13349             :  * in the input band2
   13350             :  *
   13351             :  * The resulting band is lazy evaluated. A reference is taken on input
   13352             :  * datasets.
   13353             :  *
   13354             :  * @since 3.12
   13355             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13356             :  */
   13357           2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
   13358             :                            const GDALRasterBand &band2)
   13359             : {
   13360             : #ifndef HAVE_MUPARSER
   13361             :     (void)band1;
   13362             :     (void)band2;
   13363             :     return ThrowIfNotMuparser();
   13364             : #else
   13365           2 :     GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
   13366             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13367           1 :                                   band1, band2);
   13368             : #endif
   13369             : }
   13370             : #endif
   13371             : }  // namespace gdal

Generated by: LCOV version 1.14